Метаданные файлов

Работа с Markdown и HTML в экосистеме JavaScript часто требует не только парсинга содержимого, но и извлечения дополнительной информации о файлах, такой как автор, дата создания, категории или другие настраиваемые свойства. Remark и Rehype предоставляют гибкие возможности для обработки метаданных, которые становятся особенно полезными при генерации статических сайтов, документации или систем управления контентом.

Фронтматтер в Markdown

Фронтматтер — это блок YAML, JSON или TOML в начале Markdown-файла, который содержит структурированные метаданные. В Remark фронтматтер традиционно обрабатывается через плагин remark-frontmatter.

Пример фронтматтера в YAML:

---
title: "Пример статьи"
author: "Иван Иванов"
date: "2026-03-22"
tags:
  - javascript
  - remark
---
# Содержание статьи

Фронтматтер парсится как отдельный узел AST (yaml или toml) внутри Markdown-документа. Для его извлечения используется remark-parse вместе с remark-frontmatter и yaml парсером:

import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkFrontmatter from 'remark-frontmatter';
import yaml from 'js-yaml';

const processor = unified()
  .use(remarkParse)
  .use(remarkFrontmatter, ['yaml'])
  .use(() => (tree) => {
    const metaNode = tree.children.find(node => node.type === 'yaml');
    if (metaNode) {
      const metadata = yaml.load(metaNode.value);
      console.log(metadata);
    }
  });

await processor.process('# Пример Markdown');

Ключевой момент: фронтматтер не изменяет содержимое документа, а добавляет структурированную информацию, доступную для любых дальнейших преобразований AST.

Расширение AST метаданными

После парсинга Markdown в AST часто возникает необходимость добавления произвольных метаданных на уровне узлов или документа в целом. Remark предоставляет возможность внедрять данные через поле data узлов:

tree.children.forEach(node => {
  if (node.type === 'heading' && node.depth === 1) {
    node.data = node.data || {};
    node.data.titleFound = true;
  }
});

Такой подход позволяет другим плагинам или обработчикам Rehype использовать эти данные при генерации HTML или других форматов.

Связь Remark и Rehype

Remark отвечает за Markdown, а Rehype — за HTML. Для передачи метаданных из Markdown в HTML применяется remark-rehype. AST Remark преобразуется в AST Rehype, сохраняя метаданные узлов:

import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';

const htmlProcessor = unified()
  .use(remarkParse)
  .use(remarkFrontmatter, ['yaml'])
  .use(remarkRehype, { allowDangerousHtml: true })
  .use(rehypeStringify);

const html = String(await htmlProcessor.process(markdownContent));

При этом метаданные, хранящиеся в узлах Remark, можно дополнительно перенести в атрибуты HTML:

import rehypeVisit from 'unist-util-visit';

function addMetadataToHtml() {
  return (tree) => {
    rehypeVisit(tree, 'element', node => {
      if (node.tagName === 'h1' && node.data?.titleFound) {
        node.properties = node.properties || {};
        node.properties['data-title-found'] = true;
      }
    });
  };
}

Управление глобальными метаданными

Для больших проектов часто требуется хранить глобальные свойства файлов, например slug, category или draft. Их можно добавлять к дереву AST через file.data, который доступен на этапе парсинга и сохраняется через цепочку Unified:

import { VFile } from 'vfile';

const file = new VFile({ path: 'example.md', contents: markdownContent });
file.data.slug = 'primer-stati';
file.data.category = 'javascript';

const processor = unified()
  .use(remarkParse)
  .use(remarkFrontmatter, ['yaml'])
  .use(() => (tree, file) => {
    console.log(file.data.slug); // primer-stati
  });

await processor.process(file);

Примечание: использование file.data предпочтительно для глобальных метаданных, а node.data — для локальных свойств конкретного узла.

Практические сценарии

  1. Генерация оглавления Метаданные заголовков можно собрать и использовать для построения навигации или якорных ссылок.

  2. Фильтрация статей Значение draft: true в фронтматтере позволяет исключать незавершённые статьи из сборки.

  3. SEO и Open Graph Метаданные title, description, image можно автоматически добавлять в теги <meta> при конверсии Markdown в HTML через Rehype.

  4. Многоформатный вывод Сохранив метаданные на уровне AST, можно конвертировать один и тот же Markdown одновременно в HTML, PDF и JSON без потери информации.

Рекомендации по организации

  • Все структурированные данные файлов хранить в file.data для согласованного доступа.
  • Локальные свойства, относящиеся к узлам, помещать в node.data.
  • Парсить фронтматтер перед любой трансформацией AST.
  • Сохранять типы данных и использовать проверку typeof для предотвращения ошибок при конверсии.
  • Использовать утилиты unist-util-visit и unist-util-select для удобной навигации и модификации узлов AST.

Метаданные файлов в Remark и Rehype становятся мощным инструментом для построения сложных статических сайтов и приложений с гибкой логикой обработки контента, позволяя разделять структуру документа и его дополнительные свойства без изменения основного содержимого.