В этой статье я расскажу, как мы генерируем документацию из комментариев в коде TypeScript. В целом, все довольно просто, если требования простые. Впрочем, донастроить под себя тоже не очень трудно.
Что у нас получилось — можно посмотреть здесь.
Документация в коде — это прекрасно!
Когда встала задача создания документации к нашему TypeScript API, первое, с чего мы начали — просто табличка в google docs. Мы копировали туда названия наших компонентов, их параметры, а технический писатель уже делал из этого документацию. Это было ужасно. Табличка постоянно устаревала, копировать в нее было неудобно, куча ручной работы.
Потом мы все-таки взялись сделать генерацию документации из кода, и я безумно рад, что у нас получилось. По сравнению с первым подходом — это просто фантастика:
- Документация всегда актуальна и точна. Даже если технический писатель забыл дописать текст — в документации будет что-то.
- Минимум ручного труда. Время тратится только на написание текста — все остальное делается автоматически. Никакого форматирования, оформления и прочей рутины.
- Первичный вариант документации может писать разработчик, так что нет необходимости отдельно объяснять техпису, что к чему. Он просто редактирует существующий текст.
- Вся документация отображается в IDE при использовании API.
Как все выглядит
В коде документация получается следующего вида:
/**
* Register or update value for specified key.
* @param key Key to identify value in container.
* @param value Value to inject.
* @returns Created or existing [DiRecord]{@link DiRecord}
*/
public register<KeyT, ValueT>(key: KeyT, value: ValueT): Typedin.DiRecord<KeyT, ValueT> {
}
Для генерации, в первую очередь, нужно установить typedoc. Есть плагины для gulp и grunt.
npm install typedoc -g
Базовую конфигурацию можно посмотреть на примере моей библиотеки typedin. Там используется голый typedoc, без каких-либо заморочек и кастомизации. Такую документацию вы можете сгенерировать для своего проекта, просто добавив одну команду в свои скрипты:
typedoc --readme README.md --name typedin --out ./docs/ --tsconfig tsconfig.prod.json --excludePrivate --excludeNotExported --excludeExternals
После этого в папке docs
появится статический сайт, который можно, например, опубликовать через github pages.
Стоит заметить, что документация по использованию typedoc на сайте и на github обычно неактуальная. Для справки используйте:
typedoc --help
Синтаксис комментариев
В целом, синтаксис от jsdoc. То есть, комментарии заключаются в /** */
и используются теги @returns
и @param
как в примере выше (обычно больше ничего и не требуется). Основное отличие от jsdoc — не нужно писать тип параметров, т.к. он уже есть в коде.
Комментарии поддерживают разметку markdown, что дает широкие возможности для форматирования. Не буду пересказывать весь синтаксис, приведу только самые частые кейсы:
-
Для того, чтобы отделить один абзац от другого, нужно поместить между ними пустую строку
/** * Этот метод что-то делает, первый абзац. * * Но иногда и ничего не делает, второй абзац. */ function doSomething(){ }
В принципе, можно использовать
<br/>
, но это некрасиво. -
Для вставки примера кода нужно сделать отступ в 4 пробела + отступы сверху и снизу
/** * Устанавливает значение [controlImpl]{@link controlImpl}, в соответствии с идиомой Pimpl. * Метод должен передаваться в качестве значения ref в функции render. Например: * * <MyControlImpl ref={this.attachControl} />; * * @param control Ссылка на реализацию контрола. */ protected attachControl(control) { this.controlImpl = control; }
-
Для вставки кода прямо в тексте параграфа используются бэктики
/** * При переопределении в дочернем классе должен возвращать новый * экземпляр параметров компонента, созданный через оператор `new` (например: `new MyControlParams()`) * Данный объект будет присвоен свойству `this.state`. */ protected abstract createParams(): P;
-
В комментариях можно ссылаться на различные части API при помощи тега
@link
. Синтаксис у него похож на обычные ссылки markdown:[getParamValue]{@link BaseControlImpl.getParamValue}
— ссылка на член другого класса[Constants]{@link Constants}
— ссылка на глобальный объект[setParamValues]{@link setParamValues}
— ccылка на член этого же класса
Кастомизация
Первое, с чем мы столкнулись — это необходимость кастомизации внешнего вида. Стандартная тема нас не устраивала, хотелось оформления в фирменных цветах компании. Кроме того, в стандартной теме банально не работают контролы управления в верхней части страницы. Все это решается созданием своей темы, на основе стандартной.
Документация утверждает, что все темы наследуются от default темы. То есть, нам нужно разместить в своей теме только те файлы, которые мы изменили. Но проще скопировать всю тему целиком и уже в ней разбираться, что и как нужно поправить.
Тема состоит из стилей, скриптов, различных ресурсов и шаблонов handlebars. Соответственно, в теории, изменяя тему можно сделать все что угодно. Если нужно добавить какую-то сложную логику в шаблоны, можно сделать плагин. Тем не менее, сходу сделать что-то существенное в handlebars-шаблонах у меня не получилось. Я раньше не работал с этим шаблонизатором, возможно в этом дело. Поэтому я ограничился модификацией стилей, скриптов и несущественных правок в шаблонах.
Чтобы добавить свои файлы стилей и скрипты, я разместил файлы web-client.css и web-client.js в папках assets/css
и assets/js
соответственно, и прописал их в файле layoutsdefault.hbs
:
<link rel="stylesheet" href="{{relativeURL "assets/css/web-client.css"}}">
...
<script src="{{relativeURL "assets/js/web-client.js"}}"></script>
В целом, получилось по 70 строчек css и js. Благодаря css наша документация имеет оригинальную темную шапку, отличную от стандартной и некоторые другие мелкие изменения. В javascript в основном исправлена работа флагов "показывать protected/inherited". HTML этих флагов также был исправлен в шаблоне partialsheader.hbs
.
Итого, чтобы настроить под себя генерируемую документацию, необходимо:
- Скачать стандартную тему.
- Добавить свои css, js и поправить шаблоны.
-
Добавить флаг
--theme <путь к папке с темой>
при генерации документации:typedoc --theme MyThemeFolder --name typedin --readme README.md --out ./docs/ --tsconfig tsconfig.prod.json --excludePrivate --excludeNotExported --excludeExternals
Так, путем написания несложного css, js и небольшой правки шаблонов можно решить большинство задач по кастомизации. Для более серъезных изменений понадобится разобраться с handlebars и написать плагины.
Заключение
Typedoc пока довольно сырой проект, и мне не удалось найти достойных альтернатив. Удивительно, что эта тема так слабо развита, учитывая что TypeScript все больше набирает популярность. Мне даже не удалось найти ни одной адекватной темы для typedoc — поиск по github выдает некоторые результаты, но все они либо нерабочие, либо не представляют ничего интересного. И это несмотря на то, что npm-пакет typedoc имеет десятки тысяч загрузок в день.
Этой статьей я хотел бы привлечь внимание сообщества к этой теме и к typedoc в частности. Проект остро нуждается в контрибьюторах, нужно развивать утилиту, писать классные темы, актуализировать документацию. Генерация документации из кода — это мегаполезная вещь и хорошего API Reference очень не хватает многим javascript-библиотекам.
Можно с уверенностью сказать, что typedoc — рабочий инструмент, который справляется со своей задачей и достаточно гибок, чтобы удовлетворить большинству потребностей. У нас довольно большой проект, и никаких особых проблем в его работе мы пока не обнаружили. Код разбирается корректно, ничего не падает и работает хорошо.
Единственное, чего ему не хватает — внимания от сообщества. Используйте в своих проектах и делитесь своими наработками. Нашу тему можно скачать на github.
Автор: Павел Богатырёв