Test all the code in your markdown docs!
npm install @doccident/doccident

Test the code examples in your Markdown documentation.
As an open source developer, few things are more frustrating for users than encountering broken examples in a README. doccident ensures your documentation remains accurate by treating your examples as testable code. It parses your Markdown files, extracts code blocks for multiple languages, and executes them in a sandboxed environment to verify they run without errors.
This project was born out of frustration. The author once wrote a massive technical book, only to be haunted by the realization that subtle bugs had crept into the code examples and output listings during the editing process.
doccident solves this by automating the verification of your documentation. It doesn't just check if your code compiles; it can execute your snippets and verify their output matches what you claim in your docs. This "living documentation" approach guarantees that your readers always see correct, working code and accurate output.
Supported Languages:
* JavaScript (Node.js)
* TypeScript
* Python
* Shell (Bash, Sh, Zsh)
* Go
* Rust
* Fortran
* COBOL
* C
* BASIC
* Java
* Perl
* C#
* R
* Pascal
> Note: doccident primarily verifies that your code runs without throwing exceptions. While you can add assertions to your examples to test correctness, its main goal is to ensure your documentation examples are valid and runnable.
``bash`
npm install --save-dev @doccident/doccident
Run doccident in your project root. By default, it recursively checks all .md and .markdown files (excluding node_modules).
`bash`
npx doccident
You can also target specific files or directories:
`bash`
npx doccident docs/*/.md
By default, each code snippet has a 5-minute (300,000ms) timeout to prevent infinite loops or hangs. You can customize this with the --timeout flag (in milliseconds):
`bash`
npx doccident --timeout 60000 # 60 second timeout
If a snippet exceeds the timeout, it will fail with an error message indicating the timeout was reached.
doccident executes code inside fenced code blocks for the following languages:
* JavaScript: js, javascript, es6ts
* TypeScript: , typescriptpy
* Python: , pythonsh
* Shell: , bash, zsh, shellgo
* Go: rust
* Rust: , rsfortran
* Fortran: , f90, f95cobol
* COBOL: , cobc
* C: basic
* BASIC: java
* Java: perl
* Perl: , plcsharp
* C#: , csr
* R: pascal
* Pascal: , pastext
* Text/Output: , txt, output (for output verification)
It automatically transforms modern JavaScript and TypeScript using esbuild before execution.
#### JavaScript
Use js, javascript, or es6 for JavaScript examples.
Execution Model:
Runs directly in a Node.js vm sandbox.
Recipe:
1. Use js fenced code blocks.require
2. Write standard JavaScript (ES6+ supported).
3. Use to load dependencies defined in your configuration.
`js`
const { sum } = require('./math-utils');
const result = sum(1, 2);
#### TypeScript
Use ts or typescript for TypeScript examples.
Execution Model:
Transpiled via esbuild, then runs in a Node.js vm sandbox.
Recipe:
1. Use ts fenced code blocks.doccident
2. Include type annotations to demonstrate correct usage.
3. strips types during execution, so your examples serve as both documentation and functional tests.
`ts
interface User {
id: number;
name: string;
}
const user: User = { id: 1, name: 'Doccident' };
console.log(user.name);
`
#### Python
Use py or python for Python examples.
Prerequisites:
* python3 must be installed and available in your system path.brew install python
* macOS: sudo apt-get install python3
* Ubuntu/Debian:
Execution Model:
Spawns a python3 subprocess with the code piped to stdin.
Recipe:
1. Use python fenced code blocks.
2. Standard library imports work out of the box.
3. State can be shared between blocks using .
`python`
import json
data = {"key": "value"}
assert json.loads('{"key": "value"}') == data
#### Shell Scripts
Use sh, bash, zsh or shell (defaults to bash) for shell examples.
Prerequisites:
* The specified shell (bash, sh, or zsh) must be available in your system path.
Execution Model:
Spawns a subprocess using the specified shell, with the code piped to stdin.
Recipe:
1. Use specific shell tags like bash or zsh if your script relies on shell-specific syntax.sh
2. Use for POSIX-compliant scripts.
3. State (variables) can be shared between blocks using .
`bash`
export MY_VAR="hello"
`
bash`
if [ "$MY_VAR" != "hello" ]; then exit 1; fi
#### Go
Use go for Go examples.
Prerequisites:
* go must be installed and available in your system path.brew install go
* macOS: sudo apt-get install golang-go
* Ubuntu/Debian:
Execution Model:
Writes code to a temporary file and executes it via go run.
Recipe:
1. Use go fenced code blocks.package main
2. You can provide a full program (including ) OR a simple snippet.package main
3. Simple snippets (without ) are automatically wrapped in a main function and include import "fmt".
4. Note: is supported for Go snippets (auto-wrapped). Declarations (func, type, import) are extracted to top-level.
Simple Snippet:
`go`
fmt.Println("Hello Go")
#### Rust
Use rust or rs for Rust examples.
Prerequisites:
* rustc (Rust compiler) must be installed and available in your system path.brew install rust
* macOS: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
* Ubuntu/Debian: or sudo apt-get install rustc
Execution Model:
Compiles the code using rustc into a temporary binary, then executes the binary.
Recipe:
1. Use rust fenced code blocks.fn main()
2. You can provide a full program (including ) OR a simple snippet.fn main
3. Simple snippets (without ) are automatically wrapped in a main function.
4. Note: is supported for Rust. Attributes like #![...] and extern crate are hoisted to the crate root. Other code is wrapped in fn main().
Simple Snippet:
`rust`
println!("Hello Rust");
let x = 5;
assert_eq!(x, 5);
#### Fortran
Use fortran, f90, or f95 for Fortran examples.
Prerequisites:
* gfortran must be installed and available in your system path.brew install gcc
* macOS: (includes gfortran)sudo apt-get install gfortran
* Ubuntu/Debian:
Execution Model:
Compiles the code using gfortran into a temporary binary, then executes the binary.
Recipe:
1. Use fortran fenced code blocks.program name
2. You can provide a full program (starting with ) OR a simple snippet.program main ... end program main
3. Simple snippets are automatically wrapped in a block.
4. Note: is supported for Fortran. Modules are extracted to the top level; use statements are moved to the top of program main.
Simple Snippet:
`fortran`
print *, "Hello Fortran"
#### COBOL
Use cobol or cob for COBOL examples.
Prerequisites:
* cobc (GnuCOBOL) must be installed and available in your system path.brew install gnucobol
* macOS: sudo apt-get install gnucobol
* Ubuntu/Debian:
Execution Model:
Compiles the code using cobc -x -free into a temporary executable, then runs it.
Recipe:
1. Use cobol fenced code blocks.IDENTIFICATION DIVISION
2. Provide a full COBOL program (including ).-free
3. The compiler is run in free-format mode ().
4. Note: is not supported for COBOL.
`cobol`
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO.
PROCEDURE DIVISION.
DISPLAY 'Hello COBOL'.
STOP RUN.
#### C
Use c for C examples.
Prerequisites:
* gcc must be installed and available in your system path.xcode-select --install
* macOS: or brew install gccsudo apt-get install build-essential
* Ubuntu/Debian:
Execution Model:
Compiles the code using gcc into a temporary binary, then executes the binary.
Recipe:
1. Use c fenced code blocks.main()
2. You can provide a full program (including ) OR a simple snippet.main
3. Simple snippets are automatically wrapped in a function and include stdio.h.
4. Note: is supported for C. Includes and definitions (struct, func) are hoisted; statements are placed in main().
Simple Snippet:
`c`
printf("Hello C\n");
#### BASIC
Use basic for BASIC examples.
Prerequisites:
* cbmbasic must be installed and available in your system path.brew install cbmbasic
* macOS: test.yml
* Ubuntu/Debian: Build from source (see for example).
Execution Model:
Spawns a cbmbasic subprocess with the code piped to stdin.
Recipe:
1. Use basic fenced code blocks.
2. Write standard Commodore BASIC V2 code.
3. State can be shared between blocks using .
`basic`
10 PRINT "HELLO BASIC"
20 END
#### Java
Use java for Java examples.
Prerequisites:
* javac and java must be installed and available in your system path.brew install openjdk
* macOS: sudo apt-get install default-jdk
* Ubuntu/Debian:
Execution Model:
Compiles the code using javac into a temporary class file in a unique directory, then executes it with java.
Recipe:
1. Use java fenced code blocks.public class MyClass { ... }
2. You can provide a full class (e.g. ) OR a simple snippet.public class Main { public static void main(String[] args) { ... } }
3. Simple snippets are automatically wrapped in a .
4. Note: is not supported for Java.
Simple Snippet:
`java`
System.out.println("Hello Java");
Full Class:
`java`
public class Greeting {
public static void main(String[] args) {
System.out.println("Hello from Greeting class");
}
}
#### Perl
Use perl or pl for Perl examples.
Prerequisites:
* perl must be installed and available in your system path.brew install perl
* macOS: Pre-installed or sudo apt-get install perl
* Ubuntu/Debian: Pre-installed or
Execution Model:
Spawns a perl subprocess with the code piped to stdin.
Recipe:
1. Use perl fenced code blocks.
2. Standard library imports work out of the box.
3. State can be shared between blocks using .
`perl`
print "Hello Perl\n";
#### C#
Use csharp or cs for C# examples.
Prerequisites:
* mono (includes mcs compiler) must be installed and available in your system path.brew install mono
* macOS: sudo apt-get install mono-devel
* Ubuntu/Debian:
Execution Model:
Compiles the code using mcs into a temporary executable, then runs it with mono.
Recipe:
1. Use csharp fenced code blocks.public class Program { ... }
2. You can provide a full class (e.g. ) OR a simple snippet.public class Program { public static void Main(string[] args) { ... } }
3. Simple snippets are automatically wrapped in a and include using System;.
4. Note: is not supported for C#.
Simple Snippet:
`csharp`
Console.WriteLine("Hello C#");
Full Class:
`csharp`
using System;
public class Test {
public static void Main(string[] args) {
Console.WriteLine("Hello from Test class");
}
}
#### R
Use r for R examples.
Prerequisites:
* Rscript must be installed and available in your system path.brew install r
* macOS: sudo apt-get install r-base
* Ubuntu/Debian:
Execution Model:
Spawns an Rscript subprocess with the code piped to stdin.
Recipe:
1. Use r fenced code blocks.
2. Standard R syntax works out of the box.
3. State can be shared between blocks using .
`r`
print("Hello R")
#### Pascal
Use pascal or pas for Pascal examples.
Prerequisites:
* fpc (Free Pascal Compiler) must be installed and available in your system path.brew install fpc
* macOS: sudo apt-get install fpc
* Ubuntu/Debian:
Execution Model:
Compiles the code using fpc into a temporary executable, then runs it.
Recipe:
1. Use pascal fenced code blocks.program Name;
2. You can provide a full program (including ) OR a simple snippet.program TestProgram; begin ... end.
3. Simple snippets are automatically wrapped in a block.
4. Note: is not supported for Pascal.
Simple Snippet:
`pascal`
writeln('Hello Pascal');
Full Program:
`pascal`
program Hello;
begin
writeln('Hello from Pascal program');
end.
To skip a specific code block, add the comment immediately before it:
`js`
// This code will not be executed
fetch('https://example.com');
By default, each code block is executed in isolation. To share state (variables, functions, classes) between multiple code blocks in the same file, add the comment. This applies to the entire file.
> Note: This feature is currently supported for JavaScript, TypeScript, Python, Shell, BASIC, Perl, R, Go, Rust, Fortran, and C, but not compiled languages like COBOL, Java, C#, and Pascal.
`python`
x = 10
`python`
# x is still available here
assert x == 10
You can configure execution behavior for specific snippets using comments immediately preceding the code block.
Arguments: Pass arguments to the compiler or interpreter.
`python`
import sys
print("Running with verbose output")
Environment Variables: Set environment variables for the execution.
`bash`
echo "Key: $API_KEY"
You can verify that a code snippet produces specific output by assigning it an ID and then referencing that ID in a subsequent block.
1. Assign an ID to the code snippet using .text
2. Create an output block (usually or json) and reference the ID using .
doccident will execute the first snippet, capture its stdout, and verify that it matches the content of the output block.
Example:
`js`
console.log("Hello Output");
`text`
Hello Output
This is useful for ensuring your documentation's "Output:" sections stay in sync with the actual code behavior.
When verifying output, you can optionally specify a matching mode to handle whitespace or dynamic content.
* exact (default): Exact string match (trailing whitespace is trimmed).ignore-whitespace
* : Collapses all whitespace sequences to a single space and trims ends before comparing.match:regex
* : Treats the output block content as a regular expression.
Examples:
Ignore Whitespace:
`js`
console.log(" A B \n C ");
`text`
A B C
Regex Matching:
`js`
console.log("Timestamp: " + Date.now());
`text`
^Timestamp: \d+$
If you want doccident to automatically update your output blocks with the actual output from execution, run with the --update-output flag.
`bash`
npx doccident --update-output
This will replace the content of any block with the latest captured output from the corresponding ID. This is extremely useful when writing documentation: you can write the code example, add a placeholder output block, and let doccident fill it in for you.
Create a .doccident-setup.js file in your project root to configure the test environment.
If your examples use external libraries, provide them here. This allows your examples to require modules just like users would:
`javascript`
// .doccident-setup.js
module.exports = {
require: {
// Make 'my-library' available when examples call require('my-library')
'my-library': require('./index.js'),
'lodash': require('lodash')
}
};
Define global variables available to all snippets:
`javascript`
module.exports = {
globals: {
$: require('jquery'),
window: {}
}
};
* regexRequire: Handle dynamic requires that match a pattern.
* beforeEach: Function to run before each snippet (e.g., to reset global state).
* transformCode: Pre-process code before execution (e.g., to strip out display-only syntax).
doccident is designed to be a lightweight, flexible testing harness for documentation. The codebase is modularized to separate parsing, execution, and reporting, ensuring maintainability and extensibility.
1. Parser (src/parse-code-snippets-from-markdown.ts)
* Reads Markdown content line-by-line.
* Uses a robust state machine to identify code fences and control comments (like skip-example).js
* Extracts valid snippets into structured objects containing code, file paths, and line numbers.
* Multi-Language Support: Recognizes , ts, python, shell, go, rust, fortran, cobol, c, basic, java, perl, csharp, r, and pascal blocks.
2. Test Runner (src/doctest.ts)
* The orchestrator of the application.
* Iterates through parsed snippets and manages the execution lifecycle.
* Sandboxing: Uses Node.js's vm module (runInNewContext) to execute JS/TS code in isolation.python3
* Subprocess Execution: Spawns , go, rustc, gfortran, cobc, gcc, cbmbasic, javac/java, perl, mcs/mono, Rscript, fpc, or shell subprocesses for non-JS languages.
* Transformation: Uses esbuild to compile modern JavaScript and TypeScript code down to a compatible format before execution.
3. Reporter (src/reporter.ts)
* Collects execution results (pass, fail, skip).
* Formats output using chalk for readability.
* Error Mapping: Crucially, it maps execution errors back to the specific line number in the original Markdown file, making it easy to identify exactly which line in your documentation caused the failure.
4. Types & Utils
* Shared interfaces (src/types.ts) ensure type safety across the application.src/utils.ts
* Utility functions () provide common helpers.
This separation of concerns allows doccident to be easily extended—for example, by adding new parsers for different documentation formats or custom reporters for CI environments.
This project is licensed under the Apache License, Version 2.0.
Copyright (c) 2025 Tim O'Brien
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
---
Note: This project was originally forked from markdown-doctest by Nick Johnstone. While the original inspiration and some core concepts remain, the entire codebase has been replaced and significantly expanded by Tim O'Brien to support a wide range of compiled and interpreted languages, shared state mechanisms, and output verification. All subsequent additions and modifications are covered by the Apache 2.0 Software License.
This repository contains a dedicated guide for AI agents to understand how to use doccident`. If you are an AI model tasked with maintaining this project or using it to verify documentation, please refer to:
This directory contains instructions on capabilities, verification workflows, and configuration specifically structured for machine consumption.
TEST