Skip to content

feat(markdown): render inline {@link Target} references as links#181

Open
Kiarokh wants to merge 3 commits into
mainfrom
feat/inline-link-references
Open

feat(markdown): render inline {@link Target} references as links#181
Kiarokh wants to merge 3 commits into
mainfrom
feat/inline-link-references

Conversation

@Kiarokh
Copy link
Copy Markdown
Collaborator

@Kiarokh Kiarokh commented May 18, 2026

Summary

JSDoc/TSDoc {@link Target} references inside component descriptions
previously surfaced in the generated docs as literal text — readers saw
{@link Rule} verbatim with nothing clickable. This PR teaches the
markdown pipeline to rewrite those references into proper links, the
same way IDEs interpret them for cmd-click navigation.

The change is split into three atomic commits:

  1. fix(markdown): skip type-linking inside anchor ancestors — A
    prerequisite bug fix in typeLinks. Without it, a <code> element
    inside an existing <a> would get its type token wrapped in a
    second <a>, producing invalid nested anchors. Generalises the
    existing <pre><code> skip-set into a broader "skippable code" set
    that also captures code inside any anchor ancestor.

  2. feat(markdown): render inline {@link Target} references as links — Adds a remark plugin that walks mdast text nodes for
    {@link …} syntax and emits link nodes. Supports the three TSDoc
    forms ({@link Target}, {@link Target Display},
    {@link Target | Display}) plus absolute URLs. Targets are resolved
    against the project's known types and component tags via a new
    component registry that mirrors the existing type registry. Bare
    identifiers are wrapped in <code> so they match how type names
    render elsewhere; unresolved targets still render as inline code
    instead of bare prose; references inside inline and fenced code are
    intentionally left untouched.

  3. docs(markdown): add example demonstrating inline @link references — Adds kompendium-example-inline-links so the
    rendered kompendium-markdown page shows each syntactic form
    alongside its source. An integration test pins the rendered HTML
    against the actual built kompendium.json registry to keep the
    showcase honest.

Behaviour matrix

Input Output
{@link MenuItem} (known type) <a href="#/type/MenuItem"><code>MenuItem</code></a>
{@link kompendium-markdown} (known component) <a href="#/component/kompendium-markdown/"><code>kompendium-markdown</code></a>
{@link MenuItem | the menu item} (free-form label) <a href="#/type/MenuItem">the menu item</a>
{@link https://example.com | docs} (absolute URL) <a href="https://example.com">docs</a>
{@link Unknown} (unresolved bare identifier) <code>Unknown</code>
`{@link Foo}` (inside inline code) unchanged
{@link Foo} inside ``` fenced block unchanged

Test plan

  • Unit tests for the plugin against minimal mdast trees
    (markdown-inline-links.spec.ts)
  • End-to-end tests through the full pipeline covering all syntactic
    forms, inline-code passthrough, fenced-code passthrough, and URL
    targets (markdown.spec.ts)
  • Integration test asserting the example renders correctly against
    Kompendium's own built registry (markdown-example-integration.spec.ts)
  • npm run build clean
  • npm run lint:src clean
  • npm test — 115 passing, 5 pre-existing skips
  • Manual: open npm start → navigate to kompendium-markdown
    visually verify the new "Inline @link references" example

Notes

  • The feature is purely additive in the markdown pipeline. Pages that
    contain no {@link …} references are unaffected.
  • The typeLinks fix in commit 1 is a sensible cleanup on its own merits
    (nested <a> is invalid HTML) and is a hard prerequisite for the
    feature: without it, {@link KnownType} would produce nested anchors.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added {@link ...} syntax support for creating clickable documentation links to components, types, and external URLs
    • Component references now work alongside type references in markdown
    • Unknown references automatically render as inline code
  • Tests

    • Added comprehensive test coverage for inline link behavior

Review Change Stack

Kiarokh and others added 3 commits May 18, 2026 11:04
When an inline `<code>` element already sits inside an `<a>` (for example,
from a markdown link like `[label `Foo`](url)`), the typeLinks pass would
wrap the type token in another anchor and produce a nested `<a>`, which is
invalid HTML and confuses navigation.

Generalises the existing `<pre><code>` skip-set into a more general
"skippable code" set that also captures `<code>` inside any anchor
ancestor, and leaves those code elements untouched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
JSDoc/TSDoc `{@link Target}` references in component descriptions
previously surfaced in the generated docs as literal text. Adds a remark
plugin that rewrites them into mdast link nodes during the markdown
pipeline, supporting the standard syntactic forms:

  {@link Target}
  {@link Target Display text}
  {@link Target | Display text}
  {@link https://example.com | Display text}

Targets are resolved against the project's known types and component
tags (a new component registry mirrors the existing type registry).
Bare-identifier references — those without an explicit display label —
are wrapped in `<code>` so they visually match how type names render
elsewhere in the docs. Unresolved targets still render as inline code
rather than dangling syntax, and absolute URLs link directly.

References inside inline code (``{@link Foo}``) and fenced code blocks
are intentionally left untouched so the syntax itself can be documented.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a dedicated `kompendium-example-inline-links` example component
attached to `kompendium-markdown` so the rendered docs page shows each
inline `{@link …}` syntactic form alongside its source. The integration
test renders the example against the actual built `kompendium.json`
registry to keep the showcase honest as the docs build evolves.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 18, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ef6e2cb8-d2b4-4458-8ddf-0dfb82198776

📥 Commits

Reviewing files that changed from the base of the PR and between 85b297e and 4e5284e.

📒 Files selected for processing (11)
  • src/components/app/app.tsx
  • src/components/markdown/examples/inline-links-example.ts
  • src/components/markdown/examples/inline-links.tsx
  • src/components/markdown/markdown-types.ts
  • src/components/markdown/markdown.tsx
  • src/kompendium/markdown-inline-links.ts
  • src/kompendium/markdown-typelinks.ts
  • src/kompendium/markdown.ts
  • src/kompendium/test/markdown-example-integration.spec.ts
  • src/kompendium/test/markdown-inline-links.spec.ts
  • src/kompendium/test/markdown.spec.ts

📝 Walkthrough

Walkthrough

This PR adds TSDoc/JSDoc {@link ...} inline reference transformation to the markdown pipeline. It extracts component metadata from app data, implements a configurable link resolver that routes known types and components to fragment URLs, integrates the transformation into remark/rehype preprocessing, and strengthens type-link safety to prevent double-linking.

Changes

Inline @link Reference Handling

Layer / File(s) Summary
Component registry storage and propagation
src/components/markdown/markdown-types.ts, src/components/app/app.tsx, src/components/markdown/markdown.tsx
Module-scoped components array added alongside types, populated from app's this.data.docs.components, and threaded through markdownToHtml calls.
Inline links AST transformation
src/kompendium/markdown-inline-links.ts
New utilities: normalizeInlineLinkUrls() preprocesses URL-bearing {@link ...} into markdown links; inlineLinks() transformer walks mdast text nodes, replaces {@link ...} with link/code nodes via resolver callback, and skips processing inside existing links.
Markdown pipeline integration and link resolution
src/kompendium/markdown.ts
markdownToHtml accepts components parameter, creates resolver mapping types/components to #/type/... and #/component/.../ routes, registers normalizeInlineLinkUrls preprocessing step, and adds inlineLinks transformer to pipeline.
Type-link safety for inline links
src/kompendium/markdown-typelinks.ts
Replaces pre-only code-skipping logic with collectSkippableCodeElements() that also gathers <code> inside <a> anchors, preventing type-link wrapping inside resolved inline links.
Unit tests for inline links transformer
src/kompendium/test/markdown-inline-links.spec.ts
Jest suite covering no-op behavior, bare identifier and labeled transformations with resolver, space/pipe-separated display text, unknown target fallbacks, absolute URL handling, and nested-link prevention.
Integration tests for markdown pipeline
src/kompendium/test/markdown.spec.ts
New inline @link references suite validating resolved type/component links, display-text formats, fallback rendering in edge cases, and behavior inside code blocks.
End-to-end registry test
src/kompendium/test/markdown-example-integration.spec.ts
Conditional integration spec loading real registry from www/kompendium.json, verifying inlineLinksExample renders with correct links and no syntax leakage.
Example component and reference documentation
src/components/markdown/examples/inline-links-example.ts, src/components/markdown/examples/inline-links.tsx
inlineLinksExample template string documents {@link ...} behavior; InlineLinksExample Stencil component renders it via kompendium-markdown.

Sequence Diagram

sequenceDiagram
  participant App as App.fetchData()
  participant Registry as markdown-types
  participant MarkdownTsx as Markdown.renderMarkdown()
  participant Pipeline as markdownToHtml()
  participant Normalize as normalizeInlineLinkUrls()
  participant Resolver as createLinkResolver()
  participant InlineLinks as inlineLinks()
  participant TypeLinks as typeLinks()
  participant HTML as HTML Output
  
  App->>Registry: setTypes(typeNames)
  App->>Registry: setComponents(componentTags)
  
  MarkdownTsx->>MarkdownTsx: types = getTypes()
  MarkdownTsx->>MarkdownTsx: components = getComponents()
  MarkdownTsx->>Pipeline: markdownToHtml(text, types, components)
  
  Pipeline->>Normalize: normalizeInlineLinkUrls(text)
  Normalize->>Pipeline: markdown with [label](url) links
  
  Pipeline->>Resolver: createLinkResolver(types, components)
  Resolver->>Pipeline: resolver: (target) => url | null
  
  Pipeline->>InlineLinks: inlineLinks({resolve})
  InlineLinks->>InlineLinks: walk mdast text nodes
  InlineLinks->>Resolver: resolve(target)
  Resolver->>InlineLinks: `#/type/X` or `#/component/Y/`
  InlineLinks->>Pipeline: mdast link nodes
  
  Pipeline->>TypeLinks: typeLinks() transformer
  TypeLinks->>TypeLinks: collect skippable code (inside pre or anchor)
  TypeLinks->>Pipeline: avoid wrapping types in links
  
  Pipeline->>HTML: final HTML with resolved links
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • jgroth/kompendium#178: Introduces normalizeLegacyAdmonitions preprocessing step in markdownToHtml pipeline; this PR builds on that foundation by adding normalizeInlineLinkUrls preprocessing and the inline-links transformer.

Suggested labels

released

Suggested reviewers

  • jgroth
  • adrianschmidt

Poem

A rabbit hops through markdown prose,
Linking types and components with {@link} flows,
Components now resolve with care,
Double-links prevented everywhere. 🐰✨
Docs bloom bright with reference flair!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.52% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(markdown): render inline {@link Target} references as links' directly and clearly summarizes the main change: adding support for rendering JSDoc/TSDoc {@link} syntax as clickable links in the markdown pipeline.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/inline-link-references

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Kiarokh Kiarokh requested a review from jgroth May 18, 2026 11:30
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