mdcode keeps the code blocks in your Markdown docs in sync with real source files. You write and test examples as ordinary code, point a code block at the file (or a #region inside it), and mdcode update copies the current code into the document. Your README can't drift from code that compiles and passes its tests.
It also works the other way: mdcode extract writes code blocks out to files, and mdcode run runs a command against each block. It is a TypeScript port of szkiba/mdcode, compatible with its CLI, and adds transform functions, a library API and a versioned --json output.
npm install --save-dev mdcode-tsThis installs the mdcode command. Node.js 22 or later is required. To try it without installing, run npx mdcode-ts --help.
Put the example in a source file and mark the part you want to show with a region:
// src/greet.ts
// #region greet
export function greet(name: string): string {
return `Hello, ${name}!`;
}
// #endregion
console.log(greet("docs"));In your README, add an empty code block that names the file and region:
```ts file=src/greet.ts region=greet
```Preview the change, then apply it:
npx mdcode update README.md # list the blocks that would change
npx mdcode update --diff README.md # review them as a unified diff
npx mdcode update --apply README.md # write themmdcode fills the block with the region's code, leaving out the markers and the rest of the file:
```ts file=src/greet.ts region=greet
export function greet(name: string): string {
return `Hello, ${name}!`;
}
```When src/greet.ts changes, run mdcode update --apply README.md again. In CI, mdcode update --check README.md exits 1 when a block has drifted from its source, without writing anything. To check several documents and tell drift apart from a broken file=, copy examples/ci/check-docs-sync.mjs; see Checking Docs in CI.
To keep several documents in sync without repeating their paths, list them in mdcode.config.json and run mdcode update --project --check. See Project Configuration.
To check that snippets actually run, mark them runnable=true and copy examples/ci/validate-snippets.mjs. It extracts only those blocks into a temporary workspace, runs your test or lint command there, and fails CI naming the block that broke. See Validating Runnable Snippets in CI.
| Command | What it does |
|---|---|
list |
List code blocks with their language, metadata and a preview |
update |
Refresh blocks from the files they reference, or rewrite them with a transform function. Plans by default; --apply writes, --diff and --check review |
extract |
Write blocks to files named by their file= metadata |
validate |
Report every block that update or extract would refuse, such as a missing region or two blocks writing one file, without writing anything |
watch |
Report drift as you edit documents or their sources; --apply writes it |
run |
Run a shell command on each block, such as a compiler or test runner |
dump |
Pack blocks into a tar archive |
Every command filters blocks by language, file, name or other metadata. All but watch read a Markdown file or stdin and support --json. Running mdcode with no command lists the blocks in README.md.
- Package README: the full reference, also published on npm
- CLI usage and flags reference
- JSON contract for scripts and CI
- Library usage and API reference
- Code block metadata, regions and outlines
- CLI examples: worked examples for each command
- Comparison with the Go mdcode
This is a pnpm workspace. packages/mdcode is the published package and packages/usage holds end-to-end tests against the built CLI. See TESTING.md for the test layout.
pnpm install
pnpm build # build packages/mdcode with zshy
pnpm test # unit and E2E tests (E2E runs the built dist/main.js)
pnpm -r lint:ts # type checkRun the CLI from source with Node 22.17+:
node --experimental-strip-types packages/mdcode/src/main.ts list README.mdOriginal Go implementation by szkiba.