Skip to content

feat(cv-v2): hyperlink-aware ProjectRenderer + ProjectLabel (M3, @since 1.6.8)#120

Merged
DemchaAV merged 1 commit into
developfrom
feat/project-renderer-hyperlinks
Jun 1, 2026
Merged

feat(cv-v2): hyperlink-aware ProjectRenderer + ProjectLabel (M3, @since 1.6.8)#120
DemchaAV merged 1 commit into
developfrom
feat/project-renderer-hyperlinks

Conversation

@DemchaAV

@DemchaAV DemchaAV commented Jun 1, 2026

Copy link
Copy Markdown
Owner

Summary

Closes the v1.6.8 markdown-link feature end-to-end. With M1
(#119) the
parser knew about [label](url); after this PR the CV /
cover-letter ProjectRenderer actually emits a clickable
hyperlink when a project row's label is authored as Markdown.

ProjectLabel refactor

  • Old parse() ran MarkdownInline.plainText() first, then
    split on the last (. That stripped emphasis AND links
    up-front, so the link URL was lost before the renderer ever
    saw it.
  • New parse() targets a trailing \s+\([^()]*\)\s*$ pattern
    only. Result: the title field preserves the original
    Markdown syntax ([name](url) or **bold** etc.) and is
    rendered later through MarkdownInline.append. The stack-paren
    pattern requires whitespace before its opening paren, so a
    leading [name](url) URL's own (...) segment is not mistaken
    for the stack delimiter.
Input Title Stack
"GraphCompose (Java, PDFBox)" "GraphCompose" "Java, PDFBox"
"[GraphCompose](url) (Java)" "[GraphCompose](url)" "Java"
"[GraphCompose](url)" "[GraphCompose](url)" ""
"**GraphCompose**" "**GraphCompose**" ""

ProjectRenderer wiring

  • ProjectRenderer.inline(...) and .titleThenBody(...) now
    call MarkdownInline.append(rich, label.title(), titleStyle)
    instead of rich.style(label.title(), titleStyle). Plain-text
    titles render identically to before (the emphasis pipeline
    emits one styled run); Markdown titles emit emphasis / link
    runs.
  • ProjectRenderer.plainInline(...) (one-line listing variant)
    intentionally continues to drop link syntax via
    MarkdownInline.plainText(...) because a clickable hyperlink
    would not survive the compact formatting context. This is the
    variant used by sidebar / minimal presets.

Compatibility

  • ProjectLabel.parse return shape is unchanged (still a
    two-field record). The semantic of title() changes: it now
    keeps inline Markdown rather than returning a pre-flattened
    plain-text projection. That fixed the one in-repo test that
    pinned the old abstraction-leak:
    CvV2ComponentUtilityTest.projectLabelSplitsTrailingStack was
    relying on parse() stripping ** markers up-front; the test
    is updated to assert the new shape with an inline comment
    pointing at ProjectLabelTest for the full coverage.
  • Visual baselines: existing CV v2 visual-parity baselines render
    unchanged because the canonical CvDocument fixture does not
    use inline Markdown in project labels. The new path is
    exercised by the test additions below.

Test plan

  • New ProjectLabelTest (8 tests) — pins legacy "Project
    (Stack)" parse, link-only label, link + stack, URL-paren-
    vs-stack-paren disambiguation, null/whitespace handling.
  • MarkdownInlineTest from M1 covers the link-run emission
    path itself.
  • CvV2ComponentUtilityTest.projectLabelSplitsTrailingStack
    updated to assert the new shape (**GraphCompose**
    preserved in title).
  • ./mvnw verify -pl . -P japicmp1057 tests, 0 failures.
    japicmp vs v1.6.7 baseline: semver PATCH (compatible
    internal rewiring on public methods; no signature change,
    return-shape is identical).

… 1.6.8)

Closes the v1.6.8 markdown-link feature end-to-end. With M1 the
parser knew about [label](url); after this PR, the CV/cover-letter
ProjectRenderer actually emits a clickable link when a project
row's label is authored as Markdown.

ProjectLabel refactor:
- Old parse() did MarkdownInline.plainText() first, then split on
  the last '('. That stripped emphasis AND links up-front, so the
  link URL was lost before the renderer ever saw it.
- New parse() targets a trailing `\s+\([^()]*\)\s*$` pattern only.
  Result: the title field preserves the original Markdown syntax
  ([name](url) or **bold** etc.) and is rendered later through
  MarkdownInline.append. The stack-paren pattern requires
  whitespace before its opening paren, so a leading [name](url)
  URL's own (...) segment is not mistaken for the stack delimiter.
- Examples (with the new shape):
  * "GraphCompose (Java, PDFBox)"      -> title="GraphCompose",
                                          stack="Java, PDFBox"
  * "[GraphCompose](url) (Java)"       -> title="[GraphCompose](url)",
                                          stack="Java"
  * "[GraphCompose](url)"              -> title="[GraphCompose](url)",
                                          stack=""
  * "**GraphCompose**"                 -> title="**GraphCompose**",
                                          stack=""

ProjectRenderer wiring:
- ProjectRenderer.inline and .titleThenBody now call
  MarkdownInline.append(rich, label.title(), titleStyle) instead
  of rich.style(label.title(), titleStyle). Plain-text titles
  render identically to before (the emphasis pipeline emits one
  styled run); Markdown titles emit emphasis / link runs.
- ProjectRenderer.plainInline (one-line listing variant)
  intentionally continues to drop link syntax via plainText() — a
  clickable hyperlink would not survive the compact formatting
  context (this is the variant used by sidebar / minimal presets).

Compatibility:
- ProjectLabel.parse return shape is unchanged (still a two-field
  record). The semantic of `title()` changes: it now keeps inline
  Markdown rather than returning a pre-flattened plain-text
  projection. That fixed the one in-repo test that pinned the old
  abstraction-leak: CvV2ComponentUtilityTest.projectLabelSplitsTrailingStack
  was relying on parse() stripping `**` markers up-front; the test
  is updated to assert the new shape with an inline comment
  pointing at ProjectLabelTest for the full coverage.
- Visual baselines: existing CV v2 visual-parity baselines render
  unchanged because the canonical CvDocument fixture does not use
  inline Markdown in project labels. The new path is exercised by
  the test additions below.

Test plan:
- New ProjectLabelTest (8 tests) — pins legacy "Project (Stack)"
  parse, link-only label, link + stack, URL-paren-vs-stack-paren
  disambiguation, null/whitespace handling.
- MarkdownInlineTest (from M1) covers the link-run emission path
  itself.
- CvV2ComponentUtilityTest.projectLabelSplitsTrailingStack updated
  to assert the new shape (`**GraphCompose**` preserved in title).
- ./mvnw verify -pl . -P japicmp - 1057 tests, 0 failures.
  japicmp vs v1.6.7 baseline: semver PATCH (compatible internal
  rewiring on public methods; no signature change, return-shape
  is identical).
@DemchaAV DemchaAV merged commit 06f467b into develop Jun 1, 2026
11 checks passed
@DemchaAV DemchaAV deleted the feat/project-renderer-hyperlinks branch June 1, 2026 16:43
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