Валидация схемы метаданных

В работе с Remark и Rehype часто возникает необходимость обрабатывать не только содержимое Markdown или HTML, но и сопутствующие метаданные, например, фронтматтер YAML или JSON-объекты, встроенные в документы. Корректная валидация этих данных обеспечивает надежность и предсказуемость последующей обработки.


1. Форматы метаданных

Метаданные чаще всего хранятся в следующих форматах:

  • YAML-фронтматтер в Markdown (---\nkey: value\n---)
  • JSON-объекты внутри HTML-атрибутов или скрипт-тегов
  • Пользовательские структуры, сериализуемые в JS-объекты

Remark и Rehype позволяют получать эти данные через плагины и AST-узлы:

import { remark } from 'remark';
import frontmatter from 'remark-frontmatter';

const processor = remark()
  .use(frontmatter, ['yaml']);

const file = await processor.process(`---
title: "Пример документа"
date: 2026-03-22
---`);

Фронтматтер YAML будет представлен как узел yaml в дереве MDAST, и его содержимое можно разобрать с помощью js-yaml.


2. Подходы к валидации

Существует несколько способов проверять корректность метаданных:

  1. Ручная проверка типов и обязательных полей Простейший вариант: после парсинга YAML или JSON проверять наличие ключей и соответствие типов.
import yaml from 'js-yaml';

const data = yaml.load(file.contents);

if (typeof data.title !== 'string') {
  throw new Error('Поле title должно быть строкой');
}
if (!data.date) {
  throw new Error('Отсутствует обязательное поле date');
}
  1. Схемы JSON / Yup / Zod Для крупных проектов удобнее описывать схему данных и автоматизировать проверку:
import { z } from 'zod';

const metadataSchema = z.object({
  title: z.string(),
  date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
  tags: z.array(z.string()).optional(),
});

const parsedData = metadataSchema.parse(data);

Использование таких библиотек позволяет сразу получать подробные ошибки и избегать ручных проверок.


3. Интеграция с Remark

Remark предоставляет механизм плагинов, который позволяет обрабатывать AST перед финальной генерацией документа. Валидация метаданных естественно встраивается в этот процесс.

Пример плагина для проверки фронтматтера:

function validateFrontmatter() {
  return (tree, file) => {
    const yamlNode = tree.children.find(node => node.type === 'yaml');
    if (!yamlNode) return;

    const data = yaml.load(yamlNode.value);
    try {
      metadataSchema.parse(data);
    } catch (err) {
      file.fail(`Ошибка валидации фронтматтера: ${err.message}`);
    }
  };
}

remark()
  .use(frontmatter, ['yaml'])
  .use(validateFrontmatter)
  .process(markdownContent);

Плагин анализирует узел yaml, применяет схему и генерирует ошибки через объект file, что интегрируется с системой обработки ошибок Remark.


4. Валидация Rehype

В Rehype метаданные чаще встречаются в атрибутах HTML или в скриптах JSON. Валидация осуществляется аналогично:

  • Извлечение данных через AST-узлы типа element и атрибут data-*.
  • Применение схемы с помощью Zod, Yup или ручной проверки.
  • Генерация ошибок через контекст обработки плагина.

Пример:

import { rehype } from 'rehype';
import rehypeParse from 'rehype-parse';

function validateDataAttributes() {
  return (tree) => {
    const elements = tree.children.filter(node => node.type === 'element');
    elements.forEach(el => {
      if (el.properties?.['data-meta']) {
        const meta = JSON.parse(el.properties['data-meta']);
        metadataSchema.parse(meta);
      }
    });
  };
}

rehype()
  .use(rehypeParse, { fragment: true })
  .use(validateDataAttributes)
  .process(htmlContent);

5. Практические рекомендации

  • Всегда определять обязательные поля и типы: это снижает риск ошибок при генерации страниц или экспорта данных.
  • Использовать схемы для крупных проектов: ручные проверки подходят для простых случаев, но схемы дают структурированность и документированность.
  • Интегрировать валидацию в pipeline: Remark и Rehype позволяют выполнять проверку на этапе плагинов, что делает процесс безопасным и централизованным.
  • Логировать ошибки корректно: объект file в Remark и кастомные исключения в Rehype позволяют легко отлаживать большие проекты.

6. Валидация сложных структур

Метаданные могут включать вложенные объекты, массивы и условные поля. В таких случаях Zod и Yup позволяют строить рекурсивные схемы:

const complexSchema = z.object({
  title: z.string(),
  authors: z.array(z.object({
    name: z.string(),
    email: z.string().email().optional(),
  })),
  date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
});

Это обеспечивает строгую проверку структуры без необходимости писать десятки условных операторов вручную.


7. Рекомендации по производительности

  • Парсинг YAML и JSON выполняется один раз, а затем результат валидируется.
  • В больших проектах желательно кешировать результаты валидации.
  • Проверка на этапе AST позволяет раннее обнаружение ошибок, до генерации HTML или Markdown.

Метаданные становятся надежной частью конвейера обработки документов благодаря строгой валидации, интегрированной с AST-плагинами Remark и Rehype.