@takagaki/cortex-decisions-viewer 0.12.163 → 0.12.164
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build.js +8 -1
- package/dist/story.js +49 -7
- package/package.json +1 -1
package/dist/build.js
CHANGED
|
@@ -2367,11 +2367,18 @@ async function buildSite(opts, views) {
|
|
|
2367
2367
|
// ストーリー(#901 V2-5)の日本時間の今日。日・週・月の3つで同じ日にそろえるため1回だけ計算する
|
|
2368
2368
|
const storyToday = (0, story_1.todayJst)(new Date(opts.generatedAt));
|
|
2369
2369
|
// ストーリーの日々の動き(#901 V2-5)。帳簿で on の日のファイルが無ければ null(キーごと出さない)
|
|
2370
|
+
const shownIds = new Set([...decisions.map((d) => d.id), ...sections.flatMap((s) => s.records.map((r) => r.id))]);
|
|
2371
|
+
const idByRepoPath = new Map();
|
|
2372
|
+
for (const [id, rel] of recordRelPaths)
|
|
2373
|
+
if (shownIds.has(id))
|
|
2374
|
+
idByRepoPath.set(rel, id);
|
|
2370
2375
|
const story = await (0, story_1.readStory)(repoRoot, renderGroundingSection, (p) => repo.baseUrl ? `${repo.baseUrl}/edit/${repo.branch}/${encodePath(p)}` : null,
|
|
2371
2376
|
// 動きのない日を埋める終点=ビルドの時刻の日本時間の日付(時計を注入できる)
|
|
2372
2377
|
storyToday, ledgerDir,
|
|
2373
2378
|
// 名前のリンク(story.screen-name-links): 日の relations の関係者・用語・ルールを、画面にある記録の表示名・別名・同義語で本文に当てる
|
|
2374
|
-
(targets) => (0, story_1.storyNameLinks)(targets, storyNameSources(sections))
|
|
2379
|
+
(targets) => (0, story_1.storyNameLinks)(targets, storyNameSources(sections)),
|
|
2380
|
+
// 本文の相対リンク(決定の記録など)の飛び先: 画面に載る記録(決定・各区画)のパス → id
|
|
2381
|
+
(repoPath) => idByRepoPath.get(repoPath));
|
|
2375
2382
|
// 週・月のあらすじ(#901)。週・月のファイルが無ければ null(キーごと出さない=今までと同じ画面)
|
|
2376
2383
|
const storyDigest = await (0, story_1.readStoryDigest)(repoRoot, renderGroundingSection, (p) => repo.baseUrl ? `${repo.baseUrl}/edit/${repo.branch}/${encodePath(p)}` : null, storyToday, ledgerDir);
|
|
2377
2384
|
// 案件アイコン(#348)。Cortex構成でなければ undefined(旧レイアウトには置き場が無い)
|
package/dist/story.js
CHANGED
|
@@ -19,6 +19,7 @@ exports.isEngineQuietDay = isEngineQuietDay;
|
|
|
19
19
|
exports.todayJst = todayJst;
|
|
20
20
|
exports.quietStoryRow = quietStoryRow;
|
|
21
21
|
exports.withQuietDays = withQuietDays;
|
|
22
|
+
exports.linkRecordRefs = linkRecordRefs;
|
|
22
23
|
exports.readStory = readStory;
|
|
23
24
|
exports.storyWeekHeading = storyWeekHeading;
|
|
24
25
|
exports.storyMonthHeading = storyMonthHeading;
|
|
@@ -75,19 +76,29 @@ const MACHINE_WORD_RE = /urn:|cortex-engine|sha=|<!--|-->|\.md\b|Days\/|story-da
|
|
|
75
76
|
* 門に掛ける前にリンクの文字だけに剝がす。外の URL(`https://…`・`<https://…>`)は対象外(そのまま残す)。
|
|
76
77
|
* 本文に素で書かれた `foo.md` はここでは剝がさず、`MACHINE_WORD_RE` が行ごと伏せる
|
|
77
78
|
*/
|
|
78
|
-
const RELATIVE_MD_LINK_RE = /\[([^\]\n]*)\]\(\s*<?(?![a-zA-Z][a-zA-Z0-9+.-]*:|\/\/|#)[^)\s<>]*\.md(?:#[^)\s<>]*)?>?\s*\)/g;
|
|
79
|
+
const RELATIVE_MD_LINK_RE = /\[([^\]\n]*)\]\(\s*<?(?![a-zA-Z][a-zA-Z0-9+.-]*:|\/\/|#)([^)\s<>]*\.md)(?:#[^)\s<>]*)?>?\s*\)/g;
|
|
79
80
|
const LINK_OPEN_RE = /\[[^\]\n]*\]\([^)\s]*/g;
|
|
80
81
|
/**
|
|
81
82
|
* 相対 `.md` のリンクを文字に剝がす。剝がした結果、剝がす前の行に無かった `](` のリンクが現れる行(入れ子のリンクなど)は、
|
|
82
83
|
* 剝がさず元のまま返す(`.md` が残るので `MACHINE_WORD_RE` が行ごと伏せる)。後ろの関所に頼らない
|
|
83
84
|
*/
|
|
84
|
-
const unlinkRelativeMd = (line) => {
|
|
85
|
+
const unlinkRelativeMd = (line, keepRecordRefs = false) => {
|
|
85
86
|
const out = line.replace(RELATIVE_MD_LINK_RE, "$1");
|
|
86
87
|
if (out === line)
|
|
87
88
|
return line;
|
|
88
89
|
const before = new Set(line.match(LINK_OPEN_RE) ?? []);
|
|
89
|
-
|
|
90
|
+
if ((out.match(LINK_OPEN_RE) ?? []).some((m) => !before.has(m)))
|
|
91
|
+
return line;
|
|
92
|
+
if (!keepRecordRefs)
|
|
93
|
+
return out;
|
|
94
|
+
// 記録(`…/records/<名前>.md`)を指すものは、`.md` を落とした印のリンク `#rec:<相対パス>` にして残す(門の `.md` の伏せを通すため)。
|
|
95
|
+
// 画面の中の飛び先への差し替えは `linkRecordRefs`(build が記録の表を握って渡す)。それ以外の相対リンクは今までどおり文字に剝がす
|
|
96
|
+
return line.replace(RELATIVE_MD_LINK_RE, (_m, text, href) => RECORD_HREF_RE.test(href) ? `[${text}](${RECORD_REF_PREFIX}${href.slice(0, -3)})` : text);
|
|
90
97
|
};
|
|
98
|
+
/** 記録の相対パス(`…/records/<名前>.md`) */
|
|
99
|
+
const RECORD_HREF_RE = /(?:^|\/)records\/[^/]+\.md$/;
|
|
100
|
+
/** 記録を指すリンクの印。門(`.md` の伏せ)と関所(相対 URL を許す)を通り、`linkRecordRefs` が飛び先に差し替える */
|
|
101
|
+
const RECORD_REF_PREFIX = "#rec:";
|
|
91
102
|
/** 太字だけの 1 行(筋の名前の行) */
|
|
92
103
|
const BOLD_ONLY_RE = /^\*\*[^*]+\*\*$/;
|
|
93
104
|
/** 見出しの行(`##`〜`######`) */
|
|
@@ -346,7 +357,7 @@ function storyDayMarkdown(content, day) {
|
|
|
346
357
|
}
|
|
347
358
|
// 機械の行: 印と機械の語の行を伏せる
|
|
348
359
|
// 決定の記録へのリンクは、門に掛ける前に文字だけに剝がす(行ごと伏せない)
|
|
349
|
-
const clean = (ls) => ls.map(unlinkRelativeMd).filter((l) => !STORY_MARKER_RE.test(l.trim()) && !MACHINE_WORD_RE.test(l));
|
|
360
|
+
const clean = (ls) => ls.map((l) => unlinkRelativeMd(l, true)).filter((l) => !STORY_MARKER_RE.test(l.trim()) && !MACHINE_WORD_RE.test(l));
|
|
350
361
|
// 🔴 人の追記: 落とすのは**印の行だけ**(人が書いた行を画面が黙って消さない・実装レビュー 🟠2)
|
|
351
362
|
const humanKept = human.filter((l) => !STORY_MARKER_RE.test(l.trim()));
|
|
352
363
|
const out = withoutEmptySections(withoutEmptyBoldHeads([...clean(main), ...clean(lateAfter)]));
|
|
@@ -466,6 +477,35 @@ async function loadStoryLedger(repoRoot, warn, ledgerDir) {
|
|
|
466
477
|
}
|
|
467
478
|
return ledger;
|
|
468
479
|
}
|
|
480
|
+
/**
|
|
481
|
+
* 本文(関所を通した HTML)の相対リンクのうち、記録(`Cortex/<区画>/records/*.md`)を指すものを
|
|
482
|
+
* 画面の中のその記録への飛び先(人名・用語のリンクと同じ `a.wikilink[data-go]`)にする。
|
|
483
|
+
*
|
|
484
|
+
* - 相対パスはその日のファイルの置き場から解く(`../../../Decisions/records/x.md` → `Cortex/Decisions/records/x.md`)
|
|
485
|
+
* - 🔴 記録が見つからない(`idOf` が undefined)相対リンクは `<a>` を外して文字のまま残す(壊れたリンク・行き止まりを作らない)
|
|
486
|
+
* - 外の URL(http・https・mailto など `scheme:`・`//`)とページ内の `#…` は触らない
|
|
487
|
+
*
|
|
488
|
+
* 呼び手は**サニタイズ後**の HTML を渡す(属性値・文字はエスケープ済み。ここで新しい HTML は混ぜず、data-go の値だけ & と " を逃がす)
|
|
489
|
+
*/
|
|
490
|
+
function linkRecordRefs(html, dayRepoPath, idOf) {
|
|
491
|
+
const baseDir = node_path_1.default.posix.dirname(dayRepoPath);
|
|
492
|
+
return html.replace(/<a href="([^"]*)">([\s\S]*?)<\/a>/g, (whole, href, inner) => {
|
|
493
|
+
const isRef = href.startsWith(RECORD_REF_PREFIX);
|
|
494
|
+
if (!isRef && (/^[a-z][a-z0-9+.-]*:/i.test(href) || href.startsWith("//") || href.startsWith("#")))
|
|
495
|
+
return whole;
|
|
496
|
+
let target = isRef ? href.slice(RECORD_REF_PREFIX.length).replace(/&/g, "&") + ".md" : href.replace(/&/g, "&").replace(/[?#].*$/, "");
|
|
497
|
+
try {
|
|
498
|
+
target = decodeURIComponent(target);
|
|
499
|
+
}
|
|
500
|
+
catch { /* 解けない綴りはそのまま照合して見つからなければ文字に落とす */ }
|
|
501
|
+
const resolved = target.startsWith("/") ? node_path_1.default.posix.normalize(target.slice(1)) : node_path_1.default.posix.join(baseDir, target);
|
|
502
|
+
const id = /^Cortex\/[^/]+\/records\/[^/]+\.md$/.test(resolved) ? idOf(resolved) : undefined;
|
|
503
|
+
if (!id)
|
|
504
|
+
return inner;
|
|
505
|
+
const attr = id.replace(/&/g, "&").replace(/"/g, """);
|
|
506
|
+
return `<a class="wikilink" data-go="${attr}">${inner}</a>`;
|
|
507
|
+
});
|
|
508
|
+
}
|
|
469
509
|
/**
|
|
470
510
|
* 案件のストーリーを読む。**載せる日が無ければ `null`**(タブも器も出さない)。
|
|
471
511
|
*
|
|
@@ -479,7 +519,9 @@ today = todayJst(),
|
|
|
479
519
|
// 帳簿の置き場(既定は `<repoRoot>/.cortex`)
|
|
480
520
|
ledgerDir,
|
|
481
521
|
// 日の `relations` の target から名前のリンクの表を作る口(build が記録の表を握って渡す。無ければリンクは付けない)
|
|
482
|
-
linksOf = () => []
|
|
522
|
+
linksOf = () => [],
|
|
523
|
+
// 本文の相対リンクが指す記録(リポジトリ相対パス)の id。画面にある記録だけ返す(無ければリンクは文字に落とす)
|
|
524
|
+
recordIdOf = () => undefined) {
|
|
483
525
|
const ledger = await loadStoryLedger(repoRoot, true, ledgerDir);
|
|
484
526
|
if (!ledger)
|
|
485
527
|
return null;
|
|
@@ -543,7 +585,7 @@ linksOf = () => []) {
|
|
|
543
585
|
const links = linksOf(dayRelationTargets(fm));
|
|
544
586
|
const partialHour = dayPartialHour(fm);
|
|
545
587
|
out.push({
|
|
546
|
-
date: f.day, heading: heading, bodyHtml: await renderMarkdown(markdown),
|
|
588
|
+
date: f.day, heading: heading, bodyHtml: linkRecordRefs(await renderMarkdown(markdown), f.rel, recordIdOf),
|
|
547
589
|
...(editUrl ? { editUrl: editUrl } : {}),
|
|
548
590
|
...(partialHour !== null ? { partialHour: partialHour } : {}),
|
|
549
591
|
...(links.length ? { links: links } : {}),
|
|
@@ -613,7 +655,7 @@ function storyDigestParts(content) {
|
|
|
613
655
|
const end = body.findIndex((l) => DIGEST_END_RE.test(l.trim()));
|
|
614
656
|
const at = body.findIndex((l, i) => i > end && l.trim() === HUMAN_HEADING);
|
|
615
657
|
// 機械の部分の `#` の見出しの行は落とす(流れは段落だけの約束。見出しが紛れると後ろの文が別の節に見える)
|
|
616
|
-
const main = withoutHiddenBoldGroups((at < 0 ? body : body.slice(0, at)).map(unlinkRelativeMd).filter((l) => !STORY_MARKER_RE.test(l.trim()) && !/^\s{0,3}#{1,6}(\s|$)/.test(l)))
|
|
658
|
+
const main = withoutHiddenBoldGroups((at < 0 ? body : body.slice(0, at)).map((l) => unlinkRelativeMd(l)).filter((l) => !STORY_MARKER_RE.test(l.trim()) && !/^\s{0,3}#{1,6}(\s|$)/.test(l)))
|
|
617
659
|
.filter((l) => !MACHINE_WORD_RE.test(l));
|
|
618
660
|
const human = (at < 0 ? [] : body.slice(at + 1)).filter((l) => !STORY_MARKER_RE.test(l.trim()));
|
|
619
661
|
let phase = null;
|
package/package.json
CHANGED