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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ashusevim/markdown-processor

v2.3.0

Published

marcus — a zero-dependency Markdown to HTML CLI and library that verifies its own output: safe-by-default escaping, line-numbered diagnostics for CI, and LLM-artifact repair

Readme

Markdown Processor (marcus)

A zero-dependency Markdown → HTML CLI and library for Node.js — the converter that verifies its own output.

marcus: escaping untrusted HTML, failing a CI gate on warnings, and repairing LLM artifacts

Pandoc tells you nothing. Marked trusts everything. marcus checks the input, escapes untrusted HTML by default, and reports everything it changes.

Install

npm install -g @ashusevim/markdown-processor   # exposes `marcus`

Requires Node.js >= 20. No runtime dependencies.

Usage

marcus file.md                # HTML on stdout
cat notes.md | marcus         # stdin (implicit with no file argument)
marcus a.md b.md              # multiple files, in order
marcus --strict docs/*.md     # CI gate: exit 1 if warnings are found
marcus --report json doc.md   # machine-readable report instead of HTML
llm | marcus --fix-llm        # repair known LLM artifacts, logging each one

Why marcus

  • Safe by default. Raw HTML from users, scrapers or models is escaped to visible text, so a <script> can't execute. --unsafe passes it through for trusted documents. Most converters do the opposite and leave you to "sanitize it yourself".

  • It tells you the truth. Render-affecting problems come back as line-numbered diagnostics instead of silently wrong HTML:

    marcus: draft.md:4: warning [unclosed-bold]: odd number of '**' — bold segment may be unclosed
  • Repairs LLM slop on the record. --fix-llm fixes the well-documented artifacts and logs every repair as an info issue, so nothing is rewritten behind your back.

  • Tiny and auditable. A few hundred dependency-free lines; the CLI is a thin wrapper around a pure parser you can import.

Options

| Option | Description | |---|---| | -h, --help · -V, --version | help and version | | - · -- | read stdin explicitly · treat the rest as file names | | --strict | exit 1 on warning-level issues (CI gate) | | --report json | JSON report (html, issues, stats) instead of HTML | | -q, --quiet | don't mirror issues to stderr | | --unsafe | pass raw HTML through unescaped (trusted input) | | --fix-llm | repair LLM artifacts before parsing, logging each repair |

Exit codes: 0 success · 1 unreadable file or --strict warnings · 2 usage error.

Diagnostics

Two severities: warning means the output probably doesn't match your intent (and --strict fails on it); info is a repair or unsupported-syntax notice, which never fails a build.

| Code | Problem | |---|---| | unclosed-fence · unclosed-inline-code · unclosed-bold · unclosed-strikethrough | a delimiter is never closed, so everything after it renders wrong | | heading-skip | heading level jumps (e.g. h1 → h4), breaking the outline | | list-interrupted · mixed-list-markers | implicit list boundary, or marker style changed mid-list | | table-ragged | a table row has more cells than the header — the extras are dropped | | frontmatter-unsupported · html-escaped | --- frontmatter (renders as <hr>) · raw HTML neutralized by safe mode | | repaired-* | what --fix-llm changed (heading space, frontmatter fence, proved, table delimiter) |

Reports are deterministic — identical input produces byte-identical output (no timestamps), so they can be cached and diffed:

{
  "tool": "marcus", "version": "2.3.0",
  "files": [{ "file": "doc.md", "html": "…", "words": 5, "headings": [] }],
  "issues": [{ "file": "doc.md", "line": 5, "code": "unclosed-fence", "severity": "warning", "message": "…" }],
  "stats": { "files": 1, "words": 5, "readingTimeMinutes": 1, "warnings": 1, "infos": 0, "repairs": 0 }
}

Library

import { parseMarkdown, parseMarkdownDetail } from "@ashusevim/markdown-processor";

parseMarkdown("# hi");                     // '<h1>hi</h1>'
const { html, issues, headings, words } = parseMarkdownDetail(source, { fixLlm: true });

Syntax

CommonMark-style blocks and GFM extensions: ATX headings, thematic breaks, blockquotes (parsed recursively), ordered/unordered lists nested to any depth, task lists (- [x]), GFM pipe tables with :---/:-:/---: alignment, fenced code with language classes, and inline code (including multi-backtick spans), bold/italic/strikethrough, links, angle autolinks and images. A leading BOM and CRLF/CR line endings are normalized.

Limitations

  • No footnotes or setext headings yet.
  • Frontmatter is not parsed; it renders as a thematic break and is reported as info.
  • Safe mode is escape-all, not an allowlist sanitizer. Pipe --unsafe output through a dedicated sanitizer if you need fine-grained control.
  • Task-list checkboxes are inert (disabled) by design.
  • Lists render tight: a blank line between items doesn't force <p> wrappers, and a blank line inside an item only wraps the paragraphs that follow it.

Development

npm test        # builds, then runs the node:test suite (165 tests)
npm run build   # tsc → dist/

src/parse.ts is the whole parser and diagnostics engine (no I/O, no deps) — that's the library. src/cli.ts is the argument/stdin/exit-code wrapper. docs/demo.sh regenerates the demo GIF:

asciinema rec -q --overwrite --cols 124 --rows 32 -c "bash docs/demo.sh" docs/demo.cast
.tools/agg --font-size 14 --theme monokai docs/demo.cast docs/demo.gif

License

ISC