Powitajmy Doco!

blog.comandeer.pl 1 dzień temu

W 2024 roku odbył się konkurs 100 commitów. Założenia były proste: każda osoba w nim uczestnicząca miała rozwijać swój własny projekt open-source’owy. Konkurs trwał 100 dni i każdego dnia na głównego brancha powinien wpaść przynajmniej 1 commit – stąd nazwa konkursu. Stwierdziłem, iż w sumie się zgłoszę, dzięki czemu będę miał motywację do pracy nad projektem. A iż miał to być nowy projekt, to postawiłem na Doco – czyli generator dokumentacji.

Wytrzymałem jakieś 2 tygodnie. Okazało się, iż tempo jednego commita dziennie totalnie mi nie odpowiada. Zwłaszcza w projekcie, w którym sporo rzeczy trzeba przekminić, zanim się owego commita zrobi. No więc mamy drugą połowę 2025 i stwierdziłem, iż pora wrócić do Doco na własnych warunkach.

Tak, zdaję sobie sprawę, iż nie dokończyłem jeszcze czasomierzy. Ale hej, zawsze lepiej nie dokończyć dwóch projektów niż jednego!

Oto Doco

I'm Doco. Umberto Doco.

Doco to w założeniu ma być generator dokumentacji dla projektów napisanych w TS-ie lub JS-ie. Na potrzeby konkursu powstało choćby oficjalne repozytorium, ale niedługo prawdopodobnie zajdą w nim poważne zmiany.

Założenia przyświecające Doco są dość proste:

  1. Podstawą dokumentacji jest kod. Dzięki TypeScriptowi łatwo można wygenerować informacje o typach, a dodatkowe komentarze w formatach takich jak JSDoc czy TypeDoc dostarczą reszty informacji.
  2. Czasami trzeba czegoś więcej niż kod. W JSDocu można przemycić bardzo dużo, łącznie choćby z przykładami kodu. Ale nie wciśnie się tam całego poradnika. Dlatego Doco musi też obsługiwać dodatkową dokumentację, np. w postaci plików .md.
  3. Konfigurowalność, ale przy sensownych ustawieniach domyślnych. Konfiguracja powinna umożliwiać dostosowanie niemal każdego aspektu działania Doco. Ale im większe możliwości konfiguracyjne, tym większa gęstwina opcji, w których można się pogubić. Dlatego też Doco powinno mieć sensowne ustawienia domyślne – tak, żeby w 80% przypadków nie trzeba było ruszać bardziej zaawansowanych opcji konfiguracyjnych.
  4. Rozszerzalność i modularność. Doco w domyśle ma być prostym generatorem statycznych stron, a większość ficzerów będzie egzystować sobie radośnie w pluginach. Modularna budowa pozwoli na łatwe podmienianie pojedynczych kawałków całości, np. standardowy parser TS-a będzie można wymienić na własny. Rozszerzalność pozwoli też dodawać całkowicie nowe funkcjonalności, jak choćby obsługa generowania dokumentacji API w innych językach (Ruście, Go, itd.).
  5. Dobre wsparcie dla monorepo i wielu repozytoriów. Coraz więcej projektów w ekosystemie JS-a korzysta z monorepo. Doco musi zatem ogarniać pracę z repozytoriami, w których jest więcej niż jeden pakiet npm. Równocześnie niektóre większe projekty podzielone są na kilka repozytoriów, dla których jednak powinna powstać ostatecznie jedna, połączona dokumentacja. Innymi słowy: Doco musi umieć obsłużyć obydwa te skrajne przypadki.

Podsumowując: to ma być taki Docusaurus – generator statycznej strony zoptymalizowany pod generowanie dokumentacji. Główna różnica polega na tym, iż gadzina nie ma wbudowanej obsługi generowania dokumentacji API bezpośrednio z kodu. W Doco z kolei byłby to trzon, wokół którego dodane byłyby pozostałe ficzery związane z generowaniem całych stron z dokumentacją.

Architektura

Poczyniłem już choćby wstępne założenia architektoniczne. Doco składałoby się z następujących elementów:

Architektura na ładnym diagramie
  1. Doco. Trzon całości, który mieliłby konfigurację i na jej podstawie robił coś z kodem źródłowym aplikacji. Prawdopodobnie byłby to zwykły emiter zdarzeń i trochę kleju, żeby pospinać wszystkie pozostałe elementy. Trzon zawierałby także pewnie UI dla osób wystarczająco śmiałych, żeby spróbować tego używać w swoich projektach. A pisząc UI, mam na myśli prosty program CLI – na początek z jedną komendą: doco build.
  2. Parsery. To prawdopodobnie będzie najbardziej kłopotliwe do stworzenia. Parsery powinny być bowiem rozszerzalne. Wystarczy spojrzeć na różnice między formatami JSDoc a TypeDoc. Ich składnia jest de facto identyczna, ale już semantyka poszczególnych elementów potrafi się subtelnie różnić. Stąd jeden parser może bezproblemowo sparsować obydwa formaty, ale musi umieć przy tym przetłumaczyć sparsowany kod na poprawną dokumentację. A przecież JSDoc ma sporo odmian, choćby z powodu istnienia kilku różnych parserów w ekosystemie (w tym takich antyków jak jsduck). Nie wspominając już o projektach, które mają swoje własne wariacje na temat dokumentacji w kodzie. Parser będzie musiał to obsłużyć.
  3. Generatory. One będą odpowiedzialne za wyplucie dokumentacji. Tutaj zadanie wydaje się stosunkowo proste i wystarczy podpiąć jakiegoś gotowca, takiego jak Astro czy Eleventy. Tyle teoria, bo w praktyce pewnie nie będzie to aż takie proste. Problem może stanowić format dodatkowej dokumentacji w projekcie. choćby jeżeli ograniczyć to wyłącznie do Markdowna, to jest wiele jego odmian (CommonMark, GFM…). Do tego dochodzą wynalazki pokroju MDX-a. Ktoś też może chcieć nieco zmienić sposób generowania Markdowna. Co oznacza, iż generatory również muszą być do jakiegoś stopnia rozszerzalne.
  4. Motywy. Dokumentacja musi ładnie wyglądać. Zatem muszą istnieć motywy. Tutaj wyzwaniem mogą być ficzery, które muszą coś dodawać do wygenerowanej treści, np. wyszukiwarka, która chce wyświetlić pole wyszukiwania. Motywy muszą mieć więc możliwość dodawania różnych rzeczy w konkretne miejsca layoutu. Musi też istnieć sensowny sposób na nadpisywanie poszczególnych elementów motywu. Można zastosować tutaj podejście z Jekylla: motyw podzielony jest na wiele mniejszych części-plików. Nadpisanie części motywu sprowadza się do stworzenia pliku o nazwie takiej samej jak istniejąca część. Wówczas Jekyll użyje stworzonego przez nas pliku, zamiast tego oryginalnego.
  5. Pluginy. Wszystkie ficzery powinny być dodawane przez pluginy. To oznacza, iż plugin powinien mieć dostęp do pozostałych części – parsera, generatora oraz motywu. Dzięki temu przykładowy plugin wyszukiwarki mógłby dodać do generatora krok związany z indeksacją treści, a następnie umieścić pole wyszukiwania we właściwym miejscu w motywie. A to oznacza, iż pluginy muszą mieć dobrze zaprojektowane API.
  6. Konfiguracja. To ona tak naprawdę będzie miejscem styku z osobą korzystającą z Doco. Dodawanie nowych pluginów, wybieranie motywu, podmienienie parsera – wszystko będzie się odbywać w pliku konfiguracyjnym. Oczywiście, nie ma sensu zmuszać nikogo do mozolnego uzupełniania wszystkiego samemu w każdym nowym projekcie, więc prawdopodobnie skończy się to powstaniem jakiejś paczki pokroju @docojs/config-recommended albo podobnej. Sama konfiguracja pewnie przybierze postać podobną do tej z Rollupa lub ESLinta.

Jeśli przyjrzeć się obecnej zawartości repozytorium Doco, to powyższa lista wydaje się dość podobna do pomysłu, jaki miałem w trakcie konkursu. Nie ma co się jednak za bardzo przywiązywać. prawdopodobnie w trakcie prac niejedno się jeszcze zmieni.

Plan pracy

Nie ma jeszcze jakiegoś rozbudowanego planu pracy. Na pierwszy ogień pójdzie jednak prawdopodobnie API poszczególnych części składowych oraz przemyślenie formatu konfiguracji. Równocześnie pewnie ruszą prace nad “infrastrukturą”, czyli tym, jak powinno funkcjonować monorepo dla projektu. Jak już repo będzie działać, a API będzie w miarę sensownie wyglądać, będzie można wziąć się za poszczególne części składowe. Prawdopodobnie równolegle będzie powstawać parser, jak i generator. Na sam koniec powstanie moduł spinający wszystko w całość.

Czy coś z tego wyjdzie? Zobaczymy. Plan jest, wystarczy go zrealizować.

Idź do oryginalnego materiału