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

@farhnkrnapratma/markers

v1.0.0-alpha1

Published

High-performance HTML to Markdown converter with full GFM support

Readme

markers

High-performance HTML to Markdown conversion for LLMs, written in Rust.

Status

Alpha (v1.0.0-alpha1). The API can still change before the first stable release.

| Registry | Name | | --- | --- | | crates.io | markers | | npm | @farhnkrnapratma/markers |

One package, one src/. The bindings are optional Cargo features:

| Feature | Source | Purpose | | --- | --- | --- | | (none) | src/lib.rs | Rust library | | napi | src/bindings/node.rs | Node.js / Bun bindings, published as @farhnkrnapratma/markers | | wasm | src/bindings/wasm.rs | WebAssembly bindings |

Install

cargo add markers                       # Rust
bun add @farhnkrnapratma/markers        # Node.js / Bun (or: npm install @farhnkrnapratma/markers)

The npm package ships prebuilt binaries for Linux (x64 and arm64, glibc and musl), macOS (x64 and arm64) and Windows (x64 and arm64) as optional dependencies, so nothing is compiled on install.

Usage

Rust:

fn main() -> Result<(), String> {
    let _markdown = markers::convert("<h1>Hello</h1>");

    let options = markers::ConversionOptions::new()
        .heading_style(markers::HeadingStyle::Setext)
        .base_url(Some("https://example.com".to_string()))
        .exclude_selectors(vec!["nav".to_string()]);
    let markdown = markers::convert_with_options("<h1>Hello</h1>", &options)?;
    println!("{markdown}");
    Ok(())
}

convert_with_options returns an error when an include or exclude CSS selector is invalid.

Node.js / Bun:

const { convert, convertAsync } = require('@farhnkrnapratma/markers')

convert('<h1>Hello</h1>')
convert('<h1>Hello</h1>', { headingStyle: 'setext', baseUrl: 'https://example.com' })
await convertAsync('<h1>Hello</h1>')

Options

| Option (Rust / JS) | Values | Default | | --- | --- | --- | | heading_style / headingStyle | atx, setext | atx | | link_style / linkStyle | inline, referenced | inline | | code_fence / codeFence | `, ~ | ` | | bullet_marker / bulletMarker | -, *, + | - | | base_url / baseUrl | URL used to resolve relative links and images | none | | exclude_selectors / excludeSelectors | CSS selectors to drop | none | | include_selectors / includeSelectors | CSS selectors kept even if an exclude selector matches | none |

Repository layout

src/
  lib.rs        public API: convert, convert_with_options, ConversionOptions
  options.rs    ConversionOptions, HeadingStyle, LinkStyle
  pipeline/     the conversion: input_guard -> parse -> annotate -> render -> cleanup
  handlers/     one TagHandler per group of tags (block/ and inline/)
  text/         Markdown escaping, URL handling, whitespace
  bindings/     Node.js (napi) and WebAssembly (wasm) glue
tests/          integration tests and HTML fixtures
examples/       Rust, Node.js and browser demos

Development

Requirements: Rust (stable) and Cargo, and Bun for the JavaScript side (bun.lock is the only lockfile).

bun install                  # JS dependencies and git hooks
bun run build                # Node.js / Bun binding for this platform
cargo test --features napi   # unit and integration tests, plus the napi module
bun run test                 # Node.js binding tests (after bun run build)
cargo clippy --all-targets --features napi
cargo bench --bench conversion   # set MARKERS_BENCH_ITERATIONS to change the run length

Examples:

cargo run --example basic     # default options
cargo run --example options   # headings, bullets, links, selectors
bun examples/node.js          # Node.js / Bun (after bun run build)

examples/wasm.html is a browser demo for the wasm build, which needs the wasm32-unknown-unknown target (napi is compiled out on wasm32, so --all-features also works there):

cargo check --target wasm32-unknown-unknown --features wasm

Releases are cut with git-flow (git-flow release start/finish). Pushing a v* tag makes CircleCI build the bindings for every platform and publish them to npm; the crate is published with cargo publish.

Contributing

This repository uses git-flow-next (classic preset): main is release-only, work happens on feature/* and bugfix/* branches off develop. Commits are signed off (git commit -s) and follow Conventional Commits, enforced by commitlint in a commit-msg hook and in CI. Install the hooks with bash .githooks/install.sh (bun install does it through the prepare script). CI runs on CircleCI: reuse lint, format and lint, tests, cargo deny, a TruffleHog secret scan and commitlint on every push. The branch rules are written out in CLAUDE.md.

License

Licensed under either of

at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Copyright © 2026 Farhan Kurnia Pratama