Skip to content

lzilioli/md-macros

Repository files navigation

md-macros

Extensible macro processing framework for markdown, written in TypeScript.

Node.js CI

Table of Contents

Breaking changes in v7.0.0

In order to call a macro, you must now precede the text with macro:. e.g. \\[[youtube url="url"]] must now be written as \\[[macro:youtube url="url"]].

This is so that we can add support for parsing of wiki-style linking in the future, and so that the macro system does not collide with common markdown applications, which use wiki-style linking.

Overview

There have been lots of requests and proposals over the years for an official spec for a rich and extensible version of markdown. People want to be able to write clean and succinct text in their markdown files, and have it rendered into complex html components, without the need for inline html in their markdown files.

To John Gruber's (the creator of Markdown) credit, he designed Markdown to be lightweight, and he has stuck to his original spec. It is unlikely we will see an overhaul to the markdown specification that would bring features like macros or more rich rendering capabilities to the markdown language itself.

The best thing about markdown is that it's plain text. It is easy to pre- or post- process any markdown text without interfering with other steps of the text processing pipeline. This is how mdmacros works. Technically, this module can work on any text, not just markdown.

Sample Use Case

If you want to embed a YouTube video in a markdown document without mdmacros, you'd do this:

This is my regular markdown document. If I wanted to include
a youtube video embed, this is what I would do today:

<iframe width="560" height="315" src="<youtube-embed-url>"
    frameborder="0" allowfullscreen></iframe>

This is not ideal for two reasons:

  1. This can get hairy for complex markup
  2. Your content creators shouldnt have to know html to create rich, interactive content.

md-macros lets you define your own macros that enable you to simplify the same file to this:

This is my super clean markdown document thanks to md-macros!
This is all I need to type in order to include a video.
[[macro:youtube url="<youtube-embed-url>"]]

A clear improvement.

Usage

mdmacros is available as a cli or a nodejs module.

cli

You can run the bundled macros against any markdown file with:

mdmacros README.tmpl.md README.md

Out of the box you can use this to insert a table of contents section into your readme, by including a call to the mdToc macro, or to inline a file with a call to the inlineFile macro (both are documented below).

nodejs

Typedefs

[[inlineFile path="./lib/typedefs.ts"]]

Methods

replaceMacrosInMd

async function replaceMacrosInMd(
	md: string,
	macros: {[key: string]: MacroMethod},
	skipMacroNamePatterns: string[] = []
): Promise<string>`

This method is where all of the magic happens.

Usage
[[inlineFile path="examples/replace-macros-in-md-usage.ts"]]

parseMacrosFromMd

function parseMacrosFromMd(md: string): ParsedMacros

Usage
[[inlineFile path="examples/parse-macros-from-md-usage.ts"]]
[[inlineFile path="tests/expected-parsed-macros.ts"]]

Bundled macros

This package is intended to aid in the markdown processing pipeline by introducing the concept of macros. To that end, it doesn't provide many macros for consumption.

youtube

This macros is utilized in the above examples.

args

url: the embed url for the YouTube video

mdToc

This macro takes no arguments, and replaces the macro call with the table of contents for the file.

inlineFile

Inlines the contents of a file into the markdown document. Used within this readme for the Typedefs section.

args

path: path to the file to inline

Custom macros

You can easily write your own macro methods. Be sure to specify all macros that you call in your text in the macros argument to replaceMacrosInMd when you call it.

Macros are simple functions that take two arguments, and return a Promise for a string (refer to the MacroMethod typedef above.

The arguments passed to the method are as follows:

  1. args object. This is a map containing whatever was passed to the macro in the markdown text. Each macro defines what goes in the args object that is passed to itself. The macro should take care to validate that it was passed the proper arguments, and throw if not.
  2. mdText: string. The text for the original markdown document with no replacements having been made. This is useful for macros such as the mdToc macro, which needs the full document in order to generate and return a table of contents.

An example will help illustrate:

[[inlineFile path="examples/creating-macros-usage.ts"]]