撰寫註解
目的
此儲存庫中的註解是由貢獻者閱讀,時間可能是數個月或數年後,屆時他們將完全沒有你現在所擁有的上下文。此技能定義了該讀者是誰、每種註解的用途,以及哪些模式是被禁止的。
範圍邊界
此技能管理 TypeScript/JavaScript 原始碼中面向貢獻者的註解。它不適用於終端使用者文件:
- 在
packages/astro/src/types/public/config.ts與packages/astro/src/core/errors/errors-data.ts中標記@docs的 JSDoc 區塊,會由外部docgen工具抓取並發布至 Astro 文件網站。請遵循packages/astro/src/core/errors/README.md的規範,並取得文件團隊的審查——當types/public/**變更時,CI 會重新產生參考文件。 types/public/**中的其他 JSDoc 會透過編輯器的 IntelliSense 顯示給使用者。請以建置網站的 Astro 使用者為對象撰寫,而不是閱讀原始碼的貢獻者。
以下內容均針對貢獻者在 HEAD 分支上閱讀的原始碼。
讀者
為一位精通 TypeScript 但無法取得你當前上下文的 Astro 貢獻者撰寫:不是這次對話、不是這個 Pull Request、不是這個 Issue、也不是這個 diff。他們只看見 HEAD 分支上的儲存庫。
這直接導出兩個後果:
- 切勿敘述變更歷史。 像「現在」、「先前」、「不再」、「新方法」這類詞彙在 HEAD 分支上是沒有意義的,因為那裡只有一種方法存在。請陳述程式碼如何運作,而不是它如何演變而來。(
@deprecated標記是例外——請參閱此程式碼庫的慣例——因為它描述了合約的未來,這是讀者需要的資訊。) - 切勿對審查者說話。 一個為你的變更辯護的註解(「這正確處理了 X」)屬於 PR 描述,不屬於原始碼。註解必須永久性地為程式碼的現狀提供理由。
三種註解,三種不同的職責
| 種類 | 語法 | 職責 | 內容 |
|---|---|---|---|
| 檔案 / 模組總覽 | 檔案頂部的 /** */ | 解釋 | 模組存在的原因、定義的概念與術語、各部分如何關聯、設計理由 |
| 項目文件 | 宣告上方的 /** */ | 參考 | 合約:行為、參數、回傳值、拋出的錯誤、不變量。中立且基於事實。 |
| 行內註解 | 主體內的 // | 理由 | 僅包含程式碼無法說明的內容:限制條件、替代方案(附 Issue 連結)、不明顯的耦合關係 |
請勿混淆職責。實作細節不屬於 /** */ 合約——請將它們放在主體內作為 // 註解。合約不應該散落在行內註解中——請將它放在宣告上。
行為文件
當需要項目文件時,請為人類讀者撰寫合約,而不是作為實作的翻譯。這並不要求每個函式都有 JSDoc;名稱、型別與結構本身就應該能承載直接的行為。
- 以白話描述函式回傳或達成的目標。
- 使用短到中等的句子,每個句子包含一個主要想法。
- 當呼叫者不需要時,避免使用 Astro 內部術語。如果必須使用技術術語,請在同一段落中解釋。
- 描述可能令人驚訝的、呼叫者可見的注意事項:備援行為、工作限制、模糊結果、多載順序、副作用,以及會回傳
undefined、null、空結果或其他不確定值的條件。 - 當呼叫者預期要區分或從中恢復時,記錄拋出的錯誤。
- 除非呼叫者需要理解行為或安全使用 API,否則不要描述實作細節。
當行為依賴於簽名無法清楚顯示的關係時,請加入範例。常見的 Astro 與 TypeScript 情況包括:
- 選擇了哪個多載;
- 引數如何對應到可選或其餘參數;
- 哪個公開的 Astro 進入點暴露了在其他地方實作或重新匯出的符號;
- 模糊路由、不完整設定或遺失內容的備援行為;
- 結果的意義從其型別無法看出的情況。
在程式碼區塊之前以散文介紹範例。說明它展示的內容以及預期的結果。保持程式碼片段簡短、自給自足,並從 Astro 使用者或擁有該合約的內部呼叫者的角度撰寫。
模組文件應描述一個持久的觀念、架構邊界或設計理由。請勿為了總結檔案而列出各個匯出名稱;當符號被新增或重新命名時,這種清單會過時。如果一個模組沒有可解釋的持久觀念,請使用簡短的一行描述或省略總覽。
刪除測試
在撰寫任何註解之前,請問:這是否說明了讀者無法從程式碼本身恢復的資訊?
- 如果資訊已由名稱、型別或結構承載,請勿撰寫註解。如果名稱無法承載,請改進名稱。
- 合法需要註解的資訊:不變量、理由、與其他地方程式碼的耦合、附連結的替代方案、相依套件的驚人行為、模組定義的術語。
在後續編輯時,同樣的測試也適用於反向:不再通過測試的註解應被刪除,而不是任其過時。
為替代方案連結 Issue
此程式碼庫一致地將替代方案錨定到一個來源。任何解釋替代方案、HACK、回歸防護或相依套件驚人行為的註解必須連結驅動它的 GitHub Issue 或 PR。這個連結能讓未來的讀者判斷替代方案是否仍然需要。
// Handle recommended nanostores. Only @nanostores/preact is required from our testing!
// Full explanation and related bug report: https://github.com/withastro/astro/pull/3667
'@nanostores/preact',
沒有連結的替代方案與錯誤無異。
禁止的模式
敘述下一行。 見即刪除:
// 遞增世代計數器
generation += 1;
敘述變更歷史。 改寫為現在式的理由:
// 錯誤:我們現在從使用者根目錄解析 lightningcss,而不是我們的根目錄。
// 正確:lightningcss 是一個可選的 peer 依賴,因此它從使用者的專案根目錄解析。
對審查者的論證。 將論點移至 PR:
// 錯誤:這正確處理了錯誤報告中的多重編碼路徑。
// 正確:在 MAX_DECODE_ITERATIONS 之後仍未完全解碼的路徑會被拒絕,因此
// middleware 與路由永遠不會對解碼後的路徑產生分歧。
複述 JSDoc。 一個重複宣告名稱的 /** */ 區塊毫無意義:
// 錯誤:
/** 編譯樣式。 */
function compileStyles(...)
// 正確:
/** 相對於 `base` 重寫 `css` 中的相對 `url()` 參考,保留
* 絕對與 data URL 不變。 */
function compileStyles(...)
模糊的保留用語。 「某些情況」、「各種原因」、「處理邊界情況」、「等等」——請明確指出或刪除該句子。
表情符號。 在原始碼與註解中禁止使用(儲存庫全域政策)。
臨時章節標題(// ----- helpers -----、// ==== TYPES ====)。此程式碼庫沒有 // #region 摺疊慣例;請勿新增標題。如果一個檔案長到讓你想使用標題,這表示應該拆分檔案,而不是裝飾它。
此程式碼庫的慣例
JSDoc 標籤。 @param name - description、@returns 與 @throws 陳述合約。僅在簽名本身不明確時才用大括號包裹型別(@returns {Promise<string>})。對於不明顯的使用方式,請使用 @example 搭配圍欄 ```js 區塊。
交叉參考。 使用 {@link Symbol} / {@linkcode Symbol},而不是裸名稱,這樣重新命名時會更新參考,且編輯器可以跳轉到目標。
@internal。 標記不屬於公開介面的 API。這只是一個慣例——這裡沒有 typedoc 或 api-extractor 來移除它——因此它記錄了意圖,但不會取代存取修飾詞。
@deprecated。 說明遷移方式,然後說明移除時間:
/** @deprecated 請改用實例方法 `cookies.consume()`。這將在 Astro 7 中移除 */
說明要使用什麼來取代,而不僅僅是標籤已棄用。這個未來式的備註是讀者需要的合約資訊,不是被禁止的變更歷史敘述。
TODO。 使用 // TODO: 表示延遲的工作;當有 Issue 追蹤時連結該 Issue。對於取決於重大變更視窗的工作,請使用已建立的慣用語 // TODO: remove in Astro <N>。此程式碼庫沒有 FIXME——請勿引入。
編輯現有程式碼
- 保留現有註解。如果你的變更改變了行為,請擴充或修正特定散文——切勿用通用文字取代。刪除得來不易的上下文比留下稍微過時的註解更糟。
- 當你的變更使註解變得不正確時,請在同一個 diff 中修正它。一個過時的註解比沒有註解更糟。
- 比照周圍的密度。一個文件豐富的模組應在新項目上保持相同水準;請勿在稀疏的模組上四處加上註解。
完成前的自我檢查
在完成任何與註解相關的任務後,請隔離程式碼變更,僅重新閱讀你 diff 中的註解:
- 每個註解是否都通過了刪除測試?
- 是否有任何註解參考了對話、變更本身或審查者?
- 每個替代方案是否都連結了它的 Issue 或 PR?
- 一個無法存取 diff 的讀者是否能理解每個註解?
修正或刪除未通過的項目。刪除是預設選項;缺少一個註解比一個誤導性的註解更便宜。
參考資料
- Diátaxis——支撐上述解釋/參考/理由分類的框架。
packages/astro/src/core/errors/README.md——適用於標記@docs的錯誤條目,這些是終端使用者文件。- TSDoc——TypeScript 文件註解的標籤參考。