mdast-util-mdx
Mdast extensions that parse and serialize MDX syntax — ESM, JSX, and expressions — inside markdown syntax trees.
Repository Health
Technical Analysis
mdast-util-mdx is the combined mdast extension for working with MDX syntax — ESM import/export statements, JSX elements, and {} expressions — inside a markdown abstract syntax tree. It bundles three sibling packages (mdast-util-mdx-expression, mdast-util-mdx-jsx, and mdast-util-mdxjs-esm) behind two functions, mdxFromMarkdown() and mdxToMarkdown(options?), so tooling built on mdast-util-from-markdown and mdast-util-to-markdown can parse MDX documents into a syntax tree and serialize them back to text without wiring up each extension individually.
It is a low-level building block maintained by the syntax-tree/unified collective, used internally by remark-mdx and, transitively, by the MDX compiler itself. Most application code reaches it indirectly through remark-mdx or an MDX-aware pipeline; you reach for this package directly only when you’re building custom markdown/MDX tooling — linters, formatters, codemods, or static-analysis tools — that needs direct access to the mdast syntax tree rather than a full compile-to-JSX pipeline.
What You Get
mdxFromMarkdown()— a ready-to-use array ofmdast-util-from-markdownextensions covering ESM, JSX, and expressions in one callmdxToMarkdown(options?)— a singlemdast-util-to-markdownextension that serializes those same node types back to MDX text- New mdast node types (
mdxjsEsm,mdxJsxFlowElement,mdxJsxTextElement,mdxFlowExpression,mdxTextExpression) registered against@types/mdastfor full TypeScript coverage - Serialization options (
quote,quoteSmart,tightSelfClosing,printWidth) for controlling how JSX attributes are printed back to markdown - ESTree
Programnodes attached underdata.estreeon ESM and expression nodes when combined withmicromark-extension-mdxjs’saddResultoption
Common Use Cases
- Building a custom remark/mdast plugin that needs to inspect or transform MDX-specific nodes (JSX, imports, expressions) in a syntax tree
- Writing a linter or formatter for
.mdxfiles that operates on the parsed tree rather than raw text - Implementing an alternative or extended MDX compiler that reuses the standard mdast node shapes instead of inventing new ones
- Round-tripping MDX documents — parse to a tree, programmatically edit nodes, and serialize back to valid MDX — for codemods or content migrations
Under The Hood
Architecture
The package is a thin facade: index.js re-exports two functions from a single ~50-line lib/index.js, which itself does no parsing or serialization of its own. mdxFromMarkdown() returns an array combining the mdast-util-from-markdown extensions of three sibling syntax-tree packages (mdast-util-mdx-expression, mdast-util-mdx-jsx, mdast-util-mdxjs-esm); mdxToMarkdown(options) returns one aggregated mdast-util-to-markdown extension, forwarding its options argument only to the JSX extension since that’s the only one with serialization knobs. There is no internal state, no classes, and no business logic beyond composition — if the shared extension contract from mdast-util-from-markdown/mdast-util-to-markdown changes, this package breaks immediately since it holds nothing of its own to buffer that change.
Tech Stack
A pure ESM-only Node.js/browser library ("type": "module", single ./index.js export, consumable via esm.sh in Deno and browsers). Types are authored as hand-written .d.ts re-exports layered over JSDoc-typed source, compiled with tsc --build in declaration-only mode under a strict tsconfig.json (strict, exactOptionalPropertyTypes, node16 module resolution) and checked with type-coverage for full type coverage. All five runtime dependencies are sibling mdast-util-* packages from the same org; there is no bundler, no framework, and no external service integration — it’s a dependency-thin composition layer.
Code Quality
Tests run entirely on Node’s built-in node:test and node:assert/strict (no external test framework), asserting deep equality against full ESTree-plus-mdast JSON trees for both parsing and serialization paths; c8 enforces 100% coverage as part of npm test, and type-coverage separately enforces 100% type coverage as part of the build. Linting and formatting are unified through xo (an opinionated ESLint preset with Prettier integration) plus remark-preset-wooorm for consistent README/doc formatting, all wired into GitHub Actions CI across two Node versions. There’s little explicit error handling in the source itself, which is consistent with its role as a stateless composition layer rather than a gap in defensive coding.
API Design
The public surface is exactly two functions, named and shaped identically to every other mdast-util-*-from-markdown/-to-markdown extension in the ecosystem, so anyone who has used one sibling package already knows this one. Getting started requires no configuration for the common case — pass the from-markdown extensions and the to-markdown extension straight into fromMarkdown/toMarkdown alongside a micromark MDX syntax extension — with a single optional options object exposed only for advanced JSX serialization control. The package also re-exports every new node’s TypeScript type so consumers get tree-node autocomplete simply by referencing the package once in their types, exactly as the README documents.
Used by 2 apps in this directory
Fern
Developer Tools
Fern turns a single OpenAPI, AsyncAPI, or Protobuf definition into type-safe SDKs for nine languages and a hosted API documentation site, all from one CLI and one source of truth.
Supabase
Developer Tools · Databases · Search
The open-source Postgres development platform that replaces Firebase with authentication, real-time APIs, edge functions, storage, and vector embeddings — all built on PostgreSQL.