Skip to content

feat(markdown): inline [label](url) link parsing in MarkdownInline (M1, @since 1.6.8)#119

Merged
DemchaAV merged 1 commit into
developfrom
feat/markdown-inline-link-parser
Jun 1, 2026
Merged

feat(markdown): inline [label](url) link parsing in MarkdownInline (M1, @since 1.6.8)#119
DemchaAV merged 1 commit into
developfrom
feat/markdown-inline-link-parser

Conversation

@DemchaAV

@DemchaAV DemchaAV commented Jun 1, 2026

Copy link
Copy Markdown
Owner

Summary

Headline feature for the v1.6.8 cycle — closes the CV v2
migration gap where project / education / experience entry titles
could not be rendered as hyperlinks.

The renderer pipeline already had the output primitive
(RichText.link(text, uri) — used by the CV header's contact
links since v1.6.0). What was missing was the inline-markdown
adapter
that every body / row / entry renderer routes through
recognising the [label](url) syntax. After this PR it does.

Implementation

MarkdownInline.append(rich, text, baseStyle) gets a pre-pass
that scans for [text](url) matches:

  • Each match emits exactly one rich.link(text, url) run.
  • Plain segments between (or surrounding) link matches flow
    through the existing MarkdownText emphasis pipeline unchanged
    **bold** / *italic* / _italic_ still work as before.
  • MarkdownInline.plainText(value) is updated in lockstep:
    [label](url) collapses to just label. Callers that need
    the visible-text projection (ProjectLabel.parse uses this
    for the project title) keep getting clean output.
  • One shared LINK_PATTERN regex constant for both paths so the
    two views agree on what counts as a link.

What this PR does NOT touch

  • ProjectRenderer / EntryRenderer — they currently call
    rich.style(...) directly on the title segment instead of
    routing through MarkdownInline.append, so a [text](url) in
    a CvRow.label still won't render as a link in the existing
    layered presets. That's deliberately scoped to Track M3 (a
    separate focused PR) so this PR stays a pure parser change with
    japicmp-clean public-API extension.
  • CvRow record shape — no new field, no breaking change.
    The link information rides inside the existing label string.

Design tradeoffs

  • v1 does not honour emphasis inside the link label
    ([**bold**](url) renders as a single link run with literal
    asterisks; outside emphasis works fine). Recursive parsing
    inside the label is a v2 candidate.
  • v1 does not support nested brackets [a [b] c](url)
    the regex requires no inner brackets. Document authors hit
    by this can restructure the label.
  • Empty link text [](url) is matched and emits an empty-text
    link run. Unusual but legal.

Test plan

  • New MarkdownInlineTest (12 tests):
    • plainText strips link syntax, combines with emphasis strip,
      leaves bare brackets intact, handles multiple links, handles
      null safely (5 tests).
    • append emits exactly one hyperlink run with the correct
      text + uri for [text](url), mixes plain + emphasis + link,
      preserves ordering of multiple links, leaves bare brackets
      as literal, keeps ** / * / _ emphasis working without
      links, null/empty no-op, appendTrimmed strips whitespace
      then parses (7 tests).
  • ./mvnw verify -pl . -P japicmp1049 tests, 0
    failures
    ; japicmp vs v1.6.7 baseline: semver PATCH
    (compatible behaviour extension on existing public
    methods, no signature change).

@SInCE 1.6.8)

Headline feature for v1.6.8 — closes the CV v2 migration gap
where project / education / experience entry titles could not be
rendered as hyperlinks. The renderer pipeline already had the
output primitive (RichText.link); the inline-markdown adapter that
every body / row / entry renderer routes through just didn't
recognise the syntax. After this PR it does.

Implementation:
- MarkdownInline.append(rich, text, baseStyle) gets a pre-pass
  that scans for [text](url) matches. Each match emits exactly
  one rich.link(text, url) run. Plain segments between (or
  surrounding) link matches flow through the existing
  MarkdownText emphasis pipeline unchanged, so **bold** /
  *italic* still work as before.
- MarkdownInline.plainText(value) strips link syntax in lockstep:
  [label](url) collapses to just `label`. Callers that need the
  visible-text projection (ProjectLabel.parse uses this for the
  project title) keep getting clean output.
- One shared LINK_PATTERN regex constant for both paths so the
  two views agree on what counts as a link.

Design notes:
- v1 does NOT honour emphasis INSIDE the link label (a
  `[**bold**](url)` renders as a single link run with the literal
  asterisks). Outside emphasis works. Recursive parsing inside
  the label is a v2 candidate; not worth the parser complexity
  for the typical CV / cover-letter use case.
- v1 does NOT support nested brackets `[a [b] c](url)`. Pattern
  requires no inner brackets. Document authors hit by this can
  escape with HTML entities or restructure the label.
- Empty link text `[](url)` is matched and emits an empty-text
  link run (downstream rich.link("", url) handles gracefully).
  Unusual but legal.

What's NOT in this PR:
- ProjectRenderer / EntryRenderer wiring. They currently call
  rich.style(...) directly on the title segment instead of
  routing through MarkdownInline.append, so a [text](url) in a
  CvRow.label still won't render as a link in the existing
  layered presets. That's deliberately scoped to Track M3 (a
  separate focused PR) so this PR stays a pure parser change
  with japicmp-clean public-API extension.

Test plan:
- New MarkdownInlineTest (12 tests):
  * plainText strips link syntax, combines with emphasis strip,
    leaves bare brackets intact, handles multiple links, handles
    null safely (5 tests).
  * append emits exactly one hyperlink run with correct text/uri
    for [text](url), mixes plain + emphasis + link, preserves
    ordering of multiple links, leaves bare brackets as literal,
    keeps **/* emphasis working without links, null/empty no-op,
    appendTrimmed strips whitespace then parses (7 tests).
- ./mvnw verify -pl . -P japicmp - 1049 tests, 0 failures.
  japicmp vs v1.6.7 baseline: semver PATCH (compatible behaviour
  extension on existing public methods, no signature change).
@DemchaAV DemchaAV merged commit d54c505 into develop Jun 1, 2026
11 checks passed
@DemchaAV DemchaAV deleted the feat/markdown-inline-link-parser branch June 1, 2026 16:31
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.

1 participant