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

yume-dsl-markdown-it

v0.1.1

Published

markdown-it plugin that renders yume-dsl rich-text tags via token-walker

Downloads

15

Readme

English | 中文

yume-dsl-markdown-it

npm GitHub CI License: MIT Contributing Security

markdown-it plugin that renders yume-dsl-rich-text tags inside Markdown.

Heads-up: The default tag prefix $$ conflicts with LaTeX math delimiters ($$...$$) used by most markdown-it math plugins. If your Markdown includes math, create the parser with a different prefix — e.g. createEasySyntax({ tagPrefix: "%%" }) — to avoid collisions. See Custom Syntax.

The plugin is pure pipeline glue — it delegates tag grammar to the rich-text parser and rendering to yume-dsl-token-walker. No syntax rules are hard-coded; swap createEasySyntax({ tagPrefix: "%%" }) upstream and the plugin follows.

  • Inline tags ($$tag(...)$$) handled by an inline rule
  • Raw ($$tag(arg)%...%end$$) and block ($$tag(arg)*...*end$$) tags handled by a block rule
  • createText output is automatically HTML-escaped via md.utils.escapeHtml
  • Failed DSL fragments fall back to escaped source text by default (onRenderFailure: "preserve")
  • Optional shouldAttempt fast-path gate to skip parsing at non-DSL positions
  • Silent / non-silent result caching — each position is parsed at most once per parser state
  • Block matching is bounded to the current markdown-it container, so blockquotes / lists do not leak prefixes or closing markers across boundaries

This package is in early development (v0.x). The API may change between minor versions. Once stable, breaking changes will land in major versions with explicit migration notes.


Table of Contents


Ecosystem

text ──▶ yume-dsl-rich-text (parse) ──▶ TextToken[] ──▶ yume-dsl-token-walker (interpret) ──▶ TNode[]
         │                                                        │
         ╰─────────── yume-dsl-markdown-it (glue) ───────────────╯
                                   ↓
                        markdown-it pipeline ──▶ HTML

| Package | Role | |------------------------------------------------------------------------------------|--------------------------------------------------------------| | yume-dsl-rich-text | Parser — text to token tree | | yume-dsl-token-walker | Interpreter — token tree to output nodes | | yume-dsl-shiki-highlight | Syntax highlighting — tokens or TextMate grammar | | yume-dsl-markdown-it | markdown-it plugin — DSL tags inside Markdown (this package) |


Install

npm install yume-dsl-markdown-it markdown-it
# or
pnpm add yume-dsl-markdown-it markdown-it

yume-dsl-token-walker and yume-dsl-rich-text are dependencies and will be installed automatically. markdown-it is a peer dependency — bring your own version (>=14).


Quick Start

import MarkdownIt from "markdown-it";
import {createParser, createSimpleInlineHandlers} from "yume-dsl-rich-text";
import type {InterpretRuleset} from "yume-dsl-token-walker";
import {yumePlugin} from "yume-dsl-markdown-it";

const parser = createParser({
    handlers: createSimpleInlineHandlers(["bold", "italic"]),
});

const ruleset: InterpretRuleset<string> = {
    createText: (text) => text,
    interpret: (token, helpers) => {
        if (token.type === "bold")
            return {type: "nodes", nodes: ["<strong>", ...helpers.interpretChildren(token.value), "</strong>"]};
        if (token.type === "italic")
            return {type: "nodes", nodes: ["<em>", ...helpers.interpretChildren(token.value), "</em>"]};
        return {type: "unhandled"};
    },
    onUnhandled: "flatten",
};

const md = new MarkdownIt().use(yumePlugin, {parser, ruleset, env: undefined});

md.render("# Hello $$bold(world)$$");
// → <h1>Hello <strong>world</strong></h1>

Options

interface YumePluginOptions<TEnv = undefined> {
    /** yume-dsl-rich-text parser instance */
    parser: Parser;

    /** token-walker ruleset whose string nodes represent HTML fragments */
    ruleset: InterpretRuleset<string, TEnv>;

    /** environment value forwarded to every interpret call */
    env: TEnv;

    /** optional fast-path gate before delegating to the parser */
    shouldAttempt?: (src: string, pos: number) => boolean;

    /** render contract for parse / interpret failures after a DSL match is confirmed */
    onRenderFailure?: "preserve" | "throw" | ((context: RenderFailureContext<TEnv>) => string);
}

shouldAttempt

Called at every character position before the parser runs. Return false to skip parsing entirely at that position. Useful when you know your DSL always starts with a fixed prefix:

md.use(yumePlugin, {
    parser,
    ruleset,
    env: undefined,
    shouldAttempt: (src, pos) => src.charCodeAt(pos) === 0x24 && src.charCodeAt(pos + 1) === 0x24,
});

onRenderFailure

Controls what happens when a DSL tag is structurally matched but interpretTokens throws:

| Value | Behavior | |--------------|--------------------------------------------------------------| | "preserve" | Emit the original source text, HTML-escaped | | "throw" | Re-throw the error | | function | Call with { error, source, env, form }, return HTML string |

Default: "preserve".


Tag Forms

The plugin recognizes all three yume-dsl tag forms:

| Form | Syntax | Rule | Example | |--------|------------------------------|--------|-----------------------------------| | Inline | $$tag(content)$$ | Inline | $$bold(hello)$$ | | Raw | $$tag(arg)% content %end$$ | Block | $$code(ts)% const x = 1; %end$$ | | Block | $$tag(arg)* content *end$$ | Block | $$collapse(note)* ... *end$$ |

Inline tags live inside paragraphs, headings, list items, etc. Raw and block tags are block-level — they stand alone between paragraphs. When used inside blockquotes or list items, block/raw matching stays inside that container.


Custom Syntax

The plugin does not hard-code any delimiter. If you create a parser with custom syntax, the plugin follows automatically:

import {createEasySyntax, createParser, createSimpleInlineHandlers} from "yume-dsl-rich-text";

const parser = createParser({
    syntax: createEasySyntax({tagPrefix: "%%"}),
    handlers: createSimpleInlineHandlers(["bold"]),
});

const md = new MarkdownIt().use(yumePlugin, {parser, ruleset, env: undefined});

md.render("%%bold(hello)%%");
// → <p><strong>hello</strong></p>

For full syntax customization details, see the yume-dsl-rich-text documentation.


Error Handling

  • Structural match but render failure: controlled by onRenderFailure (default: "preserve")
  • No structural match: the text passes through to markdown-it as-is — no error
  • Parser exception during structural scan: silently skipped (returns false to markdown-it)
  • Inline matches inside link labels / other silent scans: consume input correctly and do not break markdown-it

The plugin never throws by default. Set onRenderFailure: "throw" to surface errors during development.


Safety

  • createText output is wrapped with md.utils.escapeHtml — plain text nodes are always escaped
  • Failed fragments are escaped before emitting when onRenderFailure is "preserve"
  • The plugin does not inject raw HTML from user input unless your ruleset.interpret explicitly returns it
  • ruleset.createText should return un-escaped plain text; the plugin handles escaping

Changelog

See CHANGELOG.md.

License

MIT © 星野夢華