Lompat ke konten
dokumentasi.id
Commit 3ce63fd
v3
Star5,3 rb

4

Pipeline Build Markdown

src/build.ts adalah satu skrip Bun yang dijalankan lewat bun run src/build.ts (package.json:36-42). 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-10).

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.
Fig. 1: Siklus build dari JSON ke READMEbuild.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-16). resolve merakit path dengan data sebagai akar (src/utils/index.ts:5-7). Penelusuran berjalan rekursif: setiap berkas berekstensi .json masuk fileList, setiap direktori ditelusuri lagi (src/utils/index.ts:19-31).

Isi setiap berkas dibaca sebagai CategoryType, lalu json.apis diurutkan menaik dengan localeCompare pada apiName (src/build.ts:13-18). Hasil sort langsung dipersist: Bun.write(file, JSON.stringify(json, undefined, 2)) menimpa berkas sumber dengan indentasi dua spasi (src/build.ts:77). 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-11). Setiap kategori lalu dikelompokkan ke data[language] (src/build.ts:79-83), sesuai bentuk ListType yang memetakan satu key bahasa ke daftar kategori (src/types.ts:15-17). 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-75). 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-91). 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-90). Pengurutan kategori inilah yang menentukan urutan bagian pada daftar isi, misalnya Agama Islam muncul sebelum Berita (README.md:15-19).

Template memuat dua pasang marker komentar yang menjadi sasaran penggantian: <!-- TOC START --> (README.md:13) dan <!-- API START --> (README.md:46). Kedua blok diisi oleh dua replace berurutan.

UrutanVariabel regexMarker yang digantiPengisi
1apiRegex<!-- API START --> sampai <!-- API END -->markdownBuilder(categories, language) (src/build.ts:96-98)
2tocRegex<!-- TOC START --> sampai <!-- TOC END -->generateToc(result) (src/build.ts:101-103)

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:12), lalu tabel enam kolom: nama API, pengembang, dokumentasi, status, deskripsi, dan autentikasi (src/utils/markdown.ts:8-33). Label kolom berasal dari translate, sedangkan authentication yang kosong diisi false dan status boolean dipetakan menjadi ✅ atau ❎ (src/utils/markdown.ts:19-26).

Mengapa daftar isi disusun belakangan

generateToc menerima result yang sudah berisi blok API, bukan template kosong (src/build.ts:101-103). Fungsi itu memindai seluruh heading #{1,6} pada result (src/utils/markdown.ts:36-45), 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-54).

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.
Fig. 2: Urutan dua blok replaceBlok 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:105). Langkah terakhir memanggil Bun.spawn(['bun', 'format']) (src/build.ts:108-109), dan script format berisi prettier --write . dengan konfigurasi printWidth 100 serta singleQuote aktif (package.json:26-35).

⚠️ bun format menjalankan prettier --write . pada seluruh repository, bukan hanya README, dan fase 1 sudah menimpa berkas di data/ sebelum itu. Jalankan build di branch bersih dan periksa git status setelahnya agar perubahan format tidak tercampur perubahan data.

Dipanggil tanpa await, sehingga skrip selesai lebih dulu daripada prettier (src/build.ts:108-109). Perubahan berkas akibat format baru terlihat setelah subprocess itu selesai.