Больше чем просто пропущенные экспорты: создание раннего сборщика мусора
Я пытался использовать стандартный плагин, чтобы исправить отсутствующие ссылки в документации Webpack. Это не сработало.
Интеграция плагина в большую кодовую базу — задача не из простых. Это превратилось в архитектурный вызов. Мне пришлось управлять манипуляциями с абстрактным синтаксическим деревом (AST), использованием памяти и рекурсивными циклами.
Проблема со стандартными плагинами
Чтобы найти решение, я провел три эксперимента.
Эксперимент 1: Плагин восстановил 135 типов. Однако он поместил их во внутренний модуль. Наш инструмент создавал для них отдельную папку. Нам приходилось сортировать их вручную. Структура документации также была неверной.
Эксперимент 2: Я включил настройку для скрытия внешних типов. Это сработало лишь частично. Объем данных сократился до 60 типов Webpack. Но TypeDoc
Больше, чем просто отсутствие экспортов: создание раннего сборщика мусора для AST TypeDoc в Webpack
При работе с документацией для крупных TypeScript-проектов часто возникает проблема: документация содержит символы, которые на самом деле не являются частью публичного API. Это происходит из-за того, что TypeDoc строит свое абстрактное синтаксическое дерево (AST), основываясь на анализе файлов, но не всегда учитывает, какие именно элементы действительно экспортируются и доступны через точку входа, особенно когда в цепочке участвует Webpack.
Проблема отсутствующих экспортов
Когда мы используем Webpack для сборки, он выполняет сложную работу по разрешению зависимостей и оптимизации кода. Однако TypeDoc работает на уровне анализа типов. Возникает разрыв: TypeDoc может видеть символы, которые Webpack «вырезает» или которые не экспортируются из основной точки входа. Это приводит к «раздутому» AST, наполненному неиспользуемыми узлами.
Обычно разработчики пытаются решить эту проблему, вручную настраивая поля exports в конфигурации TypeDoc. Но в масштабах огромных монорепозиториев это становится невозможным. Нам нужно решение, которое будет работать автоматически.
Решение: Ранний сборщик мусора
Вместо того чтобы пытаться очистить уже построенное дерево (что может быть ресурсозатратно и сложно из-за запутанных связей), мы можем внедрить механизм «сбора мусора» на раннем этапе — непосредственно в процессе построения AST.
Идея заключается в том, чтобы использовать алгоритм Mark-and-Sweep (пометить и очистить):
- Mark (Пометка): Начиная с точек входа (entry points), мы обходим дерево и помечаем все достижимые узлы.
- Sweep (Очистка): Все узлы, которые не были помечены как достижимые, удаляются из дерева.
Реализация
Чтобы реализовать это в контексте TypeDoc, нам нужно вмешаться в процесс создания узлов. Мы можем создать специальный Visitor, который будет проходить по дереву и отслеживать связи.
Вот концептуальный пример того, как это может выглядеть:
// Псевдокод реализации сборщика мусора для AST
class ASTGarbageCollector {
private markedNodes = new Set<Node>();
constructor(private entryPoints: Node[]) {}
public collect(root: Node): void {
this.mark();
this.sweep(root);
}
private mark(): void {
const queue = [...this.entryPoints];
while (queue.length > 0) {
const node = queue.shift();
if (node && !this.markedNodes.has(node)) {
this.markedNodes.add(node);
queue.push(...node.getChildren());
}
}
}
private sweep(node: Node): void {
const children = node.getChildren();
for (const child of children) {
if (!this.markedNodes.has(child)) {
node.removeChild(child);
} else {
this.sweep(child);
}
}
}
}
Почему это важно?
- Точность: Документация будет отражать только то, что реально доступно пользователю вашего пакета.
- Производительность: Меньший размер AST означает более быструю генерацию документации и меньшее потребление памяти.
- Чистота: Избавляет от «призрачных» экспортов, которые могут запутать разработчиков, использующих ваш API.
Заключение
Создание раннего сборщика мусора для AST — это способ синхронизировать то, как Webpack видит ваш код, с тем, как TypeDoc его документирует. Это превращает процесс генерации документации из простого «сканирования файлов» в интеллектуальный анализ графа зависимостей.