Remark и Rehype строят обработку Markdown и HTML через систему плагинов, где каждый плагин может изменять дерево синтаксиса (AST) или трансформировать контент. Ошибки в процессе могут возникать на нескольких уровнях: синтаксическом, семантическом или логическом.
Remark и Rehype предоставляют встроенные механизмы для обнаружения и
передачи этих ошибок. Основным инструментом является объект
VFile, который хранит как содержимое файла, так и
метаданные, включая сообщения об ошибках (messages). Каждое
сообщение содержит:
reason — текст ошибки,position — диапазон в исходном тексте,fatal — булево значение, определяющее критичность
ошибки.Каждый плагин в Remark/Rehype реализуется как функция, принимающая
AST и объект VFile. Для корректного тестирования важно,
чтобы плагин возвращал ошибки через file.message:
function examplePlugin(options) {
return (tree, file) => {
visit(tree, 'text', (node) => {
if (node.value.includes('TODO')) {
file.message('Обнаружено TODO в тексте', node.position, 'example-plugin/todo');
}
});
};
}
visit — утилита для обхода дерева AST.file.message создает объект ошибки и добавляет его в
массив сообщений.Ошибки можно помечать как фатальные, если нужно прервать обработку:
file.fail('Критическая ошибка: недопустимый контент', node.position);
Метод fail автоматически завершает обработку и
генерирует исключение, что полезно для строгой валидации.
Тестирование плагинов должно проверять:
import {unified} from 'unified';
import remarkParse from 'remark-parse';
import {examplePlugin} from './plugins/example-plugin.js';
import {expect} from 'chai';
const processor = unified().use(remarkParse).use(examplePlugin);
it('должен сообщать об ошибке при наличии TODO', () => {
const file = processor.processSync('Здесь есть TODO');
expect(file.messages).to.have.lengthOf(1);
expect(file.messages[0].reason).to.include('TODO');
});
file.fail корректно прерывает обработку:it('должен прерывать обработку при критической ошибке', () => {
expect(() => processor.processSync('Некорректный контент'))
.to.throw('Критическая ошибка');
});
position соответствует реальному месту в исходном
тексте:expect(file.messages[0].position.start.line).to.equal(1);
expect(file.messages[0].position.start.column).to.equal(11);
Remark и Rehype позволяют строить сложные цепочки плагинов. Ошибки могут возникать на любом этапе:
VFile.const processor = unified()
.use(remarkParse)
.use(pluginA)
.use(pluginB);
const file = await processor.process('Исходный текст');
file.messages.forEach(msg => {
console.log(msg.reason, msg.position);
});
Для анализа сложных цепочек рекомендуется использовать логирование ошибок:
file.messages.forEach(msg => {
console.error(`[${msg.source}] ${msg.reason} (строка ${msg.position.start.line})`);
});
source помогает идентифицировать плагин, который
сгенерировал ошибку.Rehype использует аналогичную систему сообщений. Для тестирования HTML-парсинга можно проверять:
import rehypeParse from 'rehype-parse';
import rehypeStringify from 'rehype-stringify';
const processor = unified()
.use(rehypeParse, {fragment: true})
.use(rehypeStringify);
const file = processor.processSync('<div><span>Текст</div>');
file.messages.forEach(msg => {
console.log(msg.reason); // Сообщения о несоответствии структуры
});
Сообщения об ошибках позволяют автоматизировать проверку HTML-контента перед дальнейшей обработкой.
Для систематического контроля рекомендуется:
Такая практика обеспечивает высокую надежность цепочек Remark/Rehype и позволяет безопасно добавлять новые плагины или модифицировать существующие.