The Problem Many HTML‑to‑Markdown libraries are generic, heavyweight, and generate output that wastes tokens when fed to LLMs. Teams that need fast, low‑overhead conversion for prompt construction end up writing ad‑hoc parsers or paying the performance penalty of larger converters.
What This Does mdream provides a zero‑dependency, pure‑JS converter tuned for LLM token efficiency. The core lives in packages/mdream/src/index.ts (the hub module, imported by 39 other files) and delegates to a small set of helpers:
packages/mdream/src/parse.ts– tokenises and walks the DOM, producing Markdown.packages/mdream/src/markdown-processor.ts– applies minimal GitHub‑flavoured rules.packages/mdream/src/pluggable/plugin.tsand theplugins/folder – optional extensions (e.g.,plugins/extraction.ts).
A thin CLI (packages/mdream/src/cli.ts) reads from stdin or a file and streams the result, exposed via the executable bin/mdream.mjs. The same core is re‑exported by the top‑level package.json for consumption as a library.
How It Is Wired
bin/mdream.mjs
→ packages/mdream/src/cli.ts
→ packages/mdream/src/index.ts (hub)
→ packages/mdream/src/parse.ts
→ packages/mdream/src/libs/query-selector.ts
→ packages/mdream/src/markdown-processor.ts
→ plugins/* (optional)
→ packages/mdream/src/pluggable/plugin.ts
- Execution starts at
bin/mdream.mjs, which parses CLI args and callsrun()incli.ts. run()importsindex.ts; this module orchestrates conversion by callingparse()(inparse.ts) and then feeding the AST tomarkdownProcessor()(inmarkdown-processor.ts).- If any plugin is registered (via
plugins.ts), the plugin processor (plugin-processor.ts) injects additional node handlers before the final Markdown string is emitted. - The only side‑effects are I/O (reading HTML, writing Markdown) and optional network calls made by plugins (e.g.,
plugins/extraction.ts).
The import graph shows packages/mdream/src/index.ts as the most‑connected hub (Ca = 39, Ce = 6). Four modules form a cycle (types.ts, pluggable/plugin.ts, plugins/extraction.ts, plugins.ts), increasing cognitive load for changes. The largest single file is parse.ts (≈694 LOC), a natural candidate for refactoring into smaller, testable units.
How To Use It
# Clone the repo
git clone https://github.com/moses-y/mdream
cd mdream
# Install dependencies (pnpm is the lockfile manager)
pnpm install
# Run the CLI on a local HTML file
node bin/mdream.mjs < path/to/page.html > page.md
# Or use the library in code
npm install mdream # publishes the core package
For containerised deployment, build the published Docker image:
docker build -t mdream:latest .
docker run --rm -i mdream:latest < page.html > page.md
Real‑World Use A content‑generation pipeline can fetch a rendered article, pipe it through mdream to obtain a compact Markdown prompt, and feed the result directly to an LLM. Example (Node):
import { convert } from 'mdream';
import fetch from 'node-fetch';
async function promptFromUrl(url) {
const html = await (await fetch(url)).text();
const md = await convert(html); // core library call
return md;
}
Code Health & Issues
- High – Import cycles (
packages/mdream/src/types.ts,pluggable/plugin.ts,plugins/extraction.ts). Break the cycle by extracting shared types. - High – Hub module (
packages/mdream/src/index.ts). Stabilise; avoid adding volatile logic here. - High – Oversized files (
parse.ts,test/unit/templates/nav.test.ts,tags.ts). Split into focused modules. - High – Duplicated code in
bench/bundle/*.ts. Consolidate helpers. - High – Deep nesting in
test/unit/templates/nav.test.ts. Refactor with early returns. - Medium – High branching density in
packages/crawl/src/glob-utils.ts,llms-txt.ts,libs/query-selector.ts. Consider strategy tables.
CI / DevOps
- Pin GitHub Action versions to commit SHAs.
- Add a test step to the existing workflows so CI actually runs the 107 test files.
- Declare least‑privilege
permissions:forGITHUB_TOKEN. - Enable Dependabot (
.github/dependabot.yml). - Pin the Docker base image by digest.
- Add a dependency‑vulnerability scan (e.g.,
dependency-review-action). - Set
persist-credentials: falseon checkout steps. - Define
timeout-minuteson all workflow jobs.
The Bottom Line mdream delivers a lightweight, LLM‑aware HTML‑to‑Markdown converter with a clear CLI and library API, but the core module is a high‑impact hub surrounded by import cycles and several large files that raise maintenance risk. Addressing the measured code‑health issues—especially the cycles and oversized modules—will make the package more robust for production use. Teams needing fast, token‑efficient conversion can adopt it now, provided they budget time for the suggested refactors and CI hardening.