4
Pipeline Build Markdown
src/build.ts adalah satu skrip Bun yang dijalankan lewat bun run src/build.ts (package.json:36-421). Skrip itu bekerja dalam tiga fase berurutan: membaca seluruh berkas data/**/*.json lalu menuliskannya kembali, menyusun blok API dan daftar isi di README, kemudian memanggil prettier. Keadaan antar-fase disimpan di variabel tingkat modul data, crawledx, crawled, dan agent (src/build.ts:7-102).
Satu siklus build penuh
Diagram berikut menelusuri satu kali eksekusi build.ts, dari pemanggilan getFiles sampai subprocess prettier.
sequenceDiagram
autonumber
participant B as build.ts
participant FS as getFiles
participant J as berkas JSON
participant MD as markdownBuilder
participant TC as generateToc
participant RM as README template
participant PR as prettier
B->>FS: panggil getFiles tanpa argumen
FS-->>B: fileList semua berkas .json
loop setiap berkas
B->>J: Bun.file(file).json()
B->>B: json.apis.sort pada apiName
B->>J: Bun.write versi terurut
B->>B: data[language].push(json)
end
loop setiap key language
B->>B: categories.sort pada categoryName
B->>RM: Bun.file(filePath).text()
RM-->>B: markdown dengan marker
B->>MD: markdownBuilder(categories, language)
MD-->>B: heading kategori plus tabel
B->>B: replace apiRegex
B->>TC: generateToc(result)
TC-->>B: daftar tautan heading
B->>B: replace tocRegex
B->>RM: Bun.write(filePath, result)
end
B->>PR: Bun.spawn bun format
%% fig: Siklus build dari JSON ke README
%% desc: build.ts menulis ulang setiap berkas JSON, menyusun blok API dan daftar isi per bahasa, lalu menjalankan prettier.Tiga fase itu punya dua titik serah yang menentukan hasil akhir: berkas JSON ditulis ulang sebelum markdown dibangun, dan daftar isi disusun setelah blok API terisi.
Fase 1: membaca dan menulis ulang JSON
getFiles dipanggil tanpa argumen, sehingga dirPath memakai nilai default resolve() yang menunjuk direktori data (src/utils/index.ts:13-163). resolve merakit path dengan data sebagai akar (src/utils/index.ts:5-74). Penelusuran berjalan rekursif: setiap berkas berekstensi .json masuk fileList, setiap direktori ditelusuri lagi (src/utils/index.ts:19-315).
Isi setiap berkas dibaca sebagai CategoryType, lalu json.apis diurutkan menaik dengan localeCompare pada apiName (src/build.ts:13-186). Hasil sort langsung dipersist: Bun.write(file, JSON.stringify(json, undefined, 2)) menimpa berkas sumber dengan indentasi dua spasi (src/build.ts:777). Karena urutannya sudah dibakukan di disk, README selalu dibangun dari data yang terurut dan diff pada commit berikutnya hanya memuat perubahan isi.
Nama bahasa diambil dari nama berkas lewat getLanguage, yang memakai path.basename tanpa ekstensi (src/utils/index.ts:9-118). Setiap kategori lalu dikelompokkan ke data[language] (src/build.ts:79-839), sesuai bentuk ListType yang memetakan satu key bahasa ke daftar kategori (src/types.ts:15-1710). Jadi data/books/id.json menjadi data.id, sedangkan data/books/en.json menjadi data.en.
Mode --rewrite berjalan di dalam loop yang sama (src/build.ts:20-7511). Pembahasan lengkapnya ada di Mode Rewrite dan Status API.
Fase 2: menyusun blok API dan daftar isi
Fase kedua mengulang setiap key language pada data, mengurutkan kategori dengan localeCompare pada categoryName, lalu membaca berkas README sebagai template (src/build.ts:87-9112). Nama berkas tujuan dirakit dari ['README', language === 'id' ? null : language, 'md'].filter(...): bahasa id menghasilkan README.md, bahasa lain menghasilkan README.en.md (src/build.ts:89-9013). Pengurutan kategori inilah yang menentukan urutan bagian pada daftar isi, misalnya Agama Islam muncul sebelum Berita (README.md:15-1914).
Template memuat dua pasang marker komentar yang menjadi sasaran penggantian: <!-- TOC START --> (README.md:1315) dan <!-- API START --> (README.md:4616). Kedua blok diisi oleh dua replace berurutan.
| Urutan | Variabel regex | Marker yang diganti | Pengisi |
|---|---|---|---|
| 1 | apiRegex | <!-- API START --> sampai <!-- API END --> | markdownBuilder(categories, language) (src/build.ts:96-9817) |
| 2 | tocRegex | <!-- TOC START --> sampai <!-- TOC END --> | generateToc(result) (src/build.ts:101-10318) |
Kedua regex memakai flag gm dan mengganti isi blok dengan pola $1, isi baru, $3, sehingga pasangan marker tetap utuh di berkas hasil. markdownBuilder menyusun satu heading ### <categoryName> per kategori (src/utils/markdown.ts:1219), lalu tabel enam kolom: nama API, pengembang, dokumentasi, status, deskripsi, dan autentikasi (src/utils/markdown.ts:8-3320). Label kolom berasal dari translate, sedangkan authentication yang kosong diisi false dan status boolean dipetakan menjadi ✅ atau ❎ (src/utils/markdown.ts:19-2621).
Mengapa daftar isi disusun belakangan
generateToc menerima result yang sudah berisi blok API, bukan template kosong (src/build.ts:101-10318). Fungsi itu memindai seluruh heading #{1,6} pada result (src/utils/markdown.ts:36-4522), sehingga heading kategori hasil markdownBuilder ikut terdaftar. Tautan dibentuk dari teks heading yang di-lowercase dan spasinya diganti -, dengan dua spasi indentasi per tingkat heading (src/utils/markdown.ts:47-5423).
graph TD
A["markdown template dengan marker API dan TOC"] --> B["replace apiRegex"]
B --> C["markdownBuilder(categories, language)"]
C --> D["result dengan blok API terisi"]
D --> E["generateToc(result)"]
E --> F["replace tocRegex"]
F --> G["Bun.write(filePath, result)"]
style A fill:#8b5cf6,color:#fff
style B fill:#f59e0b,color:#000
style C fill:#f59e0b,color:#000
style D fill:#2d7d46,color:#fff
style E fill:#f59e0b,color:#000
style F fill:#f59e0b,color:#000
style G fill:#336791,color:#fff
%% fig: Urutan dua blok replace
%% desc: Blok API diisi lebih dahulu, lalu generateToc membaca hasilnya sehingga heading kategori ikut masuk daftar isi sebelum berkas ditulis.Fase 3: penyimpanan dan format
Setelah kedua blok terisi, Bun.write(filePath, result) menimpa berkas README bahasa tersebut (src/build.ts:10524). Langkah terakhir memanggil Bun.spawn(['bun', 'format']) (src/build.ts:108-10925), dan script format berisi prettier --write . dengan konfigurasi printWidth 100 serta singleQuote aktif (package.json:26-3526).
⚠️
bun formatmenjalankanprettier --write .pada seluruh repository, bukan hanya README, dan fase 1 sudah menimpa berkas didata/sebelum itu. Jalankan build dibranchbersih dan periksagit statussetelahnya agar perubahan format tidak tercampur perubahan data.
Dipanggil tanpa await, sehingga skrip selesai lebih dulu daripada prettier (src/build.ts:108-10925). Perubahan berkas akibat format baru terlihat setelah subprocess itu selesai.