unist-util-filter — это утилита для работы с деревьями
синтаксического представления (AST), совместимыми с
unist. Она позволяет создавать новые деревья, фильтруя
узлы по заданным критериям, при этом структура дерева сохраняется, а
нежелательные ветви удаляются. Это особенно полезно при работе с
библиотеками Remark и Rehype, когда
требуется выбирать, трансформировать или удалять определённые типы узлов
из Markdown или HTML AST.
Для использования unist-util-filter необходимо
установить пакет через npm:
npm install unist-util-filter
Подключение в коде выглядит следующим образом:
import { filter } from 'unist-util-filter';
Функция filter принимает два основных аргумента:
const newTree = filter(tree, predicate);
remark.parse()) или Rehype
(rehype.parse()).(node) => boolean, которая возвращает true,
если узел должен быть оставлен, и false, если узел должен
быть удалён.Пример использования функции-предиката:
const keepHeadings = node => node.type === 'heading';
const headingsTree = filter(tree, keepHeadings);
В этом примере создаётся новое дерево, включающее только заголовки.
unist-util-filter поддерживает передачу массива типов
узлов. Узлы, соответствующие любому типу из массива, остаются в
дереве:
const typesToKeep = ['heading', 'paragraph'];
const filteredTree = filter(tree, typesToKeep);
Такой подход удобен для быстрого удаления всех узлов, кроме указанных типов.
Важный аспект работы unist-util-filter — сохранение
иерархии дерева. Если узел не удовлетворяет условию фильтрации, он
удаляется, но его потомки проверяются рекурсивно. Таким образом, могут
оставаться потомки, даже если родительский узел был исключён:
const keepText = node => node.type === 'text';
const newTree = filter(tree, keepText);
Даже если родительский узел типа paragraph не
сохраняется напрямую, все текстовые узлы внутри него будут включены в
результат.
Функция-предикат может использовать любые свойства узла. Например, фильтрация заголовков определённого уровня:
const h2Only = node => node.type === 'heading' && node.depth === 2;
const h2Tree = filter(tree, h2Only);
Аналогично можно фильтровать ссылки по URL или изображения по пути:
const keepExternalLinks = node => node.type === 'link' && /^https?:\/\//.test(node.url);
const externalLinksTree = filter(tree, keepExternalLinks);
Для более сложных случаев можно комбинировать несколько предикатов или строить рекурсивные условия:
const predicate = node => {
if (node.type === 'heading') return node.depth <= 3;
if (node.type === 'paragraph') return true;
return false;
};
const filteredTree = filter(tree, predicate);
Такой подход позволяет гибко контролировать, какие узлы сохраняются на каждом уровне дерева.
Remark: выбор только заголовков и параграфов
import { remark } from 'remark';
import { filter } from 'unist-util-filter';
const md = `
# Заголовок 1
Текст параграфа.
## Заголовок 2
Больше текста.
`;
const tree = remark().parse(md);
const filteredTree = filter(tree, ['heading', 'paragraph']);
console.log(filteredTree);
Rehype: выбор всех ссылок на внешние ресурсы
import { rehype } from 'rehype';
import { filter } from 'unist-util-filter';
const html = `<p>Текст <a href="https://example.com">ссылки</a></p>`;
const tree = rehype().parse(html);
const linksTree = filter(tree, node => node.type === 'element' && node.tagName === 'a' && /^https?:\/\//.test(node.properties.href));
console.log(linksTree);
unist-util-filter является универсальным инструментом
для чистки и отбора узлов AST, что позволяет создавать
новые представления документа, ориентированные на конкретные задачи:
генерацию оглавлений, извлечение ссылок, фильтрацию контента и многое
другое. Его гибкость и простота делают его неотъемлемой частью работы с
Remark и Rehype.