Markdown Run Book
Turn your Markdown documentation into executable runbooks.
Features
- 🦕 Built with and runs on Deno
- 🌀 Blend documentation with code execution; bring your
README.md
developer setup to life without losing the narrative format - ✅ Execute
TypeScript
andJavaScript
fenced code blocks as a multi-step “runbook” - ✨ Automatic availability of dsherret/dax within code blocks to simplify cross-platform shell execution
- ⬇ Works with local and remote Markdown files and even Markdown content piped to
stdin
Motivation and How it Works
How many times have you had to follow along with a set of steps in a README.md
in order to setup your development
environment to work on a project? Copy-and-Paste-ing from the README
to your terminal back and forth, hoping you do
each step correctly and don’t miss something gets old; wouldn’t it be nice if you could just execute the code in that
README
? Well, that’s what mdrb
allows you to do!
When provided a Markdown file (or a remote URL that points to one, or pipe the content of one through stdin
) to
mdrb
, it does the following:
- Extract all of the fenced code blocks which are annotated with a valid
TypeScript
orJavaScript
language code (typescript
,ts
,javascript
, andjs
) - Pull out the code from each and do a bit of processing to allow it to work seamlessly with
Deno
- for example, references to
import.meta.url
need to be rewritten with the litteral value of the source Markdown file
- for example, references to
- (optionally, but by default) add an import of the bundled version of dax to the code
that will be executed
- From the
dax
module the$
object is exposed automatically to your code blocks, allowing them to transparently reference the functions and features (of which there are many) of$
- most important of which is the execution of cross-platform shell commands.
- From the
- Execute the code blocks according to the chosen mode; by default the “
runbook
” mode is used, which treats each code block as an isolated script and execution is paused awaiting your confirmation before going on.- “
isolated
” mode is the same as “runbook
” mode, except that there is no pause to prompt between each code block. This is the mode used instead ofrunbook
for all piped content due to the absence of atty
. - “
single
” mode concatenates your code blocks together as if they were all a single script and executes the resulting single block. In this mode, your code blocks can depend on each other, but be careful about things like re-declaring variables across code blocks - at runtime, they aren’t isolated from each other!
- “
Installation
deno install -Arfn mdrb https://deno.land/x/mdrb/mod.ts
Note: if you prefer not to bake
--allow-all
permissions (with the-A
flag) into the installed command, you can specify alternate permissions, e.g.deno install --allow-net -rfn mdrb https://deno.land/x/mdrb/mod.ts
but be aware that this means you will be prompted for permissions at runtime.
Demos
Local Markdown
Within the source repository for
mdrb
, executemdrb
on the local demo.md file. This results in executing the 3 included (ts/js
) code blocks as a “runbook”, pausing execution after each step awaiting user confirmation to proceed.
Remote Markdown
Just like when we referenced the local
demo.md
file, we can also just reference the demo Markdown by a URL.
🧪 Try it yourself with:
mdrb https://deno.land/x/mdrb/demo.md
Note that in this demo, we used “
isolated
” mode instead of the default “runbook
” mode which omits the pauses for confirmation between code blocks
Piped Markdown
We can also pipe the Markdown content to
mdrb
Note that for this demo, even though we didn’t manually specify “
isolated
” mode,mdrb
used it instead of the normal default of “runbook
” mode because the prompts will fail if we don’t have atty
dax
Using There are a ton of useful things you can do with
dax
, so here’s a little showcase of some of what you can do with the automatically added$
object.
dax
addition
Skipping automatic If you don’t want
dax
to be automatically added to your code blocks, you can pass the--dax=false
option
Step Configuration
It is possible to (optionally) configure your code blocks using an HTML <details data-mdrb>
element which comes
immediately before your code blocks. Each ts / js
fenced code block can have its own configuration (though one is not
required). The contents of your code block configuration can change aspects of how mdrb
will execute.
By providing configuration within a preceding <details data-mdrb>
element, most places where Markdown is rendered will
display the configuration information natively as a collapsed dropdown.
The configuration syntax supports two features within a <details data-mdrb>
element:
- a value which specifies a “step name / title”, and this is provided as the
<summary>
element directly inside of the<details data-mdrb>
. - a value which is TOML formatted configuration placed inside of a
<pre>
element below the<summary>
element.Warning the
<pre>
must have a newline before it (a blank line between the<summary>
and the<pre>
) and its content must not be indented (otherwise the Markdown parser will classify the content as an “indented code block” which is another feature of Markdown)
If you include the <details data-mdrb>
element for step configuration (again, it’s optional), you may specify within
it both a <summary>
and a <pre>
, only a <summary>
, only a <pre>
, or neither. Basically, everything about this
step configuration is optional and mdrb
will use default values in the absence of user-provided configuration
overrides.
Important Notes About Configuration
Here is an example of a valid, and configured, step:
> ... preceding Markdown content
<details data-mdrb>
<summary>Log a diagnostic message</summary>
</details>
```ts
console.log("hello from this configured step!");
```
> ... the rest of the Markdown
Please note the following:
- The
<details>
element has an attribute ofdata-mdrb
, which is required to signal tomdrb
that this<details>
is meant to configure a code block - The
<summary>
element is nested inside of the<details data-mdrb>
element
With this configuration in place, when executed this Markdown will show (with the first line dimmed in your terminal):
step 1 of 1 // Log a diagnostic message
hello from this configured step!
Here is an example of a step with a “full” configuration:
> ... preceding Markdown content
<details data-mdrb>
<summary>Log a diagnostic message</summary>
<pre>
description = '''
# important step
> I can have blockquotes!
basic demonstration of the fact that
you can log to the console with code
blocks.
'''
</pre>
</details>
```ts
console.log("hello from this configured step!");
```
> ... the rest of the Markdown
In this example notice the following:
- The
<pre>
has a blank line before it separating it from the<summary>
- The text content of the
<pre>
is not indented at all and is validTOML
- This example has a single key-value pair, showing the ability to use multiline
TOML
strings as well as the fact that thedescription
key can contain Markdown content
Today, the only key from the <pre>
which may be used when specified is the description
. This key can have either a
single-line value or a multi-line value, and further, the value can contain Markdown which will be beautifully rendered
in the terminal when you use “runbook
” mode or when you use “isolated
” mode with the --isolated-desc=true
flag.
Beyond the description
key, no other configuration values are used, even if they are well defined according to these
rules, however in the future, there may be additions to the way you can configure mdrb
execution exposed through these
configuration values.
Some possible examples of things which may be included are:
- Skip the automatic addition of
dax
for a given code block - Conditionally skip a code block entirely (say, for instance, if you were on Windows or Mac but not on Linux)
- Your ideas? Make an issue or PR and it will be considered
Prior Art
- https://github.com/jacobdeichert/mask
- https://github.com/c4spar/deno-dzx
- https://github.com/google/zx
License
MIT. Copyright (c) Andrew Brey