'use strict';
// 固定留言模板:本 action 發到 PR 的留言一律由此產生(繁體中文、UTF-8、表格優先)。
// 隱藏標記:辨識哪些留言是本 action 發的(步驟 2 標註過時時使用)。
const MARK = '';
// 舊留言標註前綴(步驟 2 的降級做法:無 resolve API 時編輯加註)。
const OUTDATED_PREFIX = '> 〔已過時〕本留言屬於較舊的審查回合。\n\n';
// 嚴重等級對應的 emoji 與排序權重。
const SEVERITY_EMOJI = { 嚴重: '🔴', 警告: '🟠', 建議: '🔵' };
const SEVERITY_ORDER = { 嚴重: 0, 警告: 1, 建議: 2 };
// 面向代碼對應的中文標籤。
const FOCUS_LABEL = {
logic: '邏輯',
security: '安全性',
efficiency: '效率',
style: '風格',
testing: '測試',
maintainability: '可維護性',
verdict: '裁決',
};
/**
* 把任意文字整理成可安全放進 Markdown 表格儲存格的單行內容。
*
* 處理順序:nullish 轉空字串 → 逸出管線符號(`|` → `\|`)→ 換行轉 `
`
* → 去除頭尾空白 → 空字串以 `—` 佔位。純函式、無副作用,任何輸入
* (含 null/undefined/數字)都不會拋出例外。
*
* @param {*} text - 任意待處理內容;非字串會先以 `String()` 轉型,null/undefined 視為空字串。
* @returns {string} 已逸出、單行化的儲存格內容;若結果為空則回傳 `'—'`。
* @remarks
* 使用情境:審查流程中所有表格型留言的共用防呆——例如步驟 4 的
* `diffComment()` 產生變更摘要表格時,檔名與用途欄位都經本函式處理,
* 避免檔名或 AI 產生的描述含 `|` 或換行而撐破 Markdown 表格。
* 本函式未匯出,僅供模組內部使用。
*/
function cell(text) {
return String(text ?? '')
.replace(/\|/g, '\\|')
.replace(/\r?\n/g, '
')
.trim() || '—';
}
/**
* 把審查面向代碼轉成「中文(原文)」的顯示字串。
*
* 以模組常數 `FOCUS_LABEL` 查表,支援 logic/security/efficiency/
* style/testing/maintainability/verdict 七種代碼;查表命中回傳
* 「中文(代碼)」格式,未命中則原樣回傳代碼,falsy 輸入回傳 `—`。
*
* @param {string} focus - 審查面向代碼(例如 `'logic'`、`'security'`);可為 undefined。
* @returns {string} 顯示字串:命中時如 `'邏輯(logic)'`;未命中時原樣回傳 `focus`;falsy 時回傳 `'—'`。
* @remarks
* 使用情境:審查流程步驟 5/7 的角色登場留言——`rolesComment()`
* 產生「角色|面向|個性」表格時,以本函式把每位審查員
* (攻擊方/防守方)的 focus 代碼轉成中英並列的面向欄位內容。
* 本函式未匯出,僅供模組內部使用。
*/
function focusLabel(focus) {
const label = FOCUS_LABEL[focus];
return label ? `${label}(${focus})` : focus || '—';
}
/**
* 產生審查流程步驟 3 的「審查工具」PR 留言內容。
*
* 留言以隱藏標記 `MARK` 開頭,包含工具資訊表格(工具/版本/模型/
* 審查 commit/Run Job 連結)與一張 mermaid 流程圖,說明整條審查管線
* (整理 git diff → 攻擊方找問題 → 防守方裁決 → 保存 findings → 留言到 PR)。
*
* @param {Object} params - 工具資訊(解構參數)。
* @param {string} params.toolName - 審查工具名稱,直接以行內程式碼呈現(不經 cell 逸出)。
* @param {string} params.version - 工具版本;經 cell() 防呆。
* @param {string} [params.model] - 使用的 AI 模型;falsy 時顯示「(工具預設)」。
* @param {string} params.sha - 本回合審查的 commit SHA;經 cell() 防呆。
* @param {string|number} params.runNumber - CI run 編號,作為連結文字;經 cell() 防呆。
* @param {string} params.runLink - CI run 的網址,直接內插為 Markdown 連結目標。
* @returns {string} 完整留言 Markdown 字串(含 MARK 隱藏標記,結尾帶換行)。
* @remarks
* 使用情境:審查流程步驟 3——每回合審查開始時,先把工具身分與
* 管線流程圖留言到 PR,讓開發者知道這回合由哪個版本/模型執行;
* 留言開頭的 MARK 讓步驟 2 能辨識並將舊回合留言標註為過時。
*/
function toolComment({ toolName, version, model, sha, runNumber, runLink }) {
return `${MARK}
## 🤖 AI Code Review|審查工具
| 項目 | 內容 |
| --- | --- |
| 工具 | \`${toolName}\` |
| 版本 | \`${cell(version)}\` |
| 模型 | ${model ? `\`${cell(model)}\`` : '(工具預設)'} |
| 審查 commit | \`${cell(sha)}\` |
| Run Job | [#${cell(runNumber)}](${runLink}) |
\`\`\`mermaid
flowchart LR
A[整理 git diff] --> B[⚔️ 攻擊方找問題]
B --> C[🛡️ 防守方裁決]
C --> D[保存 findings]
D --> E[留言到 PR]
\`\`\`
`;
}
/**
* 產生審查流程步驟 4 的「變更摘要(送審 git diff)」PR 留言內容。
*
* 以四欄表格(檔案/用途/git diff 長度/最後更新時間)列出本回合
* 送審的每個檔案;diff 過長被截斷送審的檔案會加註「(過長截斷送審)」,
* 無任何檔案時補上「(無)」佔位列。結尾以引言統計納入審查的檔案數,
* 並在有排除檔案時註明 `.reviewignore` 排除數量。
*
* @param {Array