mdast-util-toc: Markdown Table of Contents Utility
mdast-util-toc is a utility within the unified (specifically mdast) ecosystem for programmatically generating a table of contents from a markdown abstract syntax tree (AST). It provides a `toc` function that processes an `mdast` tree, identifying headings and constructing a new `mdast` list node representing the table of contents. The package is currently stable at version 7.1.0, with minor and patch releases occurring periodically, and major versions introducing breaking changes like ESM-only support or Node.js version bumps. Key differentiators include its tight integration with the `mdast` AST format, allowing for flexible programmatic manipulation, and its robust options for controlling the TOC generation, such as specifying heading depth (`minDepth`, `maxDepth`), skipping specific headings, and defining parent node types. It's often used indirectly via `remark-toc` for simpler integration into `remark` pipelines, which handles the injection of the generated TOC back into the document. Its focus is purely on AST transformation, making it highly composable.
Common errors
-
ERR_REQUIRE_ESM: require() of ES Module ...mdast-util-toc failed
cause Attempting to use `require()` to import an ESM-only package.fixChange your import statement to `import { toc } from 'mdast-util-toc';` and ensure your project is configured for ESM (e.g., `"type": "module"` in `package.json`). -
TypeError: Cannot read properties of null (reading 'map')
cause Your code is expecting the `toc` function to return an object with a `map` property, but it received `null` (pre-v7 behavior) or `undefined` (v7+ behavior) because no table of contents could be generated.fixBefore accessing properties like `map`, check if the `table` result is not `undefined` (or `null` for older versions): `const table = toc(tree); if (table && table.map) { /* process table */ }` -
SyntaxError: Named export 'toc' not found. The requested module 'mdast-util-toc' does not provide an export named 'toc'
cause This typically occurs when trying to use ESM `import` syntax in an environment (like an older Node.js version) that doesn't fully support ESM, or when there's a module resolution issue.fixEnsure you are running Node.js 16+ and your project's `package.json` specifies `"type": "module"` if you are using `.js` files for ESM. Otherwise, use `.mjs` file extensions. Verify `mdast-util-toc` is correctly installed.
Warnings
- breaking mdast-util-toc became an ESM-only package. CommonJS `require()` is no longer supported.
- breaking Node.js 16 or higher is now required to use mdast-util-toc.
- breaking The `toc` function now returns `undefined` if no table of contents can be generated (e.g., no headings found or no matching heading). Previously, it returned `null`.
- gotcha The package now uses an `export` map. Avoid using private or internal APIs as they might change without warning.
- gotcha The `minDepth` option was added, allowing you to specify the minimum heading depth to include in the generated table of contents.
Install
-
npm install mdast-util-toc -
yarn add mdast-util-toc -
pnpm add mdast-util-toc
Imports
- toc
const toc = require('mdast-util-toc')import { toc } from 'mdast-util-toc' - Options, Result
import type { Options, Result } from 'mdast-util-toc' - toc
import {toc} from 'https://esm.sh/mdast-util-toc@7'
Quickstart
import {toc} from 'mdast-util-toc';
/** @type {import('mdast').Root} */
const tree = {
type: 'root',
children: [
{type: 'heading', depth: 1, children: [{type: 'text', value: 'Alpha'}]},
{type: 'heading', depth: 2, children: [{type: 'text', value: 'Bravo'}]},
{type: 'heading', depth: 3, children: [{type: 'text', value: 'Charlie'}]},
{type: 'heading', depth: 2, children: [{type: 'text', value: 'Delta'}]},
{type: 'paragraph', children: [{type: 'text', value: 'Some content here.'}]},
{type: 'heading', depth: 1, children: [{type: 'text', value: 'Gamma'}]}
]
};
// Generate a table of contents for the entire tree
const table = toc(tree, { maxDepth: 2 });
console.dir(table, {depth: 3});
/* Expected Output (simplified):
{
index: undefined,
endIndex: undefined,
map: {
type: 'list',
ordered: false,
spread: true,
children: [
{ type: 'listItem', spread: true, children: [ [Object] ] }, // Alpha
{ type: 'listItem', spread: true, children: [ [Object], [Object] ] } // Gamma
]
}
}
*/