/** * Portal 溯源 scheme 測試(daemon-beta t21 — kb:// vs gitea:// 斷鏈地雷) * * 驗的是 src/portal-ui.ts 內嵌客戶端 JS 的 srcHref / srcLocalPath: * gitea:// → {base}/(舊 rag_ingest v2 實形,行為不回歸) * gitea:@ → {base}//src/branch/main/(km-wiki-ingest 實形, * 見 registry/examples/km-wiki-ingest/workflow.yaml `gitea:${repo}@${relPath}`) * kb:// → 不造連結(雲端無對應網頁),srcLocalPath 給本地路徑文字, * UI 標「在你的同步資料夾內」(arcrun-rag rag-ingest.yaml `'kb://' + path`) * * 測法:從 portal-ui.ts 的 template literal 抽出三個函式原始碼(brace 平衡掃描), * 還原 template 跳脫(`\\` → `\`)後用 new Function 求值——測的就是真正會被 * build 進 public/portal/index.html 的那份 JS,零外部依賴(console-ui 哲學)。 */ import { test } from 'node:test'; import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; const HERE = dirname(fileURLToPath(import.meta.url)); const SRC = readFileSync(join(HERE, '..', 'src', 'portal-ui.ts'), 'utf8'); /** 從原始碼抽出 `function (...) { ... }` 全文(brace 平衡;函式體無字串內大括號)。 */ function extractFn(name) { const start = SRC.indexOf(`function ${name}(`); assert.ok(start >= 0, `portal-ui.ts 找不到 function ${name}`); const braceStart = SRC.indexOf('{', SRC.indexOf(')', start)); let i = braceStart + 1; let depth = 1; while (i < SRC.length && depth > 0) { if (SRC[i] === '{') depth++; else if (SRC[i] === '}') depth--; i++; } // template literal 內的 `\\` 在產出 HTML 時是 `\`——還原成瀏覽器實際跑的 JS return SRC.slice(start, i).replace(/\\\\/g, '\\'); } /** 用指定 SOURCE_WEB_BASE 建出真正的 srcHref / srcLocalPath。 */ function makeFns(base) { const code = [extractFn('encSrcPath'), extractFn('srcHref'), extractFn('srcLocalPath')].join('\n'); return new Function('SOURCE_WEB_BASE', `${code}\nreturn { srcHref, srcLocalPath };`)(base); } const BASE = 'https://gitea.example.com'; test('gitea://(舊 rag_ingest v2)— 現行為不回歸:base + path、#n 錨點捨棄', () => { const { srcHref } = makeFns(BASE + '/'); // 尾斜線要被吃掉 assert.equal(srcHref('gitea://system-dev/wiki/foo.md'), `${BASE}/system-dev/wiki/foo.md`); assert.equal(srcHref('gitea://system-dev/wiki/foo.md#3'), `${BASE}/system-dev/wiki/foo.md`); // 中文路徑逐段 encode assert.equal(srcHref('gitea://docs/員工手冊.md'), `${BASE}/docs/${encodeURIComponent('員工手冊.md')}`); }); test('gitea:@(km-wiki-ingest)— base//src/branch/main/', () => { const { srcHref } = makeFns(BASE); assert.equal( srcHref('gitea:Leo/notes@system-dev/wiki/cards/foo.md'), `${BASE}/Leo/notes/src/branch/main/system-dev/wiki/cards/foo.md` ); // 分段錨點(#segNN)捨棄 assert.equal( srcHref('gitea:Leo/notes@wiki/foo.md#seg02'), `${BASE}/Leo/notes/src/branch/main/wiki/foo.md` ); // 中文路徑逐段 encode assert.equal( srcHref('gitea:Leo/notes@docs/員工手冊.md'), `${BASE}/Leo/notes/src/branch/main/docs/${encodeURIComponent('員工手冊.md')}` ); // 缺 @ 或畸形 → 不造連結 assert.equal(srcHref('gitea:Leo/notes'), ''); assert.equal(srcHref('gitea:@wiki/foo.md'), ''); assert.equal(srcHref('gitea:Leo/notes@'), ''); }); test('kb://(新 ingest 鏈)— 不造死鏈、srcLocalPath 給本地路徑', () => { const { srcHref, srcLocalPath } = makeFns(BASE); assert.equal(srcHref('kb://人事/員工特休假規定.md'), ''); assert.equal(srcLocalPath('kb://人事/員工特休假規定.md'), '人事/員工特休假規定.md'); assert.equal(srcLocalPath('kb://foo.md#seg01'), 'foo.md'); // 非 kb:// 不給本地路徑 assert.equal(srcLocalPath('gitea://foo.md'), ''); assert.equal(srcLocalPath('gitea:Leo/notes@foo.md'), ''); assert.equal(srcLocalPath('https://example.com/x'), ''); }); test('SOURCE_WEB_BASE 未設 — 全部 scheme 都不給 href(降級純文字),kb:// 顯示不受影響', () => { const { srcHref, srcLocalPath } = makeFns(''); assert.equal(srcHref('gitea://wiki/foo.md'), ''); assert.equal(srcHref('gitea:Leo/notes@wiki/foo.md'), ''); assert.equal(srcHref('kb://foo.md'), ''); assert.equal(srcLocalPath('kb://foo.md'), 'foo.md'); // 本地路徑與 base 無關 }); test('未知 scheme — 誠實維持純文字(不猜連結)', () => { const { srcHref, srcLocalPath } = makeFns(BASE); assert.equal(srcHref('https://example.com/foo'), ''); assert.equal(srcHref('random-string'), ''); assert.equal(srcLocalPath('random-string'), ''); }); test('UI 有 kb:// 的誠實標註(兩個顯示點:卡片詳頁 srcline + AI 出處列)', () => { const hits = SRC.split('在你的同步資料夾內').length - 1; assert.ok(hits >= 2, `「在你的同步資料夾內」標註應出現在 ≥2 個顯示點,實得 ${hits}`); assert.ok(SRC.includes('srcLocalPath(src)'), '卡片詳頁應走 srcLocalPath 降級'); });