Skip to content

feat: display yaml frontmatter as a table#2166

Merged
ghostdevv merged 6 commits intonpmx-dev:mainfrom
RYGRIT:feat/yaml-frontmatter
Mar 21, 2026
Merged

feat: display yaml frontmatter as a table#2166
ghostdevv merged 6 commits intonpmx-dev:mainfrom
RYGRIT:feat/yaml-frontmatter

Conversation

@RYGRIT
Copy link
Contributor

@RYGRIT RYGRIT commented Mar 20, 2026

🔗 Linked issue

🧭 Context

On npmx.dev, the YAML Frontmatter within .md files—specifically the key-value blocks enclosed by --- symbols—is incorrectly rendered by marked as a horizontal rule (<hr>), while the key-value pairs are erroneously rendered as <h3> tags. In contrast, GitHub renders this content as a neat key-value table.

📚 Description

Use gray-matter to parse the frontmatter, render it as a GitHub-style key-value table, and prepend it to the main HTML content.

Inspired by GitHub
image

before
image

after
image

@vercel
Copy link

vercel bot commented Mar 20, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
npmx.dev Ready Ready Preview, Comment Mar 21, 2026 4:38am
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs.npmx.dev Ignored Ignored Preview Mar 21, 2026 4:38am
npmx-lunaria Ignored Ignored Mar 21, 2026 4:38am

Request Review

@codecov
Copy link

codecov bot commented Mar 20, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 20, 2026

📝 Walkthrough

Walkthrough

The PR refactors server/utils/readme.ts imports and adds YAML frontmatter support to renderReadmeHtml via gray-matter. It parses frontmatter from the input, converts keys and stringified values to escaped HTML using escapeHtml, renders them as a key/value HTML table with a new renderFrontmatterTable helper, and prepends that table to the HTML produced by marked.parse of the markdown body. If frontmatter is absent or parsing fails, the original markdown is rendered unchanged.

Possibly related PRs

Suggested labels

needs review

Suggested reviewers

  • gameroman
  • danielroe
🚥 Pre-merge checks | ✅ 1
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The pull request description clearly relates to the changeset, explaining the problem (YAML frontmatter incorrectly rendered) and the solution (using gray-matter to parse and render as a table).

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
server/utils/readme.ts (1)

436-444: Consider logging frontmatter parsing errors for debugging.

The silent catch block provides graceful fallback, but logging the error would aid debugging when frontmatter fails to parse unexpectedly.

📝 Optional: Add error logging
-  } catch {
+  } catch (error) {
     // If frontmatter parsing fails, render the full content as-is
+    console.warn('[readme] Failed to parse frontmatter:', error)
   }

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6d62cafc-c618-4556-a7c0-aadbc2345a03

📥 Commits

Reviewing files that changed from the base of the PR and between f0ada7e and 88d6abc.

📒 Files selected for processing (1)
  • server/utils/readme.ts

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a509b5af-43a6-48d6-baeb-741e2bcbaaf2

📥 Commits

Reviewing files that changed from the base of the PR and between 88d6abc and 4457658.

📒 Files selected for processing (1)
  • server/utils/readme.ts

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fb7dc475-aa2e-4617-aec3-972edada6eeb

📥 Commits

Reviewing files that changed from the base of the PR and between 4457658 and ec1d77e.

📒 Files selected for processing (1)
  • server/utils/readme.ts

Comment on lines +472 to +476
const { data, content: body } = matter(content)
if (data && Object.keys(data).length > 0) {
frontmatterHtml = renderFrontmatterTable(data)
markdownBody = body
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

In gray-matter, for input starting with empty YAML frontmatter (---\n---\nBody), does matter(content)returndata = {}andcontent stripped of delimiters?

💡 Result:

Yes, in gray-matter, for input starting with empty YAML frontmatter (---\n---\nBody), matter(content) returns an object with data = {} (empty object) and content stripped of the frontmatter delimiters (i.e., content = "Body"). The frontmatter between the delimiters is empty (all whitespace/nothing), so the YAML parser returns an empty object, and the delimiters are removed from the content. Additionally, the result includes isEmpty: true (or a truthy value for empty matter, as per v4.0+) and possibly empty property with the original matter string.

Citations:


Always strip frontmatter delimiters even when metadata is empty.

When matter(content) parses an empty YAML frontmatter block (---\n---\nBody), it returns data = {} with the delimiters removed from content. However, the current code only assigns markdownBody = body when Object.keys(data).length > 0, leaving the delimiters in place if the frontmatter is empty. These delimiters will then render as horizontal rules (<hr>) when passed to marked. The table generation should remain conditional, but the body assignment must happen unconditionally after a successful parse.

🔧 Proposed fix
   try {
     const { data, content: body } = matter(content)
-    if (data && Object.keys(data).length > 0) {
-      frontmatterHtml = renderFrontmatterTable(data)
-      markdownBody = body
-    }
+    markdownBody = body
+    if (data && Object.keys(data).length > 0) {
+      frontmatterHtml = renderFrontmatterTable(data)
+    }
   } catch {

@ghostdevv ghostdevv added this pull request to the merge queue Mar 21, 2026
Merged via the queue into npmx-dev:main with commit 8cd4074 Mar 21, 2026
20 checks passed
@github-actions github-actions bot mentioned this pull request Mar 21, 2026
@RYGRIT RYGRIT deleted the feat/yaml-frontmatter branch March 21, 2026 07:17
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.

2 participants