Skip to content

discover: support hyperlinks and newlines in protocol descriptions - #2985

Merged
JakeUrban merged 4 commits into
masterfrom
claude/blend-protocol-security-notice-eq75s9
Aug 31, 2026
Merged

discover: support hyperlinks and newlines in protocol descriptions#2985
JakeUrban merged 4 commits into
masterfrom
claude/blend-protocol-security-notice-eq75s9

Conversation

@JakeUrban

Copy link
Copy Markdown
Contributor

What

Adds a LinkifiedText component (extension/src/popup/basics/LinkifiedText/) that renders a protocol's description while turning markdown-style [text](https://...) links and bare https:// URLs into clickable <a> links, and preserves embedded newlines (white-space: pre-line) in ProtocolDetailsPanel.

Why

The /protocols description field is currently rendered as inert plain text with newlines collapsed. We just used this field to add a security-incident notice with a link (see the stellar/kube PR for the mainnet Blend entry) and want that link to actually be clickable, and future multi-line descriptions to render correctly.

Implementation notes

  • Only https:// URLs are ever linkified, matching the existing isSafeHttpsUrl convention already used for protocol.websiteUrl in Discover/index.tsx (no http:, javascript:, etc.).
  • No markdown/HTML library is introduced — parseLinkedText is a small regex-based parser and the output is only ever plain text or <a> elements (no dangerouslySetInnerHTML), so this is safe on the API-sourced, untrusted description string.
  • Added a doc comment on ProtocolEntry.description (@shared/api/types/types.ts) documenting the supported syntax.

Known limitations

  • I was unable to run this repo's Jest/lint/typecheck in my environment (Yarn Berry 4.10.0 install failed — repo.yarnpkg.com was unreachable). I verified the parseLinkedText regex logic against the added test cases with a standalone Node script, but the actual test suite has not been run against this branch.

Generated by Claude Code

Adds a LinkifiedText component that turns markdown-style
[text](https://...) links and bare https:// URLs in a protocol's
description into clickable links, restricted to https to match the
existing isSafeHttpsUrl convention used for protocol.websiteUrl. Also
preserves embedded newlines via white-space: pre-line, which the
description text previously collapsed.
@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

PR Preview build is ready: https://github.com/stellar/freighter/releases/tag/untagged-90c10b53fa1264106624
Backend: V1 prod + V2 beta (no sandbox configured for @JakeUrban). SDF collaborators only — install instructions in the release description.

@JakeUrban
JakeUrban marked this pull request as ready for review August 28, 2026 23:16
Copilot AI balanced review requested due to automatic review settings August 28, 2026 23:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds safe HTTPS linkification and multiline formatting to Discover protocol descriptions.

Changes:

  • Adds and tests a lightweight link parser and renderer.
  • Integrates linkified descriptions into protocol details.
  • Documents supported description syntax.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
ProtocolDetailsPanel/styles.scss Preserves newlines and styles links.
ProtocolDetailsPanel/index.tsx Renders descriptions with LinkifiedText.
LinkifiedText/parseLinkedText.ts Parses Markdown and bare HTTPS links.
LinkifiedText/index.tsx Renders parsed links safely.
LinkifiedText/__tests__/parseLinkedText.test.ts Tests parser behavior.
@shared/api/types/types.ts Documents description syntax.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread extension/src/popup/basics/LinkifiedText/parseLinkedText.ts Outdated
Addresses Copilot review feedback on #2985:

- parseLinkedText previously excluded all parentheses from a URL's
  character class, truncating URLs that legitimately contain them
  (e.g. Wikipedia-style https://.../Function_(mathematics)), and for
  the markdown form the first ")" inside the URL was mistaken for the
  link's closing paren. Replaced the regex-based matcher with a small
  scanner that tracks paren depth so balanced parens stay part of the
  URL, and only an unmatched ")" ends it. Added regression tests for
  both the bare-URL and markdown-link forms.
- ProtocolDetailsPanel's global stylesheet resets all <a> underlines,
  so the description's links were distinguished from surrounding text
  by color alone. Restored text-decoration: underline on them so the
  link cue doesn't depend on color perception.
Copilot AI review requested due to automatic review settings August 28, 2026 23:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comment thread extension/src/popup/basics/LinkifiedText/parseLinkedText.ts Outdated
Comment thread extension/src/popup/basics/LinkifiedText/parseLinkedText.ts Outdated
Addresses further review feedback on #2985:

- Copilot: a markdown label containing its own https:// URL (e.g.
  [https://a.example](https://b.example)) was mishandled because the
  parser scanned for bare https:// occurrences first, matching the
  label's URL before considering the markdown link around it.
- aristidesstaffieri: a stray, unmatched "[" before a real markdown
  link could swallow the real link into its own (invalid) label, since
  the backward-scanning opener regex always matched from the leftmost
  "[" rather than the nearest one.

Replaced the backward-scanning approach with a forward scanner that
looks for the next "[" or bare "https://" (whichever comes first) and
only commits to a markdown link once a complete, valid
[label](https://...) is found starting there; an incomplete/invalid
"[" is left as literal text and scanning resumes just past it. This
also incidentally required tightening the URL boundary characters to
include quotes, since a bare URL inside quotes was absorbing the
closing quote. Added regression tests for all three cases.
Copilot AI review requested due to automatic review settings August 31, 2026 16:42
JakeUrban pushed a commit to stellar/freighter-mobile that referenced this pull request Aug 31, 2026
Addresses review feedback on #994:

- Copilot: __tests__/helpers/linkedText.test.ts imported "helpers/linkedText",
  which jest.config.js's moduleNameMapper remaps to
  __mocks__/helpers/linkedText - a file that doesn't exist, so the
  suite failed to resolve the module before any test ran. Import the
  real module via a relative path instead.
- Copilot: LinkedText had no component-level test exercising the
  actual tappable behavior (pressing a parsed segment opens the
  right URL) or its accessibility semantics.
- Copilot: bare URLs wrapped in quotes (e.g. "https://example.com/x")
  absorbed the closing quote into the tappable URL.
- aristidesstaffieri: a stray, unmatched "[" before a real markdown
  link could swallow the real link into its own (invalid) label
  (matching the same fix applied on the extension PR, stellar/freighter#2985).

Replaced the backward-scanning markdown-opener regex with a forward
scanner that looks for the next "[" or bare "https://" (whichever
comes first) and only commits to a markdown link once a complete,
valid [label](https://...) is found; this also fixes a related
Copilot finding on the extension PR where a label containing its own
https:// URL was mishandled. Tightened the URL boundary characters to
also stop at quotes. Added a LinkedText component test (renders both
link forms, presses each, asserts the in-app browser is opened with
the correct URL) and accessibilityRole="link" on tappable segments,
matching the existing pattern in BalancesList.tsx.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comment thread extension/src/popup/basics/LinkifiedText/parseLinkedText.ts
Addresses further Copilot feedback on #2985:

- A candidate was only checked against the "https://" text prefix, so
  malformed values like bare "https://" or "https://?query" (no host)
  were still emitted as clickable links, even though the existing
  isSafeHttpsUrl guard in Discover/index.tsx would reject them.
  Validate every candidate with `new URL(...)` and require the
  "https:" protocol before treating it as a link; reject candidates
  are left as plain text (the original substring, not `url.href`,
  is still used for display/navigation, since the WHATWG URL parser
  normalizes some inputs like adding a trailing slash to a bare
  origin).
- The URL boundary excluded square brackets universally, which broke
  markdown-link destinations containing the common `?tag[]=value`
  query syntax: the parse failed and the same target was then emitted
  as a truncated bare link pointing at the wrong address. Brackets are
  now only excluded from a *bare* URL's boundary (to avoid ambiguity
  with an immediately following markdown link) - a markdown
  destination's balanced closing paren is enough to bound it on its
  own.

Added regression tests for both.
Copilot AI review requested due to automatic review settings August 31, 2026 17:08
JakeUrban pushed a commit to stellar/freighter-mobile that referenced this pull request Aug 31, 2026
Addresses further Copilot feedback on #994:

- A candidate was only checked against the "https://" text prefix, so
  malformed values like bare "https://" or "https://?query" (no host)
  were still emitted as tappable links. Validate every candidate with
  `new URL(...)` and require the "https:" protocol before treating it
  as a link; rejected candidates are left as plain text (the original
  substring, not `url.href`, is still used for display/navigation,
  since the WHATWG URL parser normalizes some inputs like adding a
  trailing slash to a bare origin).
- The URL boundary excluded square brackets universally, which broke
  markdown-link destinations containing the common `?tag[]=value`
  query syntax: the parse failed and the same target was then emitted
  as a truncated bare link pointing at the wrong address. Brackets are
  now only excluded from a *bare* URL's boundary (to avoid ambiguity
  with an immediately following markdown link) - a markdown
  destination's balanced closing paren is enough to bound it on its
  own.
- Added the same eslint-disable-next-line react/no-array-index-key
  suppression to the linked-segment branch in LinkedText.tsx that the
  plain-text branch already had, since the AirBnB rule also flags
  indexes used inside template literals.

Added regression tests for both parser fixes, matching stellar/freighter#2985.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.

Suppressed comments (2)

Previously missed (2) — in code that hasn't changed since the last review.

extension/src/popup/basics/LinkifiedText/index.tsx:25

  • An empty or whitespace-only markdown label (for example, [](https://example.com)) is accepted, so this renders a focusable external link with no accessible name or visible target. Fall back to the URL when the supplied label has no meaningful text.
          {segment.text}

extension/src/popup/basics/LinkifiedText/parseLinkedText.ts:158

  • Failed markdown candidates are retried one character later, while tryParseMarkdownLink rescans the remaining string with indexOf and includes. A malformed API description such as many [ characters followed by ] therefore takes quadratic time; there is no response-length validation before this runs in the popup. Parse brackets in one forward pass or enforce a strict description-length limit to prevent a malformed response from freezing the UI.
      const link = tryParseMarkdownLink(text, bracketIndex);

JakeUrban added a commit to stellar/freighter-mobile that referenced this pull request Aug 31, 2026
* discovery: support hyperlinks in protocol descriptions

Adds a LinkedText component that turns markdown-style
[text](https://...) links and bare https:// URLs in a protocol's
description into tappable links via the existing Text `url` prop,
restricted to https to match the HTTPS-only convention already used
for protocol URLs elsewhere (helpers/protocols.ts). Newlines already
render correctly in React Native, so no change was needed there.

* discovery: fix link parsing for balanced parentheses in URLs

Ports the fix from stellar/freighter PR #2985 (Copilot review
feedback): the regex-based matcher excluded all parentheses from a
URL's character class, truncating URLs that legitimately contain them
(e.g. Wikipedia-style https://.../Function_(mathematics)), and for the
markdown form the first ")" inside the URL was mistaken for the link's
closing paren. Replaced it with a small scanner that tracks paren
depth so balanced parens stay part of the URL, and only an unmatched
")" ends it. Added regression tests for both the bare-URL and
markdown-link forms.

* discovery: fix link parsing bugs and address review feedback

Addresses review feedback on #994:

- Copilot: __tests__/helpers/linkedText.test.ts imported "helpers/linkedText",
  which jest.config.js's moduleNameMapper remaps to
  __mocks__/helpers/linkedText - a file that doesn't exist, so the
  suite failed to resolve the module before any test ran. Import the
  real module via a relative path instead.
- Copilot: LinkedText had no component-level test exercising the
  actual tappable behavior (pressing a parsed segment opens the
  right URL) or its accessibility semantics.
- Copilot: bare URLs wrapped in quotes (e.g. "https://example.com/x")
  absorbed the closing quote into the tappable URL.
- aristidesstaffieri: a stray, unmatched "[" before a real markdown
  link could swallow the real link into its own (invalid) label
  (matching the same fix applied on the extension PR, stellar/freighter#2985).

Replaced the backward-scanning markdown-opener regex with a forward
scanner that looks for the next "[" or bare "https://" (whichever
comes first) and only commits to a markdown link once a complete,
valid [label](https://...) is found; this also fixes a related
Copilot finding on the extension PR where a label containing its own
https:// URL was mishandled. Tightened the URL boundary characters to
also stop at quotes. Added a LinkedText component test (renders both
link forms, presses each, asserts the in-app browser is opened with
the correct URL) and accessibilityRole="link" on tappable segments,
matching the existing pattern in BalancesList.tsx.

* discovery: reject malformed URLs, keep brackets in markdown destinations

Addresses further Copilot feedback on #994:

- A candidate was only checked against the "https://" text prefix, so
  malformed values like bare "https://" or "https://?query" (no host)
  were still emitted as tappable links. Validate every candidate with
  `new URL(...)` and require the "https:" protocol before treating it
  as a link; rejected candidates are left as plain text (the original
  substring, not `url.href`, is still used for display/navigation,
  since the WHATWG URL parser normalizes some inputs like adding a
  trailing slash to a bare origin).
- The URL boundary excluded square brackets universally, which broke
  markdown-link destinations containing the common `?tag[]=value`
  query syntax: the parse failed and the same target was then emitted
  as a truncated bare link pointing at the wrong address. Brackets are
  now only excluded from a *bare* URL's boundary (to avoid ambiguity
  with an immediately following markdown link) - a markdown
  destination's balanced closing paren is enough to bound it on its
  own.
- Added the same eslint-disable-next-line react/no-array-index-key
  suppression to the linked-segment branch in LinkedText.tsx that the
  plain-text branch already had, since the AirBnB rule also flags
  indexes used inside template literals.

Added regression tests for both parser fixes, matching stellar/freighter#2985.

---------

Co-authored-by: Claude <noreply@anthropic.com>
@JakeUrban
JakeUrban merged commit db56fe0 into master Aug 31, 2026
12 checks passed
@JakeUrban
JakeUrban deleted the claude/blend-protocol-security-notice-eq75s9 branch August 31, 2026 18:24
CassioMG pushed a commit that referenced this pull request Aug 31, 2026
…2985)

* discover: support hyperlinks and newlines in protocol descriptions

Adds a LinkifiedText component that turns markdown-style
[text](https://...) links and bare https:// URLs in a protocol's
description into clickable links, restricted to https to match the
existing isSafeHttpsUrl convention used for protocol.websiteUrl. Also
preserves embedded newlines via white-space: pre-line, which the
description text previously collapsed.

* discover: fix link parsing for balanced parens, restore link underline

Addresses Copilot review feedback on #2985:

- parseLinkedText previously excluded all parentheses from a URL's
  character class, truncating URLs that legitimately contain them
  (e.g. Wikipedia-style https://.../Function_(mathematics)), and for
  the markdown form the first ")" inside the URL was mistaken for the
  link's closing paren. Replaced the regex-based matcher with a small
  scanner that tracks paren depth so balanced parens stay part of the
  URL, and only an unmatched ")" ends it. Added regression tests for
  both the bare-URL and markdown-link forms.
- ProtocolDetailsPanel's global stylesheet resets all <a> underlines,
  so the description's links were distinguished from surrounding text
  by color alone. Restored text-decoration: underline on them so the
  link cue doesn't depend on color perception.

* discover: fix nested-bracket and label-URL parsing bugs

Addresses further review feedback on #2985:

- Copilot: a markdown label containing its own https:// URL (e.g.
  [https://a.example](https://b.example)) was mishandled because the
  parser scanned for bare https:// occurrences first, matching the
  label's URL before considering the markdown link around it.
- aristidesstaffieri: a stray, unmatched "[" before a real markdown
  link could swallow the real link into its own (invalid) label, since
  the backward-scanning opener regex always matched from the leftmost
  "[" rather than the nearest one.

Replaced the backward-scanning approach with a forward scanner that
looks for the next "[" or bare "https://" (whichever comes first) and
only commits to a markdown link once a complete, valid
[label](https://...) is found starting there; an incomplete/invalid
"[" is left as literal text and scanning resumes just past it. This
also incidentally required tightening the URL boundary characters to
include quotes, since a bare URL inside quotes was absorbing the
closing quote. Added regression tests for all three cases.

* discover: reject malformed URLs, keep brackets in markdown destinations

Addresses further Copilot feedback on #2985:

- A candidate was only checked against the "https://" text prefix, so
  malformed values like bare "https://" or "https://?query" (no host)
  were still emitted as clickable links, even though the existing
  isSafeHttpsUrl guard in Discover/index.tsx would reject them.
  Validate every candidate with `new URL(...)` and require the
  "https:" protocol before treating it as a link; reject candidates
  are left as plain text (the original substring, not `url.href`,
  is still used for display/navigation, since the WHATWG URL parser
  normalizes some inputs like adding a trailing slash to a bare
  origin).
- The URL boundary excluded square brackets universally, which broke
  markdown-link destinations containing the common `?tag[]=value`
  query syntax: the parse failed and the same target was then emitted
  as a truncated bare link pointing at the wrong address. Brackets are
  now only excluded from a *bare* URL's boundary (to avoid ambiguity
  with an immediately following markdown link) - a markdown
  destination's balanced closing paren is enough to bound it on its
  own.

Added regression tests for both.

---------

Co-authored-by: Claude <noreply@anthropic.com>
CassioMG pushed a commit to stellar/freighter-mobile that referenced this pull request Aug 31, 2026
* discovery: support hyperlinks in protocol descriptions

Adds a LinkedText component that turns markdown-style
[text](https://...) links and bare https:// URLs in a protocol's
description into tappable links via the existing Text `url` prop,
restricted to https to match the HTTPS-only convention already used
for protocol URLs elsewhere (helpers/protocols.ts). Newlines already
render correctly in React Native, so no change was needed there.

* discovery: fix link parsing for balanced parentheses in URLs

Ports the fix from stellar/freighter PR #2985 (Copilot review
feedback): the regex-based matcher excluded all parentheses from a
URL's character class, truncating URLs that legitimately contain them
(e.g. Wikipedia-style https://.../Function_(mathematics)), and for the
markdown form the first ")" inside the URL was mistaken for the link's
closing paren. Replaced it with a small scanner that tracks paren
depth so balanced parens stay part of the URL, and only an unmatched
")" ends it. Added regression tests for both the bare-URL and
markdown-link forms.

* discovery: fix link parsing bugs and address review feedback

Addresses review feedback on #994:

- Copilot: __tests__/helpers/linkedText.test.ts imported "helpers/linkedText",
  which jest.config.js's moduleNameMapper remaps to
  __mocks__/helpers/linkedText - a file that doesn't exist, so the
  suite failed to resolve the module before any test ran. Import the
  real module via a relative path instead.
- Copilot: LinkedText had no component-level test exercising the
  actual tappable behavior (pressing a parsed segment opens the
  right URL) or its accessibility semantics.
- Copilot: bare URLs wrapped in quotes (e.g. "https://example.com/x")
  absorbed the closing quote into the tappable URL.
- aristidesstaffieri: a stray, unmatched "[" before a real markdown
  link could swallow the real link into its own (invalid) label
  (matching the same fix applied on the extension PR, stellar/freighter#2985).

Replaced the backward-scanning markdown-opener regex with a forward
scanner that looks for the next "[" or bare "https://" (whichever
comes first) and only commits to a markdown link once a complete,
valid [label](https://...) is found; this also fixes a related
Copilot finding on the extension PR where a label containing its own
https:// URL was mishandled. Tightened the URL boundary characters to
also stop at quotes. Added a LinkedText component test (renders both
link forms, presses each, asserts the in-app browser is opened with
the correct URL) and accessibilityRole="link" on tappable segments,
matching the existing pattern in BalancesList.tsx.

* discovery: reject malformed URLs, keep brackets in markdown destinations

Addresses further Copilot feedback on #994:

- A candidate was only checked against the "https://" text prefix, so
  malformed values like bare "https://" or "https://?query" (no host)
  were still emitted as tappable links. Validate every candidate with
  `new URL(...)` and require the "https:" protocol before treating it
  as a link; rejected candidates are left as plain text (the original
  substring, not `url.href`, is still used for display/navigation,
  since the WHATWG URL parser normalizes some inputs like adding a
  trailing slash to a bare origin).
- The URL boundary excluded square brackets universally, which broke
  markdown-link destinations containing the common `?tag[]=value`
  query syntax: the parse failed and the same target was then emitted
  as a truncated bare link pointing at the wrong address. Brackets are
  now only excluded from a *bare* URL's boundary (to avoid ambiguity
  with an immediately following markdown link) - a markdown
  destination's balanced closing paren is enough to bound it on its
  own.
- Added the same eslint-disable-next-line react/no-array-index-key
  suppression to the linked-segment branch in LinkedText.tsx that the
  plain-text branch already had, since the AirBnB rule also flags
  indexes used inside template literals.

Added regression tests for both parser fixes, matching stellar/freighter#2985.

---------

Co-authored-by: Claude <noreply@anthropic.com>
CassioMG added a commit to stellar/freighter-mobile that referenced this pull request Aug 31, 2026
* discovery: support hyperlinks in protocol descriptions

Adds a LinkedText component that turns markdown-style
[text](https://...) links and bare https:// URLs in a protocol's
description into tappable links via the existing Text `url` prop,
restricted to https to match the HTTPS-only convention already used
for protocol URLs elsewhere (helpers/protocols.ts). Newlines already
render correctly in React Native, so no change was needed there.

* discovery: fix link parsing for balanced parentheses in URLs

Ports the fix from stellar/freighter PR #2985 (Copilot review
feedback): the regex-based matcher excluded all parentheses from a
URL's character class, truncating URLs that legitimately contain them
(e.g. Wikipedia-style https://.../Function_(mathematics)), and for the
markdown form the first ")" inside the URL was mistaken for the link's
closing paren. Replaced it with a small scanner that tracks paren
depth so balanced parens stay part of the URL, and only an unmatched
")" ends it. Added regression tests for both the bare-URL and
markdown-link forms.

* discovery: fix link parsing bugs and address review feedback

Addresses review feedback on #994:

- Copilot: __tests__/helpers/linkedText.test.ts imported "helpers/linkedText",
  which jest.config.js's moduleNameMapper remaps to
  __mocks__/helpers/linkedText - a file that doesn't exist, so the
  suite failed to resolve the module before any test ran. Import the
  real module via a relative path instead.
- Copilot: LinkedText had no component-level test exercising the
  actual tappable behavior (pressing a parsed segment opens the
  right URL) or its accessibility semantics.
- Copilot: bare URLs wrapped in quotes (e.g. "https://example.com/x")
  absorbed the closing quote into the tappable URL.
- aristidesstaffieri: a stray, unmatched "[" before a real markdown
  link could swallow the real link into its own (invalid) label
  (matching the same fix applied on the extension PR, stellar/freighter#2985).

Replaced the backward-scanning markdown-opener regex with a forward
scanner that looks for the next "[" or bare "https://" (whichever
comes first) and only commits to a markdown link once a complete,
valid [label](https://...) is found; this also fixes a related
Copilot finding on the extension PR where a label containing its own
https:// URL was mishandled. Tightened the URL boundary characters to
also stop at quotes. Added a LinkedText component test (renders both
link forms, presses each, asserts the in-app browser is opened with
the correct URL) and accessibilityRole="link" on tappable segments,
matching the existing pattern in BalancesList.tsx.

* discovery: reject malformed URLs, keep brackets in markdown destinations

Addresses further Copilot feedback on #994:

- A candidate was only checked against the "https://" text prefix, so
  malformed values like bare "https://" or "https://?query" (no host)
  were still emitted as tappable links. Validate every candidate with
  `new URL(...)` and require the "https:" protocol before treating it
  as a link; rejected candidates are left as plain text (the original
  substring, not `url.href`, is still used for display/navigation,
  since the WHATWG URL parser normalizes some inputs like adding a
  trailing slash to a bare origin).
- The URL boundary excluded square brackets universally, which broke
  markdown-link destinations containing the common `?tag[]=value`
  query syntax: the parse failed and the same target was then emitted
  as a truncated bare link pointing at the wrong address. Brackets are
  now only excluded from a *bare* URL's boundary (to avoid ambiguity
  with an immediately following markdown link) - a markdown
  destination's balanced closing paren is enough to bound it on its
  own.
- Added the same eslint-disable-next-line react/no-array-index-key
  suppression to the linked-segment branch in LinkedText.tsx that the
  plain-text branch already had, since the AirBnB rule also flags
  indexes used inside template literals.

Added regression tests for both parser fixes, matching stellar/freighter#2985.

---------

Co-authored-by: Jake Urban <10968980+JakeUrban@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
CassioMG added a commit that referenced this pull request Aug 31, 2026
…2985) (#2989)

* discover: support hyperlinks and newlines in protocol descriptions

Adds a LinkifiedText component that turns markdown-style
[text](https://...) links and bare https:// URLs in a protocol's
description into clickable links, restricted to https to match the
existing isSafeHttpsUrl convention used for protocol.websiteUrl. Also
preserves embedded newlines via white-space: pre-line, which the
description text previously collapsed.

* discover: fix link parsing for balanced parens, restore link underline

Addresses Copilot review feedback on #2985:

- parseLinkedText previously excluded all parentheses from a URL's
  character class, truncating URLs that legitimately contain them
  (e.g. Wikipedia-style https://.../Function_(mathematics)), and for
  the markdown form the first ")" inside the URL was mistaken for the
  link's closing paren. Replaced the regex-based matcher with a small
  scanner that tracks paren depth so balanced parens stay part of the
  URL, and only an unmatched ")" ends it. Added regression tests for
  both the bare-URL and markdown-link forms.
- ProtocolDetailsPanel's global stylesheet resets all <a> underlines,
  so the description's links were distinguished from surrounding text
  by color alone. Restored text-decoration: underline on them so the
  link cue doesn't depend on color perception.

* discover: fix nested-bracket and label-URL parsing bugs

Addresses further review feedback on #2985:

- Copilot: a markdown label containing its own https:// URL (e.g.
  [https://a.example](https://b.example)) was mishandled because the
  parser scanned for bare https:// occurrences first, matching the
  label's URL before considering the markdown link around it.
- aristidesstaffieri: a stray, unmatched "[" before a real markdown
  link could swallow the real link into its own (invalid) label, since
  the backward-scanning opener regex always matched from the leftmost
  "[" rather than the nearest one.

Replaced the backward-scanning approach with a forward scanner that
looks for the next "[" or bare "https://" (whichever comes first) and
only commits to a markdown link once a complete, valid
[label](https://...) is found starting there; an incomplete/invalid
"[" is left as literal text and scanning resumes just past it. This
also incidentally required tightening the URL boundary characters to
include quotes, since a bare URL inside quotes was absorbing the
closing quote. Added regression tests for all three cases.

* discover: reject malformed URLs, keep brackets in markdown destinations

Addresses further Copilot feedback on #2985:

- A candidate was only checked against the "https://" text prefix, so
  malformed values like bare "https://" or "https://?query" (no host)
  were still emitted as clickable links, even though the existing
  isSafeHttpsUrl guard in Discover/index.tsx would reject them.
  Validate every candidate with `new URL(...)` and require the
  "https:" protocol before treating it as a link; reject candidates
  are left as plain text (the original substring, not `url.href`,
  is still used for display/navigation, since the WHATWG URL parser
  normalizes some inputs like adding a trailing slash to a bare
  origin).
- The URL boundary excluded square brackets universally, which broke
  markdown-link destinations containing the common `?tag[]=value`
  query syntax: the parse failed and the same target was then emitted
  as a truncated bare link pointing at the wrong address. Brackets are
  now only excluded from a *bare* URL's boundary (to avoid ambiguity
  with an immediately following markdown link) - a markdown
  destination's balanced closing paren is enough to bound it on its
  own.

Added regression tests for both.

---------

Co-authored-by: Jake Urban <10968980+JakeUrban@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants