mdast-util-math

mdast extension to parse and serialize LaTeX-style math syntax embedded in markdown syntax trees.

Library
npm
v3.0.0
21 stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
26 /100 Needs Attention
Development Activity 0
Maintenance 20
Community 12
Maturity 60
Momentum 12

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
69 /100 Good
Architecture 85
Code Quality 92
Innovation 55
Learning Curve 45

mdast-util-math adds math nodes to mdast, the syntax tree format used throughout the unified/remark ecosystem. It plugs into mdast-util-from-markdown and mdast-util-to-markdown to parse LaTeX-style math delimited by single or double dollar signs into inlineMath and math nodes, and to serialize those nodes back into markdown text without losing literal dollar signs inside the math content.

The package is maintained by the syntax-tree collective and works alongside micromark-extension-math for tokenizing and mdast-util-to-hast for turning math nodes into HTML code/pre elements with math-inline/math-display classes, forming the plumbing that higher-level packages like remark-math build on top of.

What You Get

  • mathFromMarkdown() extension that turns micromark math tokens into inlineMath and math mdast nodes
  • mathToMarkdown() extension that serializes those nodes back into $…$ and $$…$$ markdown, escaping dollar runs safely
  • TypeScript types for Math, InlineMath and ToOptions, registered against @types/mdast via declaration merging
  • Automatic hast field annotations (hName/hChildren) so mdast-util-to-hast renders math as <code class=“language-math”> elements with no extra configuration

Common Use Cases

  • Adding LaTeX math support to a remark-based markdown pipeline via remark-math
  • Building a custom static site generator that needs to parse and round-trip math notation in markdown
  • Writing tooling that visits or transforms math nodes in a markdown AST, e.g. rendering with KaTeX or MathJax

Under The Hood

Architecture The package has a two-function design split across index.js and lib/index.js: mathFromMarkdown builds a from-markdown extension using enter/exit handler maps keyed to micromark token names (mathFlow, mathFlowFenceMeta, mathText, mathFlowValue, mathTextData), pushing mdast math/inlineMath nodes onto the CompileContext stack and attaching hast-facing data (hName/hChildren) directly at enter time so mdast-util-to-hast needs no separate mapping step. mathToMarkdown mirrors this with a handlers map (math, inlineMath) plus an unsafe-pattern list telling mdast-util-to-markdown’s serializer safety layer which characters need escaping in phrasing versus mathFlowMeta constructs, and computes a dynamic fence length via longestStreak to avoid clashing with dollar runs already present in the value being serialized. The only internal state is a CompileContext.data.mathFlowInside flag distinguishing the opening from the closing fence token. index.d.ts holds all type declarations plus module-augmentation blocks that register the new node types into mdast’s BlockContentMap/PhrasingContentMap and mdast-util-to-markdown’s ConstructNameMap, so the real “core abstraction” here is the extension-object contract defined by the sibling from-markdown/to-markdown libraries — if that contract changed, this package’s enter/exit/handlers shape would need to change in lockstep.

Tech Stack Plain JavaScript (100%), shipped ESM-only (type: module, single exports entry). Runtime dependencies are devlop (dev-only assert helper for invariants), longest-streak (safe fence-length computation), mdast-util-from-markdown and mdast-util-to-markdown (the sibling libraries this plugs into), unist-util-remove-position, and type-only @types/hast/@types/mdast. Dev tooling generates declarations from JSDoc via TypeScript’s checkJs + emitDeclarationOnly rather than hand-written .ts, enforces full type coverage with type-coverage, lints/formats with xo and prettier via remark-preset-wooorm, and tests with Node’s built-in test runner plus c8 for coverage. GitHub Actions runs the suite across a Node version matrix and uploads coverage to Codecov; there is no bundler or build step beyond type-declaration emission since the package ships plain JS.

Code Quality Testing uses Node’s native node:test/node:assert/strict runner in a single ~480-line test.js, organized into three top-level test() blocks (core, mathFromMarkdown, mathToMarkdown) with async sub-cases asserting exact deepEqual trees for parse cases and exact string output for serialize cases. Coverage is enforced at 100% via c8 and type coverage at 100% via type-coverage, both gating the test script in CI. Error handling relies on devlop’s assert() invariant helper, which is stripped from production builds via the development/production conditional exports, appropriate for a small structural utility with no user-facing failure modes. Style is enforced by the strict xo ESLint preset and prettier, run as part of the same test pipeline. Naming conventions mirror sibling syntax-tree/unified extension packages closely and consistently.

What Makes It Unique This package doesn’t introduce new math-rendering technology — it implements the same extension contract used by other unified/remark syntax extensions (gfm, frontmatter, etc.), mirroring their structure closely. Its one genuinely careful design choice is the dynamic delimiter-length algorithm in mathToMarkdown, which uses longestStreak to pick a fence at least one dollar sign longer than any run already present in the raw value, plus an escalating-width loop for inline math, guaranteeing lossless round-tripping of math content that itself contains literal dollar signs — an edge case naive implementations tend to skip. Beyond that, it follows standard, well-established plugin architecture for the ecosystem it belongs to.

Used by 5 apps in this directory

TypeScript
96%
MIT

deepseek-harness

AI Agents · AI Development · Developer Tools

237,945

An open-source, plugin-based agent harness from DeepSeek AI that runs coding and automation agents across web, desktop, CLI, and SDK surfaces.

View details
81
Repo Health
89
Technical
74
Dependency
Built with
TypeScript 96%
Updated 5 days ago
TypeScript
75%
Apache 2.0

Fern

Developer Tools

3,787

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.

View details
90
Repo Health
86
Technical
66
Dependency
Built with
TypeScript 75%
Updated 4 days ago
TypeScript
82%
MIT

LibreChat

AI Assistants · Developer Tools

45,009

Unite every major AI model in one self-hosted chat platform with agents, code execution, MCP tools, and enterprise authentication.

View details
93
Repo Health
81
Technical
65
Dependency
Built with
TypeScript 82%
JavaScript 17%
Updated 4 days ago
TypeScript
97%
GPL 3.0

OpenKnowledge

Code Editors · Knowledge Management · Note Taking

4,337

A beautiful, local-first markdown IDE that turns any git repo into a live collaborative workspace for humans and AI coding agents like Claude, Codex, and OpenCode.

View details
79
Repo Health
89
Technical
64
Dependency
Built with
TypeScript 97%
Updated 4 days ago
Python
73%
Apache 2.0

Unsloth

AI Assistants · AI Development

76,886

Run and fine-tune LLMs, diffusion, audio and embedding models on your own hardware, from a native desktop app, a browser UI, or a Python library.

View details
89
Repo Health
83
Technical
70
Dependency
Built with
Python 73%
TypeScript 21%
Updated 4 days ago

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers