Check your docs
md-check
md-check ¶
Compile and execute your markdown documentation.
Why?
- Your docs have drifted out of sync with your codebase.
- Your docs are incomplete or wrong and won’t compile.
- Your users will thank you.
What?
Essentially this is like and borrows a lot from storybook and MDX. But isn’t focused on UI components.
- Extract fences from your markdown.
- Compile individual blocks if necessary.
- Execute each block and optionally capture output.
This verifies that
- Your code at the very least is valid.
- Your code is complete including imports because each block compiles and executes by itself. No more crawling the web for what was actually imported for that random snippet that was missing pieces.
- You code executes without an error. You could even execute tests in you code block. Part of the inspiration for this was Mocha’s doc and markdown reporters.
Install ¶
# Run node and other commands
npm install --save-dev @btilford/md-check
# To compile typescript code blocks
npm install --save-dev @btilford/md-check-compile-typescript
Getting Started ¶
The documentation here was generated from the markdown in examples/src by the md-check.js script .
Configure md-check
const {mdCheck, NodeVmExecutor} = require('@btilford/md-check');
const run = mdCheck({
include: {
patterns: [
'docs/**/*.{md,mdx}'
]
},
executors: [
[NodeVmExecutor.supply()]
]
});
// Calling run() will trigger execution.
Development ¶
If you don’t have rush installed you’ll need to get that.
npm install -g @microsoft/rush
Clone and initialize
git clone git@github.com:btilford/md-check.git
rush install
Building
rush build
Writing Markdown.
Making code blocks executable ¶
Executors get passed the fence and can either accept it or skip it. The node vm executor will split the fence’s name and check if the last item in the array is node or node-vm.
```javascript node
console.log('This would be executed by the node vm executor');
```
```javascript node-vm
console.log('This would be executed by the node vm executor');
```
```javascript js
console.warn('This would NOT be executed by the node vm executor');
```
File metadata ¶
Metadata is YAML parsed out of the header block of the file. The currently support entries are.
title: Title for the file # Used to generate header and link text
description: Added to link.title
env: # Provide env parameters for the file
- NODE_ENV: test
fences:
- title: Title for code block 0 # Used on links to specific code blocks
description: Added to link.title
env: # Provide env parameters specific for this block
- NODE_ENV: production
Run Mocha
Configure the MochaExecutor ¶
Installation
npm install --save-dev @btilford/md-check
npm install --save-dev @btilford/md-check-exec-mocha
Configuration
const {MochaExecutor} = require('@btilford/md-check-exec-mocha');
MochaExecutor.supply(); // use the defaults
MochaExecutor.supply(
{ui: 'bdd'}, // Pass in Mocha.MochaOptions object (a custom reporter will be used unless you provide one)
false // Don't fail on test failure. (default is true)
);
Running Mocha Tests ¶
Inside your markdown file add a code fence ending with mocha, ```javascript mocha.
import {expect} from 'chai';
describe('My test', function() {
it('Runs this test', function() {
expect(true).to.eq(true);
console.log('In test');
});
});
stdout >
> In test
Node Examples
Capture stdout and stderr ¶
console.log('A log message');
stdout >
> A log message
Setting up the NodeVMExecutor ¶
This uses VM2 to execute the scripts in a sandbox. All the standard vm2 options can be passed in.
import {NodeVmExecutor} from '@btilford/md-check';
NodeVmExecutor.supply(); // Use defaults
NodeVmExecutor.supply({/* vm2 options */});
Shell Examples
Run code block a bash script ¶
echo "Hello from bash"
echo "Goodbye" 1>&2
stdout >
> Hello from bash
stderr >
> Goodbye
This requires configuring a WriteSourceCompiler and a ForkExecutor that will
create a command resembling bash $COMPILED_FILE
which will expand to the path
where the code block was written by the WriteSourceCompiler.
import {WriteSourceCompiler, ForkExecutor} from '@btilford/md-check';
// This will generate a temp file with the code block's contents
WriteSourceCompiler.supply(/bash$/)
ForkExecutor.supply(
/bash$/,
'bash',
{},
'$COMPILED_FILE', // Will insert the path provided by the WriteSourceCompiler
);
Eval a code block ¶
echo "OS Type: $(uname)"
stdout >
> OS Type: Linux
This can be setup with a ForkExecutor
import {ForkExecutor} from '@btilford/md-check';
ForkExecutor.supply(
/eval$/,
'eval',
{},
'"$SOURCE"', // Eval the code block's source.
);
Configuring a ForkExecutor ¶
The fork executor takes the following arguments.
- A pattern to match on the fence name.
- The command to run.
- (optional) Default env properties. These can be overridden in your markdown at file or fence level.
- (optional) A var args to pass to the command.
In addition the command will have access to the following env properties
- COMPILED_FILE will be set if the file goes through compilation
- SOURCE_FILE the uncompiled file containing the fence’s code (not the original markdown file).
- SOURCE the raw source of the file.
import {ForkExecutor} from '@btilford/md-check';
ForkExecutor.supply(
/bash|sh$/, // match fence names ending with bash or sh
'bash', // execute bash
{}, // no env defaults
'-e', '$SOURCE' // args eval source
);
ForkExecutor.supply(
/babel$/,
'babel',
{NODE_ENV: process.env.NODE_ENV},
'$SOURCE_FILE', '--out-dir', 'dist/'
);
ForkExecutor.supply(
/npm$/,
'npm',
{},
'run', 'build'
);
Typescript Examples
Installation ¶
npm install --save-dev @btilford/md-check-compile-typescript
Setup the Typescript compiler ¶
import {TsCompiler} from '@btilford/md-check-compile-typescript';
TsCompiler.supply(); // default configs, uses ${process.cwd()}/tsconfig.json
TsCompiler.supply('tsconfig.json'); // Provide a path to you tsconfig
TsCompiler.supply({/* compiler options */}); // Provide a configuration object
Compile and run ¶
Inside your markdown file add a code fence starting with typescript ```typescript.
import {ConsoleLog} from '@btilford/ts-base';
const log: Log = ConsoleLog.create('example');
log.info('Hello');