unist-util-find: поиск узлов

Библиотека unist-util-find предоставляет утилиту для поиска узлов в деревьях AST (Abstract Syntax Tree), которые используются в экосистеме Remark и Rehype. Она упрощает задачу нахождения конкретных элементов по типу, значению или произвольным условиям, работая поверх стандартной структуры unist.


Основы работы с unist-util-find

Функция find экспортируется из пакета unist-util-find и имеет следующую сигнатуру:

import { find } from 'unist-util-find';

const node = find(tree, test);
  • tree — корень дерева AST.
  • test — функция или объект для проверки узлов.
  • Возвращает первый узел, который удовлетворяет условию test, или undefined, если узел не найден.

Варианты аргумента test

test может быть:

  1. Функцией:
const node = find(tree, (node) => node.type === 'heading');

Функция вызывается для каждого узла и должна возвращать true для нужного узла.

  1. Объектом с условиями:
const node = find(tree, { type: 'paragraph' });

find проверяет, совпадают ли свойства объекта test с соответствующими свойствами узла. Это удобно для поиска по конкретным типам или значениям атрибутов.


Примеры использования

Поиск первого заголовка в Markdown:

import { unified } from 'unified';
import remarkParse from 'remark-parse';
import { find } from 'unist-util-find';

const tree = unified()
  .use(remarkParse)
  .parse('# Заголовок\n\nТекст параграфа');

const heading = find(tree, { type: 'heading' });
console.log(heading.depth); // 1

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

const paragraph = find(tree, (node) =>
  node.type === 'paragraph' &&
  node.children.some(child => child.value.includes('Текст'))
);

Особенности поведения

  • Рекурсивный поиск: функция проходит по всему дереву AST, включая вложенные узлы.
  • Первый совпавший узел: find возвращает только первый найденный узел. Для поиска всех узлов используется unist-util-find-all или unist-util-filter.
  • Не модифицирует дерево: поиск выполняется без изменений исходной структуры AST.
  • Поддержка типов узлов Remark/Rehype: работает как с Markdown AST (MDAST), так и с HTML AST (HAST).

Комбинирование с другими утилитами unist

unist-util-find часто используется вместе с:

  • unist-util-visit: для обхода всех узлов и выполнения действий с ними.
  • unist-util-find-all: для поиска всех узлов, соответствующих условию.
  • unist-util-filter: для создания нового дерева с отфильтрованными узлами.

Пример комбинирования:

import { visit } from 'unist-util-visit';

const firstCodeBlock = find(tree, { type: 'code' });

visit(tree, 'code', node => {
  node.lang = node.lang || 'text';
});

Продвинутое использование с кастомными условиями

Можно искать узлы с учетом содержимого и структуры:

const node = find(tree, node =>
  node.type === 'link' &&
  node.url.startsWith('https://') &&
  node.children.length > 0 &&
  node.children[0].value.includes('example')
);

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


Производительность

unist-util-find эффективен для небольших и средних деревьев. Для больших документов стоит учитывать:

  • Использование функций вместо объектов в test позволяет включить более сложную логику поиска.
  • Если нужен поиск нескольких узлов, лучше использовать unist-util-find-all или unist-util-visit с фильтром, чтобы избежать повторного обхода дерева.

Поддержка TypeScript

Библиотека предоставляет типы, что позволяет безопасно работать с AST:

import type { Node } from 'unist';
import { find } from 'unist-util-find';

const node: Node | undefined = find(tree, { type: 'paragraph' });

Типизация гарантирует, что свойства узлов проверяются корректно и исключает ошибки при работе с AST.


Заключение по использованию

unist-util-find — легковесный и мощный инструмент для поиска конкретных узлов в деревьях AST, который отлично интегрируется с экосистемой Remark и Rehype, облегчая извлечение информации, фильтрацию и дальнейшую обработку контента.