remark-toc: генерация оглавления

Для работы с генерацией оглавления в Markdown используется плагин remark-toc, который интегрируется с экосистемой remark. Сначала необходимо установить необходимые пакеты через npm или yarn:

npm install remark remark-cli remark-toc

или

yarn add remark remark-cli remark-toc

После установки можно подключить плагин в проекте:

import { remark } from 'remark';
import toc from 'remark-toc';
import fs from 'fs';

const markdown = fs.readFileSync('example.md', 'utf-8');

remark()
  .use(toc)
  .process(markdown)
  .then((file) => {
    console.log(String(file));
  });

Принцип работы remark-toc

remark-toc анализирует структуру заголовков в Markdown-файле и вставляет оглавление на основе уровней заголовков (#, ##, ### и т.д.). Основные особенности:

  • Генерация вложенных списков в зависимости от уровней заголовков.
  • Автоматическое обновление оглавления при изменении заголовков.
  • Возможность ограничения глубины отображаемых заголовков.

Настройка параметров плагина

Плагин поддерживает несколько опций для тонкой настройки генерации оглавления:

remark()
  .use(toc, {
    heading: 'Содержание', // Заголовок для оглавления
    maxDepth: 3,           // Максимальный уровень заголовков в оглавлении
    tight: true            // Использовать плотный список без пустых строк
  })
  .process(markdown);

Описание опций:

  • heading — заголовок, который будет вставлен перед оглавлением. По умолчанию Table of Contents.
  • maxDepth — максимальная вложенность заголовков, которые будут включены в оглавление. Например, 2 включает только # и ##.
  • tight — если true, создаёт компактный список без дополнительных пустых строк между пунктами.

Способы вставки оглавления

remark-toc ищет специальные маркеры в Markdown-файле для вставки оглавления:

<!-- toc -->

или

<!-- TOC -->

Плагин автоматически заменяет этот маркер на сгенерированный список заголовков:

<!-- toc -->
- [Заголовок 1](#заголовок-1)
  - [Подзаголовок 1.1](#подзаголовок-11)
  - [Подзаголовок 1.2](#подзаголовок-12)
- [Заголовок 2](#заголовок-2)

Если маркер отсутствует, плагин вставляет оглавление в начало документа.

Совмещение с другими плагинами Remark

remark-toc легко интегрируется с другими плагинами, например, для обработки ссылок или форматирования:

import remarkGfm from 'remark-gfm';
import remarkSlug from 'remark-slug';

remark()
  .use(remarkGfm)   // Поддержка GitHub Flavored Markdown
  .use(remarkSlug)  // Генерация идентификаторов для заголовков
  .use(toc, { heading: 'Содержание' })
  .process(markdown);
  • remark-slug обязателен для правильной работы ссылок в оглавлении, так как генерирует идентификаторы заголовков (id), которые используются в ссылках.
  • remark-gfm добавляет поддержку таблиц, задач и других элементов GitHub Markdown.

Тонкости работы с вложенностью

При больших документах важно корректно управлять глубиной заголовков. Например:

remark()
  .use(toc, { maxDepth: 2 }) // Включает только # и ##, игнорируя ### и ниже

Для контроля уровня вложенности можно комбинировать maxDepth с фильтрацией заголовков через пользовательские функции:

remark()
  .use(toc, {
    maxDepth: 4,
    map: (node) => node.value.toUpperCase() // Преобразует текст заголовков
  });

Обновление оглавления при изменении документа

remark-toc автоматически обновляет содержимое оглавления при изменении заголовков. Если необходимо перегенерировать оглавление без изменения исходного текста, можно использовать:

remark()
  .use(toc, { heading: 'Содержание', tight: true })
  .processSync(markdown);

processSync позволяет получить обновлённый Markdown сразу в синхронном режиме, что удобно для генерации документации на этапе сборки проекта.

Интеграция с Rehype

Для конвертации Markdown в HTML через remark-rehype и последующей обработки HTML можно использовать следующий подход:

import { remark } from 'remark';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';
import toc from 'remark-toc';
import remarkSlug from 'remark-slug';

remark()
  .use(remarkSlug)
  .use(toc)
  .use(remarkRehype)
  .use(rehypeStringify)
  .process(markdown)
  .then((file) => {
    console.log(String(file));
  });
  • remarkRehype преобразует Markdown-дерево в HTML-дерево.
  • rehypeStringify формирует итоговый HTML-код.
  • Использование remark-slug гарантирует корректные якорные ссылки в HTML-оглавлении.

Практические советы

  • Всегда подключать remark-slug перед remark-toc для правильной генерации ссылок.
  • Для больших документов разумно ограничивать maxDepth, чтобы оглавление оставалось читаемым.
  • Использовать маркер <!-- toc --> для точного позиционирования оглавления.
  • В связке с remark-rehype и rehype-stringify можно автоматически получать готовый HTML с интерактивным оглавлением.

Эта связка инструментов позволяет полностью автоматизировать создание структурированного оглавления в Markdown и HTML-документах, обеспечивая единообразие и удобство навигации в больших проектах.