@takagaki/cortex-decisions-viewer 0.12.133 → 0.12.134
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 +66 -1
- package/dist/render.js +31 -0
- package/package.json +1 -1
package/dist/build.js
CHANGED
|
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.DECISION_FIRMNESS = exports.PROJECT_ICON_EXTS = exports.MIRROR_RELS = void 0;
|
|
39
|
+
exports.RELATED_MATERIALS_SECTIONS = exports.RELATED_URL_MAX = exports.RELATED_MATERIALS_FIELD = exports.DECISION_FIRMNESS = exports.PROJECT_ICON_EXTS = exports.MIRROR_RELS = void 0;
|
|
40
40
|
exports.sanitizeBody = sanitizeBody;
|
|
41
41
|
exports.findProjectIcon = findProjectIcon;
|
|
42
42
|
exports.readFleetSources = readFleetSources;
|
|
@@ -60,6 +60,10 @@ exports.build = build;
|
|
|
60
60
|
exports.decisionFirmnessOf = decisionFirmnessOf;
|
|
61
61
|
exports.decisionTopicOf = decisionTopicOf;
|
|
62
62
|
exports.decidedByOf = decidedByOf;
|
|
63
|
+
exports.isRelatedUrl = isRelatedUrl;
|
|
64
|
+
exports.relatedMaterialsRead = relatedMaterialsRead;
|
|
65
|
+
exports.relatedMaterialsView = relatedMaterialsView;
|
|
66
|
+
exports.attachRelatedMaterials = attachRelatedMaterials;
|
|
63
67
|
exports.createRefResolver = createRefResolver;
|
|
64
68
|
const node_crypto_1 = require("node:crypto");
|
|
65
69
|
const node_fs_1 = require("node:fs");
|
|
@@ -2530,6 +2534,8 @@ async function buildSite(opts, views) {
|
|
|
2530
2534
|
const records = await loadGenericRecords(recordsDir, exclude, repo.baseUrl, repo.branch);
|
|
2531
2535
|
// 人の手(削除の確認の文面を替える材料・cortex-engine #1094 段 4)
|
|
2532
2536
|
attachHumanTouched(records, recordsDir, repoRoot, ledgers.confirmation, touchedBy);
|
|
2537
|
+
// 関連の資料(cortex-engine #1094 F8)。ルール・用語だけ・欄の無い記録には何も付かない
|
|
2538
|
+
attachRelatedMaterials(e.name, records, refs);
|
|
2533
2539
|
// ルールの取り下げ(`retracted_by`・cortex-engine #1094 便 4-2d)。ルールの区画だけ・取り下げの無い案件では何も付かない
|
|
2534
2540
|
if (e.name === "Rules")
|
|
2535
2541
|
attachRetractedBy(records, decisions, (d) => rawDates.get(d) ?? d.fm.date);
|
|
@@ -2745,6 +2751,8 @@ async function parseDecision(raw, fileName, repoRelDir, repoBaseUrl, branch, ref
|
|
|
2745
2751
|
const firmness = decisionFirmnessOf(data.firmness);
|
|
2746
2752
|
const topic = decisionTopicOf(data.topic);
|
|
2747
2753
|
const decidedBy = decidedByOf(data.decided_by);
|
|
2754
|
+
// 関連の資料(#1094 F8)。通る URL が 0 本ならキーごと載せない
|
|
2755
|
+
const relatedMaterials = relatedMaterialsView(data, refs);
|
|
2748
2756
|
// 本文先頭の H1 はタイトルと重複するため除去(詳細画面ではタイトルを別途表示する)
|
|
2749
2757
|
const bodyHtml = await renderRecordBody(content);
|
|
2750
2758
|
const filePath = repoRelDir ? `${repoRelDir}/${fileName}` : fileName;
|
|
@@ -2778,6 +2786,7 @@ async function parseDecision(raw, fileName, repoRelDir, repoBaseUrl, branch, ref
|
|
|
2778
2786
|
...(firmness ? { firmness } : {}),
|
|
2779
2787
|
...(topic ? { topic } : {}),
|
|
2780
2788
|
...(decidedBy ? { decidedBy } : {}),
|
|
2789
|
+
...(relatedMaterials ? { relatedMaterials } : {}),
|
|
2781
2790
|
};
|
|
2782
2791
|
}
|
|
2783
2792
|
/**
|
|
@@ -2830,6 +2839,62 @@ function decidedByOf(value) {
|
|
|
2830
2839
|
return undefined;
|
|
2831
2840
|
return value.map(decidedByEntryOf).filter((e) => e !== null);
|
|
2832
2841
|
}
|
|
2842
|
+
/**
|
|
2843
|
+
* 関連の資料の欄 `related_materials` の読み手(決定・ルール・用語・cortex-engine #1094 F8)。
|
|
2844
|
+
*
|
|
2845
|
+
* 🔴 **写し。正本は cortex-engine `scripts/gold/related-materials-field.mjs` の `isRelatedUrl` と `relatedMaterialsRead`**。
|
|
2846
|
+
* 同じバイト列の表 `test/fixtures/related-materials-contract.json` を両リポに置き、`test/related-materials-view.test.mjs` の
|
|
2847
|
+
* 「[契約] …」が全ケースを流す。規則を変えるときは engine の正本・この写し・表を同じ日に直す。
|
|
2848
|
+
* 重複も上限も見ない(人が足した分を落とさない)。`decided_by` の URL の門(`DECIDED_BY_URL_RE`)とは別の、engine と同じ門
|
|
2849
|
+
*/
|
|
2850
|
+
exports.RELATED_MATERIALS_FIELD = "related_materials";
|
|
2851
|
+
exports.RELATED_URL_MAX = 2000;
|
|
2852
|
+
// eslint-disable-next-line no-control-regex
|
|
2853
|
+
const RELATED_URL_RE = /^https?:\/\/[^\s<>"\[\]〔〕\u0000-\u001f\u007f]+$/i;
|
|
2854
|
+
/** 欄に置いてよい URL か(http(s)・空白と制御文字・`<>"[]〔〕` を含まない・ホストあり・2000 字まで) */
|
|
2855
|
+
function isRelatedUrl(v) {
|
|
2856
|
+
if (typeof v !== "string" || !v || v.length > exports.RELATED_URL_MAX)
|
|
2857
|
+
return false;
|
|
2858
|
+
if (!RELATED_URL_RE.test(v))
|
|
2859
|
+
return false;
|
|
2860
|
+
try {
|
|
2861
|
+
const u = new URL(v);
|
|
2862
|
+
return (u.protocol === "http:" || u.protocol === "https:") && u.hostname !== "";
|
|
2863
|
+
}
|
|
2864
|
+
catch {
|
|
2865
|
+
return false;
|
|
2866
|
+
}
|
|
2867
|
+
}
|
|
2868
|
+
/** frontmatter → 欄の URL の並び(通るものだけ・順はそのまま)。欄が無い・リストでなければ [] */
|
|
2869
|
+
function relatedMaterialsRead(fm) {
|
|
2870
|
+
const v = fm && typeof fm === "object" ? fm[exports.RELATED_MATERIALS_FIELD] : null;
|
|
2871
|
+
return Array.isArray(v) ? v.filter(isRelatedUrl) : [];
|
|
2872
|
+
}
|
|
2873
|
+
/** 画面に載せる形(名前は根拠と同じ解決=帳の題名・URL の種類の名前)。通る URL が 0 本なら undefined(キーごと載せない) */
|
|
2874
|
+
function relatedMaterialsView(fm, refs) {
|
|
2875
|
+
const urls = relatedMaterialsRead(fm);
|
|
2876
|
+
if (!urls.length)
|
|
2877
|
+
return undefined;
|
|
2878
|
+
return urls.map((u) => {
|
|
2879
|
+
// 名前は scheme だけ小文字にして引く(根拠の解決は大文字の `HTTPS://` を URL と読まずパスに落とす)。飛び先は書かれたまま
|
|
2880
|
+
const q = u.replace(/^https?:/i, (m) => m.toLowerCase());
|
|
2881
|
+
const r = refs.resolve(q);
|
|
2882
|
+
// 名前が引けなければ(解決が引いた文字をそのまま返した)、書かれた URL のまま出す
|
|
2883
|
+
return { label: r.label && r.label !== q ? r.label : u, url: u };
|
|
2884
|
+
});
|
|
2885
|
+
}
|
|
2886
|
+
/** 関連の資料を持てる汎用の区画(関係者・ストーリーの日・Home の欄は拾わない) */
|
|
2887
|
+
exports.RELATED_MATERIALS_SECTIONS = new Set(["Rules", "Glossary"]);
|
|
2888
|
+
/** 区画の記録に関連の資料を載せる(ルール・用語だけ・欄の無い記録にはキーごと付けない) */
|
|
2889
|
+
function attachRelatedMaterials(section, records, refs) {
|
|
2890
|
+
if (!exports.RELATED_MATERIALS_SECTIONS.has(section))
|
|
2891
|
+
return;
|
|
2892
|
+
for (const r of records) {
|
|
2893
|
+
const view = relatedMaterialsView(r.fm, refs);
|
|
2894
|
+
if (view)
|
|
2895
|
+
r.relatedMaterials = view;
|
|
2896
|
+
}
|
|
2897
|
+
}
|
|
2833
2898
|
/**
|
|
2834
2899
|
* 解決した参照 → 書かれていた値(#968 tools 1)。つながり画面は点の鍵をこの値から決める
|
|
2835
2900
|
* (`site-data` に載せない——機械の語を画面の材料に増やさない)
|
package/dist/render.js
CHANGED
|
@@ -6115,6 +6115,8 @@ button.ops-card-btn:disabled { opacity: .6; cursor: default; }
|
|
|
6115
6115
|
.deciders { display: flex; flex-wrap: wrap; gap: 8px; }
|
|
6116
6116
|
.refs { margin: 0; padding-left: 18px; }
|
|
6117
6117
|
.refs li { margin: 4px 0; }
|
|
6118
|
+
/* 関連の資料(#1094 F8): 名前の引けない資料は URL のまま(最大 2000 字)なので、狭い画面ではみ出さないよう折り返す */
|
|
6119
|
+
.related-materials li { overflow-wrap: anywhere; }
|
|
6118
6120
|
.body {
|
|
6119
6121
|
background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
|
|
6120
6122
|
padding: 4px 22px 8px; margin-top: 8px;
|
|
@@ -7043,6 +7045,27 @@ ${calendarAddUrl.toString()}
|
|
|
7043
7045
|
function retractedFadedClass(rec) {
|
|
7044
7046
|
return isRetracted(rec) ? " is-faded" : "";
|
|
7045
7047
|
}
|
|
7048
|
+
/**
|
|
7049
|
+
* 詳細の節「関連の資料」(cortex-engine #1094 F8)。記録を生んだ会話に貼られた資料へのリンク。
|
|
7050
|
+
* 根拠(「参照」)とは混ぜない。ビルドが engine と同じ門で検めてあるが、画面でも http(s) だけをリンクにする(二重に見る)。
|
|
7051
|
+
* 関連の資料の無い記録では null(要素を作らない)
|
|
7052
|
+
*/
|
|
7053
|
+
function relatedMaterialsSection(r) {
|
|
7054
|
+
if (!r || !r.relatedMaterials || !r.relatedMaterials.length) return null;
|
|
7055
|
+
// 🔴 大文字の scheme(HTTPS://)も engine の門では通るので、ここも大文字小文字を区別しない(isHttp は区別する=ほかの画面の前例のまま触らない)
|
|
7056
|
+
var items = r.relatedMaterials.filter(function (m) { return m && typeof m.url === "string" && /^https?:\\/\\//i.test(m.url); });
|
|
7057
|
+
if (!items.length) return null;
|
|
7058
|
+
var box = el("div", { class: "related-materials-section" });
|
|
7059
|
+
box.appendChild(el("div", { class: "section-label", text: "関連の資料" }));
|
|
7060
|
+
var ul = el("ul", { class: "refs related-materials" });
|
|
7061
|
+
items.forEach(function (m) {
|
|
7062
|
+
var li = el("li");
|
|
7063
|
+
li.appendChild(el("a", { href: m.url, target: "_blank", rel: "noopener", text: m.label || m.url }));
|
|
7064
|
+
ul.appendChild(li);
|
|
7065
|
+
});
|
|
7066
|
+
box.appendChild(ul);
|
|
7067
|
+
return box;
|
|
7068
|
+
}
|
|
7046
7069
|
/** 詳細の節「取り下げを決めた決定」。取り下げの無い記録では null(要素を作らない) */
|
|
7047
7070
|
function retractSection(r) {
|
|
7048
7071
|
if (!isRetracted(r)) return null;
|
|
@@ -20537,6 +20560,10 @@ ${calendarAddUrl.toString()}
|
|
|
20537
20560
|
app.appendChild(genBody);
|
|
20538
20561
|
loadBody(r, genBody);
|
|
20539
20562
|
|
|
20563
|
+
// 関連の資料(#1094 F8)。本文の後・取り下げの節の前。ルール・用語にしか載らない
|
|
20564
|
+
var relm2 = relatedMaterialsSection(r);
|
|
20565
|
+
if (relm2) app.appendChild(relm2);
|
|
20566
|
+
|
|
20540
20567
|
// 取り下げ(便 4-2d)。本文の後・「その後の記録」の前。取り下げの無い記録では何も作らない
|
|
20541
20568
|
var retr = retractSection(r);
|
|
20542
20569
|
if (retr) app.appendChild(retr);
|
|
@@ -21512,6 +21539,10 @@ ${calendarAddUrl.toString()}
|
|
|
21512
21539
|
app.appendChild(ul);
|
|
21513
21540
|
}
|
|
21514
21541
|
|
|
21542
|
+
// 関連の資料(#1094 F8)。「参照」(根拠)の後・置き換えの前。根拠と混ぜない
|
|
21543
|
+
var relm = relatedMaterialsSection(d);
|
|
21544
|
+
if (relm) app.appendChild(relm);
|
|
21545
|
+
|
|
21515
21546
|
// 置き換え(#699 F3)。本文・参照の後、「その後の記録」の前。置き換えの無い決定では何も作らない
|
|
21516
21547
|
var sup = supersedeSection(d);
|
|
21517
21548
|
if (sup) app.appendChild(sup);
|
package/package.json
CHANGED