docs(ai-code-review): 補齊各模組 JSDoc、指令檔逐行註解並重建 README

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jeffery
2026-06-26 14:16:04 +08:00
co-authored by Claude Opus 4.8
parent 303104bb20
commit 1378f03595
18 changed files with 2243 additions and 68 deletions
+48 -5
View File
@@ -13,7 +13,15 @@ const FIELD_PATTERNS = {
建議: /\*\*建議\*\*[:]\s*(.+)/,
};
/** 取出 "**label**value" 這一行的 value(單行)。 */
/**
* 從 Markdown 內文擷取單行欄位值,對應格式為 `**標籤**:value`(全形或半形冒號皆可)。
* 僅支援預先編譯於 FIELD_PATTERNS 的標籤:嚴重等級/等級/審查員/問題/建議;
* 標籤不在表內或無命中時回傳空字串。
* @param {string} body - 已正規化換行(\n)的留言內文;呼叫端須先確保為字串。
* @param {('嚴重等級'|'等級'|'審查員'|'問題'|'建議')} label - 要擷取的欄位標籤鍵。
* @returns {string} 該行的 value(已 trim);找不到或標籤不支援時為 ''。
* @remarks 正則為靜態定義,避免每次呼叫重建並排除以外部輸入動態組 regex 的注入風險。
*/
function fieldValue(body, label) {
const re = FIELD_PATTERNS[label];
if (!re) return '';
@@ -21,6 +29,12 @@ function fieldValue(body, label) {
return m ? m[1].trim() : '';
}
/**
* 將中文嚴重等級描述(如「嚴重」「警告」「建議」)映射為內部標準鍵。
* 採子字串比對且依序判斷,第一個命中者勝出。
* @param {string} raw - 來自留言的嚴重等級文字(可能為空)。
* @returns {('critical'|'warning'|'info'|null)} 對應的內部鍵;空字串或無法辨識時回傳 null。
*/
function levelToKey(raw) {
if (!raw) return null;
if (raw.includes('嚴重')) return 'critical';
@@ -124,12 +138,24 @@ export async function judgeConversations(items, chatFn = chatJSON) {
return items.map(it => ({ idx: it.idx, verdict: byIdx.get(it.idx) || 'open' }));
}
/**
* 將一段仍成立(open)對話對應的 bot finding 加入結轉清單,標記 is_new=false 表示為延續的舊問題。
* 若該對話無 botFinding 則不做任何事。
* @param {Array<object>} target - 接收結轉 finding 的陣列(會被就地 push)。
* @param {{botFinding: object|null}} conversation - 對話群組(取其 botFinding)。
* @returns {void}
*/
function pushCarried(target, conversation) {
if (!conversation.botFinding) return;
target.push({ ...conversation.botFinding, is_new: false });
}
/** 把判定為誤報的 bot finding 轉成 exclusions.json 的排除條目。 */
/**
* 將判定為誤報的 bot finding 轉成 exclusions.json 的排除條目。
* original_finding 取 suggestion,缺則退回 problem 再退回空字串;reason 為固定的誤報說明。
* @param {{location: string, role: string, suggestion?: string, problem?: string}} botFinding - 被判為誤報的 finding(呼叫端須確保非 null)。
* @returns {{location: string, role: string, original_finding: string, reason: string}} 排除條目。
*/
function toExclusion(botFinding) {
return {
location: botFinding.location,
@@ -140,8 +166,10 @@ function toExclusion(botFinding) {
}
/**
* 僅允許 repo 內的相對路徑:排除絕對路徑/ 或 Windows 磁碟機與含 `..` 的路徑穿越。
* comment 的 path 源自外部PR 檔名),用此守衛避免被用來讀取 repo 外的檔案。
* 安全守衛:判定路徑是否為 repo 內的相對路徑(拒絕絕對路徑Windows 磁碟機前綴與含 `..` 的路徑穿越
* 用於防止以外部 PR 檔名讀取 repo 外的檔案。
* @param {string} p - 待檢查的檔案路徑。
* @returns {boolean} 安全(repo 內相對路徑)為 true,否則 false。
*/
function isSafeRepoPath(p) {
if (typeof p !== 'string' || p === '') return false;
@@ -263,10 +291,21 @@ export async function reconcileConversations(deps = {}) {
};
}
/**
* 從 location(格式 `path:line`)取出檔案路徑部分(以第一個冒號切割並 trim)。
* @param {string} location - 位置字串,可能為 `path:line` 或僅 `path`(容許 null/undefined)。
* @returns {string} 檔案路徑;無輸入時為空字串。
*/
function fileOf(location) {
return String(location || '').split(':')[0].trim();
}
/**
* 將文字正規化為穩定比對鍵:NFKC 正規化後移除所有標點/符號/空白,再 trim 並轉小寫。
* 用於讓 finding 簽章對標點與空白差異不敏感。
* @param {string} text - 待正規化文字(容許 null/undefined)。
* @returns {string} 正規化後的小寫鍵。
*/
function normalizeKey(text) {
return String(text || '')
.normalize('NFKC')
@@ -275,7 +314,11 @@ function normalizeKey(text) {
.toLowerCase();
}
/** 以「檔案路徑 + 正規化建議內容」為簽章,對 line 漂移與標點差異穩定。 */
/**
* 計算 finding 的去重簽章:以「檔案路徑 + 正規化建議內容」組成,對行號漂移與標點差異穩定。
* @param {{location?: string, suggestion?: string}} f - finding 物件(容許欄位缺漏)。
* @returns {string} 形如 `檔案路徑|正規化建議` 的簽章字串。
*/
function findingSig(f) {
return `${fileOf(f?.location)}|${normalizeKey(f?.suggestion)}`;
}