89 lines
5.1 KiB
JavaScript
89 lines
5.1 KiB
JavaScript
'use strict';
|
||
|
||
// 共用時間與日誌工具:所有訊息輸出統一為 [yyyy/MM/dd HH:mm:ss][階段][等級]: 訊息(Asia/Taipei)。
|
||
|
||
/**
|
||
* 將指定時間轉為台北時區(Asia/Taipei)的顯示字串,格式固定為 yyyy/MM/dd HH:mm:ss(24 小時制)。
|
||
* 利用 sv-SE 語系的 toLocaleString 產生 yyyy-MM-dd HH:mm:ss 後再把「-」換成「/」,
|
||
* 輸出不受執行環境(CI runner/主機)系統時區影響。
|
||
*
|
||
* @param {Date} [date=new Date()] 要格式化的時間;省略時使用現在時間。
|
||
* 須為有效的 Date 物件;傳入 Invalid Date 會得到 "Invalid Date" 字串(不丟例外),
|
||
* 傳入非 Date 型別屬誤用,可能丟出 TypeError。
|
||
* @returns {string} 台北時區的時間字串,格式 yyyy/MM/dd HH:mm:ss(例如 "2026/07/17 14:30:05")。
|
||
* @remarks
|
||
* 使用情境:log() 每次輸出日誌時呼叫本函式產生時間戳前綴;
|
||
* taipeiFromIso() 也在解析 ISO 字串成功後委派給本函式做最終格式化。
|
||
* 前置條件:無(純函式、無副作用);需要固定顯示格式的時間字串時皆可直接呼叫。
|
||
* 注意:格式與 JSC 規範「更新時間一律 Asia/Taipei、yyyy/MM/dd HH:mm:ss」一致,勿自行改動分隔符號。
|
||
*/
|
||
function taipeiNow(date = new Date()) {
|
||
return date
|
||
.toLocaleString('sv-SE', { timeZone: 'Asia/Taipei', hour12: false })
|
||
.replace(/-/g, '/');
|
||
}
|
||
|
||
/**
|
||
* 產生檔名用的台北時區時間戳,格式固定為 yyyy-MM-dd-HH:mm:ss(24 小時制),
|
||
* 即把 sv-SE 格式(yyyy-MM-dd HH:mm:ss)中的空白換成「-」,避免檔名含空白。
|
||
* 主要供 AI review findings 輸出檔的檔名命名使用。
|
||
*
|
||
* @param {Date} [date=new Date()] 要格式化的時間;省略時使用現在時間。
|
||
* 須為有效的 Date 物件;傳入 Invalid Date 會得到 "Invalid-Date" 字串(不丟例外),
|
||
* 傳入非 Date 型別屬誤用,可能丟出 TypeError。
|
||
* @returns {string} 檔名用時間戳字串,格式 yyyy-MM-dd-HH:mm:ss(例如 "2026-07-17-14:30:05")。
|
||
* @remarks
|
||
* 使用情境:產生 findings 檔案(如 .gitea/ai-review 下的輸出檔)時呼叫,
|
||
* 讓檔名帶有可排序的建立時間。前置條件:無(純函式、無副作用)。
|
||
* 注意:輸出仍含「:」字元,在 Linux 檔名合法,但不可移植到 Windows 檔案系統;
|
||
* 若未來需跨平台檔名,需另行替換「:」。
|
||
*/
|
||
function taipeiFileStamp(date = new Date()) {
|
||
return date
|
||
.toLocaleString('sv-SE', { timeZone: 'Asia/Taipei', hour12: false })
|
||
.replace(' ', '-');
|
||
}
|
||
|
||
/**
|
||
* 將 ISO 8601 時間字串轉為台北時區(Asia/Taipei)的顯示字串(yyyy/MM/dd HH:mm:ss);
|
||
* 輸入為空或無法解析時回傳佔位符「—」,不丟例外,適合直接嵌入報表或留言等顯示用文字。
|
||
*
|
||
* @param {string | null | undefined} iso ISO 8601 時間字串(例如 "2026-07-17T06:30:05Z")。
|
||
* 可為 null/undefined/空字串,皆視為無資料而回傳「—」。
|
||
* 實作上接受任何 Date 建構子可解析的輸入,但非 ISO 格式的解析結果依 JS 引擎而異,建議一律傳 ISO 字串。
|
||
* @returns {string} 台北時區時間字串(yyyy/MM/dd HH:mm:ss),或無法解析時的佔位符 "—"。
|
||
* @remarks
|
||
* 使用情境:顯示外部系統(如 Gitea API、AI 服務回應)帶回的 UTC/ISO 時間欄位時呼叫,
|
||
* 統一轉成台北時區給人閱讀;來源欄位可能缺值,故以「—」佔位而非丟例外。
|
||
* 前置條件:無;結果僅供顯示,不應再拿去做時間運算(需運算請直接使用原始 ISO 值)。
|
||
*/
|
||
function taipeiFromIso(iso) {
|
||
if (!iso) return '—';
|
||
const date = new Date(iso);
|
||
return Number.isNaN(date.getTime()) ? '—' : taipeiNow(date);
|
||
}
|
||
|
||
/**
|
||
* 以專案統一格式輸出一行日誌到標準輸出:[yyyy/MM/dd HH:mm:ss][階段][等級]: 訊息,
|
||
* 時間戳固定為台北時區(Asia/Taipei)24 小時制;stage 為空時整個 [階段] 區塊省略。
|
||
*
|
||
* @param {string | null | undefined} stage 階段名稱(例如 "步驟1"、"收尾");
|
||
* 傳空字串/null/undefined 時省略 [階段] 區塊。
|
||
* @param {string} level 日誌等級,約定限 "INF"、"WRN"、"ERR"、"TRC"、"DBG" 五種;
|
||
* 程式碼未驗證,傳入其他字串會原樣輸出,遵守約定由呼叫端負責。
|
||
* @param {string} message 日誌訊息內容;非字串會被隱式轉字串(物件會變成 "[object Object]"),
|
||
* 請由呼叫端先自行序列化。
|
||
* @returns {void} 無回傳值;副作用為寫一行到 stdout。
|
||
* @remarks
|
||
* 使用情境:action 執行過程中的所有訊息輸出都應改呼叫本函式而非直接 console.log,
|
||
* 讓 CI(Gitea Actions)log 具備一致的時間戳與等級標記、一行一則。
|
||
* 注意:所有等級(含 ERR)都輸出到 stdout 而非 stderr;此格式對應 JSC 的
|
||
* spec-time-log 輸出規範,勿自行變更括號與冒號排版。
|
||
*/
|
||
function log(stage, level, message) {
|
||
const stagePart = stage ? `[${stage}]` : '';
|
||
console.log(`[${taipeiNow()}]${stagePart}[${level}]: ${message}`);
|
||
}
|
||
|
||
module.exports = { taipeiNow, taipeiFileStamp, taipeiFromIso, log };
|