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

mdbook-nodejs-preprocessor-builder

v0.0.2

Published

> A framework for building [mdBook](https://github.com/rust-lang/mdBook) preprocessors with NodeJS. Supports MdBook 0.3.x

Readme

mdbook-nodejs-preprocessor-builder

A framework for building mdBook preprocessors with NodeJS. Supports MdBook 0.3.x

mdbook-nodejs-preprocessor-builder enables you to easily build macros and dynamically generated content into mdBook projects. Easily build macros, text replacement, table generation, or even dynamic content from the flexibility and comfort of NodeJS.

What, Why, and How

MdBook has the concept of a Preprocessor, which can transform markdown after it's been read by MdBook but before it reaches the final Renderer. Preprocessors enable users to add advanced functionality without having to modify the MdBook source or rely solely on client-side JavaScript. At its simplest, a Preprocessor can replace any input text into any output text. For example, a username replacer preprocessor could replace all instances of {{#username}} with Bob.

As MdBook is written in Rust, Rust-based preprocessors are well supported with full interfaces and examples. One can relatively easy create a new preprocessor in Rust, but there are many other languages one might use with their own advantages and disadvantages. MdBook's preprocessor feature supports executing preprocessors in a separate process, leading to the ability to implement them in any way shape and form the user likes.

The mdbook-nodejs-preproessor-builder, as its name implies, is a framework for easily implementing said preprocessors using NodeJS. It abstracts away all the details of integrating with MdBook, message passing, and serializing/deserializing data. It also includes support for common macro patterns, enabling preprocessors to be easily implemented in TypeScript or JavaScript.

Handler Types

This builder comes with out-of-the-box support for three distinct types of handlers: Raw, RegExp, and KeyValue. Each one includes a increasing level of built-in macro processing: Raw supplies the full content for generic processing by the handler, RegExp allows you to supply your own custom Regular Expression for macro matching, and KeyValue makes it easy to add structured macros with well-defined key-value attributes.

Ordering of handlers

Be aware that a preprocessor can contain any number of handlers, with any number of types. They are always executed as follows:

  1. Raw handlers, in the order of assignment to the builder.
  2. RegExp handlers, in the order of assignment to the builder.
  3. KeyValue handlers, in the order of assignment to the builder.

This means that if you attach RawA, RegExpA, KeyValueA, KeyValueB, RegExpB, RawB, the order of execution will be RawA, RawB, RegExpA, RegExpB, KeyValueA, KeyValueB.

Raw

Raw handlers are the most generic type of handler -- each chapter is passed in blindly for processing, and each handler can modify the Chapter as it wishes. Unlike the other handlers, there is no parsing or processing of the content whatsoever. It is solely the responsibility of the handler.

Note: There is no need to modify sub_items in each Chapter -- the handler will be called for each and every Chapter, including sub_items.

import {MdBookProcessorBuilder} from "mdbook-nodejs-preprocessor-builder";

MdBookPreprocessorBuilder.builder()
    .withRendererSupport("html")
    .withRawContentHandler((inputChapter: Chapter) => {
        chapter.content = chapter.content.replace("Kirk", "Picard");
        return chapter;
    })
    .ready();

RegExp

RegExp handlers include integrated support for RegExp parsing and replacement of content, without the user needing to add their own boilerplate. Unlike raw handlers above, this requires the user to return the replacement string. The full Chapter is still included for reference, as well as if the Handler would like to modify it (not recommended). Do not modify chapter.content, as it will be overridden once all handlers have been evaluated.

In the following example, all instances of any string matching the RegExp of {{RankMacro (\S*) (\S*)}} will be matched and entirely replaced.

import {MdBookProcessorBuilder} from "mdbook-nodejs-preprocessor-builder";

MdBookPreprocessorBuilder.builder()
    .withRendererSupport("html")
    .withRegExpHandler(/{{RankMacro (\S*) (\S*)}}/g, (inputChapter: Chapter, fullyMatchedString: string, firstName: string, lastName: string) => {
        // fullyMatchedString: "{{#RankMacro Jean-Luc Picard}}"
        if(firstName === "Jean-Luc" && lastName === "Picard") {
            return "Captain Jean-Luc Picard";
        }

        return `${firstName} ${lastName}`;
    })
    .ready();

KeyValue

KeyValue handlers include integrated support for parsing macros in a common form: {{#macroName key=value boolKey}}. This is the easiest way to get started with your own macro.

Names

KeyValue handlers only need a name to get started. This name is used to find any and all macros with the format: {{#macroName}}. So, if your name is Ship, the matched macro would be of the form {{#Ship}}. The handler will only be executed for strings matching that structure, regardless of whether or not there are any attributes given.

Attributes

Attributes are anything after the name of the macro (plus a space), and before the closing curly-braces. All attributes are expected to be in the format used by node-logfmt -- these are very simple key-value pairs, with boolean values optionally requiring an explicit value. Strings may be wrapped in quotes, double quotes, or none at all if they don't contain whitespace. Numbers and boolean values are likewise parsed.

Attributes passed into handlers are directly parsed from the raw macro string. For full documentation of the schema, see node-logfmt.

For example, the following are equivalent:

  • {{#Ship name="Enterprise" registryNumber=1701 active=true}}
  • {{#Ship name=Enterprise registryNumber=1701 active}}
import {MdBookProcessorBuilder} from "mdbook-nodejs-preprocessor-builder";

MdBookPreprocessorBuilder.builder()
    .withRendererSupport("html")
    .withKeyValueHandler("Ship", (inputChapter: Chapter, matches: { name: string; registryNumber: number, active: boolean }) => {
        // fullyMatchedString: "{{#Ship name="Enterprise" registryNumber=1701 active}}"
        // Replaces it with: "USS Enterprise, NCC-1701, currently active"
        return `USS ${matches.name}, NCC-${matches.registryNumber},  currently ${matches.active ? "active" : "inactive"}`;
    })
    .ready();

Creating a Preprocessor

  1. Create a new NodeJS package.
  2. Install mdbook-nodejs-preprocessor
  3. Create a TS or JS file that can be executed on the CLI. TypeScript definitions are included for your convenience.
  4. Create an instance of MdBookPreprocessorBuilder and declare one or more renderer types. These should match those in your book.toml file.
  5. Attach one or more content replacement handlers, either via KeyValue, RawContent, or RegExp.
  6. Call .ready(), optionally waiting for the promise to resolve.

Adding the Preprocessor

This is the easy part -- just add a toml table in the format of [preprocessor.*] and with command and renderer keys. The renderer types must match those declared in your preprocessor.

[preprocessor.example]
command = "node where/your/preprocessor-is.js"
renderer = ["html"]