Минимальная конфигурация проекта

Для начала работы с Remark и Rehype требуется создать минимальный проект на Node.js. Основными зависимостями будут:

npm init -y
npm install remark remark-parse remark-stringify rehype rehype-parse rehype-stringify unified
  • unified — ядро системы для обработки AST (Abstract Syntax Tree).
  • remark-parse и remark-stringify — парсер и сериализатор Markdown.
  • rehype-parse и rehype-stringify — парсер и сериализатор HTML.

Создание базовой структуры проекта:

project/
├─ src/
│  └─ index.js
├─ package.json
└─ README.md

Минимальная конфигурация Remark

Remark работает через систему плагинов, которые подключаются к процессору. Простейший пример:

import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkStringify from 'remark-stringify';

const processor = unified()
  .use(remarkParse)       // преобразует Markdown в AST
  .use(remarkStringify);  // преобразует AST обратно в Markdown

const markdown = '# Заголовок\n\nТекст параграфа.';

processor.process(markdown).then(file => {
  console.log(String(file));
});

Ключевые моменты:

  • unified().use(plugin) создаёт цепочку обработки.
  • Каждый плагин получает AST на вход и возвращает модифицированный AST.
  • process возвращает объект VFile, содержащий результат преобразования.

Минимальная конфигурация Rehype

Rehype предназначен для работы с HTML. Базовая настройка аналогична:

import { unified } from 'unified';
import rehypeParse from 'rehype-parse';
import rehypeStringify from 'rehype-stringify';

const processor = unified()
  .use(rehypeParse, { fragment: true })  // парсинг HTML-фрагмента
  .use(rehypeStringify);                 // обратное преобразование в HTML

const html = '<h1>Заголовок</h1><p>Текст параграфа.</p>';

processor.process(html).then(file => {
  console.log(String(file));
});

Особенности:

  • Опция { fragment: true } позволяет обрабатывать отдельные фрагменты HTML, а не полный документ.
  • Вся логика работы с Rehype строится на аналогичных принципах, как у Remark: цепочка плагинов → AST → сериализация.

Связка Remark и Rehype

Для конвертации Markdown в HTML используется связка:

import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';

const processor = unified()
  .use(remarkParse)
  .use(remarkRehype)      // преобразует AST Markdown в AST HTML
  .use(rehypeStringify);

const markdown = '# Заголовок\n\nТекст параграфа.';

processor.process(markdown).then(file => {
  console.log(String(file));
});

Важные моменты:

  • remark-rehype — мост между Markdown и HTML AST.
  • Все последующие плагины Rehype применяются после преобразования.

Настройка VFile для минимума

VFile позволяет хранить метаданные и путь исходного файла:

import { VFile } from 'vfile';

const file = new VFile({
  path: 'example.md',
  contents: '# Заголовок\nТекст параграфа'
});

processor.process(file).then(result => {
  console.log(result.contents);
});

Преимущества использования VFile:

  • Легко добавлять путь исходного файла.
  • Поддержка сообщений об ошибках и предупреждений.
  • Сохранение дополнительных метаданных, например, frontmatter.

Минимальный пример с плагинами

Добавление плагина для преобразования текста в верхний регистр:

function uppercase() {
  return (tree) => {
    visit(tree, 'text', (node) => {
      node.value = node.value.toUpperCase();
    });
  };
}

import { visit } from 'unist-util-visit';
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkStringify from 'remark-stringify';

const processor = unified()
  .use(remarkParse)
  .use(uppercase)
  .use(remarkStringify);

processor.process('# Заголовок\nТекст параграфа.').then(file => {
  console.log(String(file));
});

Пояснения:

  • visit(tree, type, callback) обход дерева AST.
  • Плагин получает дерево и модифицирует только узлы указанного типа.
  • Таким образом, можно создавать кастомные преобразования без сложной конфигурации.

Минимальный проект с файловой системой

Часто требуется обработка Markdown файлов из проекта:

import fs from 'fs/promises';
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';

async function convertFile(filePath) {
  const content = await fs.readFile(filePath, 'utf-8');

  const processor = unified()
    .use(remarkParse)
    .use(remarkRehype)
    .use(rehypeStringify);

  const file = await processor.process(content);
  await fs.writeFile(filePath.replace(/\.md$/, '.html'), String(file));
}

convertFile('src/example.md');

Принципы работы:

  • Чтение Markdown с помощью fs.readFile.
  • Конвертация через связку Remark → Rehype.
  • Запись результата в HTML-файл.

Минимальная конфигурация проекта с Remark/Rehype строится на трёх китах: unified, плагины для парсинга/сериализации и VFile для управления файлами и метаданными. Такая структура позволяет постепенно расширять функционал, добавляя кастомные плагины и интеграцию с другими инструментами, не усложняя базовую настройку.