npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

mdxld

v1.9.0

Published

Lightweight MDX + Linked Data parser and stringifier

Downloads

566

Readme

mdxld

Lightweight MDX + Linked Data parser and stringifier. Parse MDX documents with YAML frontmatter containing JSON-LD style properties ($id, $type, $context) into structured documents, and stringify them back.

Installation

npm install mdxld
# or
pnpm add mdxld
# or
yarn add mdxld

Features

  • Lightweight - Only ~5KB, zero runtime dependencies
  • Parse - Extract frontmatter and content from MDX files
  • Stringify - Convert documents back to MDX format
  • JSON-LD Properties - First-class support for $id, $type, $context
  • Type-Safe - Full TypeScript support with generics
  • Two Modes - Expanded (default) or flat frontmatter handling
  • Type Generation - CLI and API to generate TypeScript types from MDX files

Quick Start

import { parse, stringify } from 'mdxld'

// Parse MDX content
const doc = parse(`---
$id: https://example.com/posts/hello
$type: BlogPosting
$context: https://schema.org
title: Hello World
author: Jane Doe
---

# Hello World

This is my first post!
`)

console.log(doc)
// {
//   id: 'https://example.com/posts/hello',
//   type: 'BlogPosting',
//   context: 'https://schema.org',
//   data: { title: 'Hello World', author: 'Jane Doe' },
//   content: '\n# Hello World\n\nThis is my first post!\n'
// }

// Stringify back to MDX
const mdx = stringify(doc)

CLI

mdxld includes a CLI for generating TypeScript types from your MDX files.

Type Generation

# Generate types from all MDX/MD files in project
mdxld typegen

# Custom glob pattern
mdxld typegen "content/**/*.mdx"

# Custom output path (default: .mdx/types.d.ts)
mdxld typegen -o src/types/mdx.d.ts

This scans your MDX files, extracts frontmatter, infers TypeScript types, and generates a .d.ts file:

// .mdx/types.d.ts (auto-generated)
import type { MDXLDDocument } from 'mdxld'

export interface BlogPost {
  $type?: string
  title: string
  author: string
  tags?: string[]
}

export type BlogPostDocument = MDXLDDocument & { data: BlogPost }

Programmatic API

import { generateTypes, inferSchemaFromDocument } from 'mdxld/typegen'
import { parse } from 'mdxld'

// Parse documents
const docs = files.map(content => parse(content))

// Generate TypeScript types
const types = generateTypes(docs)
// Returns TypeScript declaration file content

API Reference

parse(content, options?)

Parse MDX content with YAML frontmatter into a structured document.

function parse(content: string, options?: ParseOptions): MDXLDDocument

Parameters:

  • content - Raw MDX string with optional YAML frontmatter
  • options.mode - 'expanded' (default) or 'flat'

Returns: MDXLDDocument object

Parse Modes

Expanded Mode (default): Extracts $id, $type, $context to root level properties.

const doc = parse(content, { mode: 'expanded' })
// { id: '...', type: '...', context: '...', data: {...}, content: '...' }

Flat Mode: Keeps all frontmatter in the data object unchanged.

const doc = parse(content, { mode: 'flat' })
// { data: { $id: '...', $type: '...', ...otherFields }, content: '...' }

stringify(document, options?)

Convert an MDXLDDocument back to MDX string format.

function stringify(doc: MDXLDDocument, options?: StringifyOptions): string

Parameters:

  • doc - MDXLDDocument to stringify
  • options.mode - 'expanded' (default) or 'flat'

Returns: MDX string with YAML frontmatter

const mdx = stringify({
  id: 'https://example.com/doc',
  type: 'Article',
  data: { title: 'My Article' },
  content: '# My Article\n\nContent here.'
})

// Output:
// ---
// $id: https://example.com/doc
// $type: Article
// title: My Article
// ---
//
// # My Article
//
// Content here.

Type Utilities

isType(doc, type)

Type guard to check if a document has a specific $type.

import { isType } from 'mdxld'

if (isType(doc, 'BlogPosting')) {
  // TypeScript knows doc.type === 'BlogPosting'
}

isOneOfTypes(doc, types)

Type guard to check if a document has one of several types.

import { isOneOfTypes } from 'mdxld'

if (isOneOfTypes(doc, ['BlogPosting', 'Article'])) {
  // doc.type is 'BlogPosting' | 'Article'
}

createTypedDocument(type, data, content)

Factory function to create typed documents with proper TypeScript inference.

import { createTypedDocument } from 'mdxld'

const post = createTypedDocument('BlogPosting', {
  title: 'Hello',
  author: 'Jane'
}, '# Hello World')

Types

MDXLDDocument<TData>

The main document type returned by parse().

interface MDXLDDocument<TData = Record<string, unknown>> {
  /** JSON-LD @id - document identifier/URL */
  id?: string

  /** JSON-LD @type - document type (e.g., 'BlogPosting') */
  type?: string | string[]

  /** JSON-LD @context - vocabulary context */
  context?: string | string[] | Record<string, unknown>

  /** Frontmatter data (excluding $id, $type, $context in expanded mode) */
  data: TData

  /** MDX content (everything after frontmatter) */
  content: string
}

MDXLDData

Type for frontmatter data with optional LD properties.

interface MDXLDData {
  $id?: string
  $type?: string | string[]
  $context?: string | string[] | Record<string, unknown>
  [key: string]: unknown
}

ParseOptions / StringifyOptions

interface ParseOptions {
  /** Parse mode: 'expanded' extracts $-prefixed props, 'flat' keeps them in data */
  mode?: 'expanded' | 'flat'
}

interface StringifyOptions {
  /** Stringify mode: 'expanded' adds $-prefixed props, 'flat' uses data as-is */
  mode?: 'expanded' | 'flat'
}

Primitives Integration

mdxld provides optional re-exports of AI primitives packages for convenient access:

AI Functions

import { RPC, AI, generateText, generateObject } from 'mdxld/functions'

// Use RPC primitives with capnweb promise pipelining
const rpc = RPC({
  functions: {
    hello: () => 'world',
    greet: (name: string) => `Hello, ${name}!`,
  },
})

// Use AI function constructors
const summarize = AI('Generate a summary', {
  input: schema({ text: 'string' }),
  output: schema({ summary: 'string' }),
})

// Use generation utilities
const result = await generateText({
  model: 'claude-3-5-sonnet-20241022',
  prompt: 'Write a haiku about MDX',
})

Installation: pnpm add ai-functions (optional peer dependency)

AI Database

import { DB } from 'mdxld/database'

// Schema-first database with automatic bi-directional relationships
const db = DB({
  Post: {
    title: 'string',
    content: 'markdown',
    author: 'Author.posts', // Creates Post.author -> Author AND Author.posts -> Post[]
  },
  Author: {
    name: 'string',
    email: 'string',
    // posts: Post[] auto-created from backref
  },
})

// Typed, provider-agnostic access
const post = await db.Post.get('hello-world')
const author = await post.author // Resolved Author
const posts = await db.Author.get('john').posts // Post[]

Installation: pnpm add ai-database (optional peer dependency)

Provider resolved from DATABASE_URL:

  • ./content - Filesystem
  • sqlite://./content - SQLite
  • libsql://your-db.turso.io - Turso
  • chdb://./content - ClickHouse (local)

AI Workflows

import { Workflow, on, every } from 'mdxld/workflows'

// Create a workflow with $ context
const workflow = Workflow($ => {
  // Register event handlers
  $.on.Customer.created(async (customer, $) => {
    $.log('New customer:', customer.name)
    await $.send('Email.welcome', { to: customer.email })
  })

  $.on.Order.completed(async (order, $) => {
    $.log('Order completed:', order.id)
  })

  // Register scheduled tasks
  $.every.hour(async ($) => {
    $.log('Hourly check')
  })

  $.every.Monday.at9am(async ($) => {
    $.log('Weekly standup reminder')
  })

  $.every.minutes(30)(async ($) => {
    $.log('Every 30 minutes')
  })

  // Natural language scheduling
  $.every('first Monday of the month', async ($) => {
    $.log('Monthly report')
  })
})

// Start the workflow
await workflow.start()

// Emit events
await workflow.send('Customer.created', {
  name: 'John',
  email: '[email protected]',
})

Installation: pnpm add ai-workflows (optional peer dependency)

Related Packages

For additional functionality, use these companion packages:

| Package | Description | |---------|-------------| | @mdxld/ast | AST manipulation and analysis | | @mdxld/jsx | MDX compilation with React/Preact/Hono JSX support | | @mdxld/compile | JSX compilation with esbuild | | @mdxld/evaluate | MDX execution and rendering | | @mdxld/validate | Schema validation | | @mdxld/extract | Bi-directional MDX ↔ Markdown extraction | | @mdxld/jsonld | JSON-LD conversion utilities |

AI Primitives (Optional Peer Dependencies)

| Package | Description | Import | |---------|-------------|--------| | ai-functions | RPC, AI functions, generation | mdxld/functions | | ai-database | Schema-first DB with bi-directional relationships | mdxld/database | | ai-workflows | Event-driven workflows with $ context | mdxld/workflows |

Examples

Blog Post

import { parse, stringify, isType } from 'mdxld'

const content = `---
$type: BlogPosting
$context: https://schema.org
title: Getting Started with MDXLD
author: Jane Doe
datePublished: 2024-01-15
tags:
  - mdx
  - tutorial
---

# Getting Started with MDXLD

Learn how to use MDXLD for your documentation.
`

const doc = parse(content)

if (isType(doc, 'BlogPosting')) {
  console.log(`Published: ${doc.data.datePublished}`)
  console.log(`Tags: ${doc.data.tags.join(', ')}`)
}

API Documentation

import { parse } from 'mdxld'

const apiDoc = parse(`---
$type: APIEndpoint
$id: /api/users
method: GET
parameters:
  - name: limit
    type: number
    required: false
---

# List Users

Returns a paginated list of users.
`)

console.log(apiDoc.type)  // 'APIEndpoint'
console.log(apiDoc.id)    // '/api/users'

Round-Trip Parsing

import { parse, stringify } from 'mdxld'

const original = `---
$type: Article
title: Hello
---

# Hello
`

const doc = parse(original)
doc.data.title = 'Updated Title'
const updated = stringify(doc)

// ---
// $type: Article
// title: Updated Title
// ---
//
// # Hello

YAML Frontmatter Support

The parser handles common YAML features:

---
# Comments are ignored
$type: Document

# Strings
title: Hello World
quoted: "With special: characters"

# Numbers
count: 42
price: 19.99

# Booleans
published: true
draft: false

# Null
deletedAt: null

# Arrays
tags:
  - one
  - two
  - three
inline_array: [a, b, c]

# Nested objects
author:
  name: Jane
  email: [email protected]
---

License

MIT