@milehimikey/em-portal 0.1.0
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/LICENSE +21 -0
- package/README.md +231 -0
- package/dist/build.d.ts +21 -0
- package/dist/build.js +132 -0
- package/dist/build.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +43 -0
- package/dist/cli.js.map +1 -0
- package/dist/crossModel.d.ts +14 -0
- package/dist/crossModel.js +49 -0
- package/dist/crossModel.js.map +1 -0
- package/dist/em/docBody.d.ts +5 -0
- package/dist/em/docBody.js +43 -0
- package/dist/em/docBody.js.map +1 -0
- package/dist/em/exportDoc.d.ts +135 -0
- package/dist/em/exportDoc.js +22 -0
- package/dist/em/exportDoc.js.map +1 -0
- package/dist/em/run.d.ts +41 -0
- package/dist/em/run.js +99 -0
- package/dist/em/run.js.map +1 -0
- package/dist/em/statusDoc.d.ts +56 -0
- package/dist/em/statusDoc.js +11 -0
- package/dist/em/statusDoc.js.map +1 -0
- package/dist/pages/html.d.ts +11 -0
- package/dist/pages/html.js +84 -0
- package/dist/pages/html.js.map +1 -0
- package/dist/pages/index.d.ts +3 -0
- package/dist/pages/index.js +128 -0
- package/dist/pages/index.js.map +1 -0
- package/dist/pages/model.d.ts +17 -0
- package/dist/pages/model.js +54 -0
- package/dist/pages/model.js.map +1 -0
- package/dist/pages/slice.d.ts +16 -0
- package/dist/pages/slice.js +144 -0
- package/dist/pages/slice.js.map +1 -0
- package/dist/pages/types.d.ts +22 -0
- package/dist/pages/types.js +4 -0
- package/dist/pages/types.js.map +1 -0
- package/dist/refs.d.ts +36 -0
- package/dist/refs.js +69 -0
- package/dist/refs.js.map +1 -0
- package/dist/slug.d.ts +5 -0
- package/dist/slug.js +30 -0
- package/dist/slug.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Per-model page: the model's full diagram plus its slice table — the
|
|
3
|
+
// drill-down step between the multi-model landing index and an individual
|
|
4
|
+
// slice page (model -> slice -> doc, per MIL-162's "state up front" design).
|
|
5
|
+
import { escapeHtml, layout } from "./html.js";
|
|
6
|
+
// Note: this page's slice links are relative to the model directory itself
|
|
7
|
+
// ("slices/<key>.html"), not the site-root-relative form src/refs.ts's
|
|
8
|
+
// sliceUrl() returns (which is for cross-page links, e.g. the landing
|
|
9
|
+
// page's cross-model-links table) — so this page builds its own hrefs
|
|
10
|
+
// rather than reusing that helper.
|
|
11
|
+
const PATTERN_LABEL = {
|
|
12
|
+
"state-change": "State Change",
|
|
13
|
+
"state-view": "State View",
|
|
14
|
+
automation: "Automation",
|
|
15
|
+
translation: "Translation",
|
|
16
|
+
unclassified: "Unclassified",
|
|
17
|
+
};
|
|
18
|
+
function statusBadge(hasDoc, status) {
|
|
19
|
+
if (!hasDoc)
|
|
20
|
+
return `<span class="badge">no doc</span>`;
|
|
21
|
+
if (!status)
|
|
22
|
+
return `<span class="badge">unknown</span>`;
|
|
23
|
+
const cls = status === "implemented" ? "ok" : "";
|
|
24
|
+
return `<span class="badge ${cls}">${escapeHtml(status)}</span>`;
|
|
25
|
+
}
|
|
26
|
+
function driftBadge(drift) {
|
|
27
|
+
if (!drift)
|
|
28
|
+
return "";
|
|
29
|
+
const cls = drift === "in-sync" ? "ok" : drift === "never-implemented" ? "warn" : "bad";
|
|
30
|
+
return `<span class="badge ${cls}">${escapeHtml(drift)}</span>`;
|
|
31
|
+
}
|
|
32
|
+
export function renderModelPage(args) {
|
|
33
|
+
const { modelName, file, diagramFile, slices } = args;
|
|
34
|
+
const rows = slices
|
|
35
|
+
.map((s) => ` <tr id="${escapeHtml(s.key)}">
|
|
36
|
+
<td><a href="slices/${escapeHtml(s.key)}.html">${escapeHtml(s.name)}</a></td>
|
|
37
|
+
<td class="pattern">${escapeHtml(PATTERN_LABEL[s.pattern])}</td>
|
|
38
|
+
<td>${statusBadge(s.hasDoc, s.status)}</td>
|
|
39
|
+
<td>${driftBadge(s.driftSignal)}</td>
|
|
40
|
+
</tr>`)
|
|
41
|
+
.join("\n");
|
|
42
|
+
const body = ` <p><code>${escapeHtml(file)}</code></p>
|
|
43
|
+
<h1>${escapeHtml(modelName)}</h1>
|
|
44
|
+
<div class="diagram-frame"><object class="diagram" type="image/svg+xml" data="${escapeHtml(diagramFile)}"></object></div>
|
|
45
|
+
<p class="full-diagram-link"><a href="${escapeHtml(diagramFile)}">Open full diagram →</a></p>
|
|
46
|
+
<table>
|
|
47
|
+
<thead><tr><th>Slice</th><th>Pattern</th><th>Status</th><th>Drift</th></tr></thead>
|
|
48
|
+
<tbody>
|
|
49
|
+
${rows}
|
|
50
|
+
</tbody>
|
|
51
|
+
</table>`;
|
|
52
|
+
return layout(`${modelName} — em portal`, body, "../index.html", [{ label: modelName, href: "." }]);
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.js","sourceRoot":"","sources":["../../src/pages/model.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,sEAAsE;AACtE,0EAA0E;AAC1E,6EAA6E;AAE7E,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAE/C,2EAA2E;AAC3E,uEAAuE;AACvE,sEAAsE;AACtE,sEAAsE;AACtE,mCAAmC;AAEnC,MAAM,aAAa,GAAiC;IAClD,cAAc,EAAE,cAAc;IAC9B,YAAY,EAAE,YAAY;IAC1B,UAAU,EAAE,YAAY;IACxB,WAAW,EAAE,aAAa;IAC1B,YAAY,EAAE,cAAc;CAC7B,CAAC;AAEF,SAAS,WAAW,CAAC,MAAe,EAAE,MAAqB;IACzD,IAAI,CAAC,MAAM;QAAE,OAAO,mCAAmC,CAAC;IACxD,IAAI,CAAC,MAAM;QAAE,OAAO,oCAAoC,CAAC;IACzD,MAAM,GAAG,GAAG,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IACjD,OAAO,sBAAsB,GAAG,KAAK,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC;AACnE,CAAC;AAED,SAAS,UAAU,CAAC,KAAoB;IACtC,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACtB,MAAM,GAAG,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,KAAK,mBAAmB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;IACxF,OAAO,sBAAsB,GAAG,KAAK,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC;AAClE,CAAC;AAmBD,MAAM,UAAU,eAAe,CAAC,IAAmB;IACjD,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACtD,MAAM,IAAI,GAAG,MAAM;SAChB,GAAG,CACF,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC;8BACjB,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;8BAC7C,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;cACpD,WAAW,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;cAC/B,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC;YAC3B,CACP;SACA,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,IAAI,GAAG,gBAAgB,UAAU,CAAC,IAAI,CAAC;UACrC,UAAU,CAAC,SAAS,CAAC;oFACqD,UAAU,CAAC,WAAW,CAAC;4CAC/D,UAAU,CAAC,WAAW,CAAC;;;;EAIjE,IAAI;;aAEO,CAAC;IAEZ,OAAO,MAAM,CAAC,GAAG,SAAS,cAAc,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;AACtG,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { EmSlice, SliceDocJoin, SlicePattern } from "../em/exportDoc.js";
|
|
2
|
+
export interface SlicePageArgs {
|
|
3
|
+
modelName: string;
|
|
4
|
+
modelKey: string;
|
|
5
|
+
diagramFile: string;
|
|
6
|
+
sliceDiagramFile: string;
|
|
7
|
+
slice: EmSlice;
|
|
8
|
+
pattern: SlicePattern;
|
|
9
|
+
doc: SliceDocJoin;
|
|
10
|
+
/** Rendered markdown body of the bound doc (src/em/docBody.ts) — `em
|
|
11
|
+
* export`'s own `doc` field never carries this (frontmatter only). `null`
|
|
12
|
+
* when no doc is bound, the bound file couldn't be read, or it has no
|
|
13
|
+
* body content after its frontmatter block. */
|
|
14
|
+
docBodyHtml: string | null;
|
|
15
|
+
}
|
|
16
|
+
export declare function renderSlicePage(args: SlicePageArgs): string;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Per-slice page: this slice's own diagram, its rendered doc, driftSignal,
|
|
3
|
+
// and a link to wherever it was implemented (MIL-172's scope: "diagram,
|
|
4
|
+
// rendered doc, driftSignal, PR link"). MIL-173: every element row also
|
|
5
|
+
// carries its own `em export` ref as a DOM id plus a visible, copyable
|
|
6
|
+
// deep-link permalink (src/refs.ts) — the URL scheme an agent's `em query`/
|
|
7
|
+
// MCP citation and a stakeholder's portal link share.
|
|
8
|
+
import { escapeHtml, layout } from "./html.js";
|
|
9
|
+
import { elementDeepLink } from "../refs.js";
|
|
10
|
+
const PATTERN_LABEL = {
|
|
11
|
+
"state-change": "State Change",
|
|
12
|
+
"state-view": "State View",
|
|
13
|
+
automation: "Automation",
|
|
14
|
+
translation: "Translation",
|
|
15
|
+
unclassified: "Unclassified",
|
|
16
|
+
};
|
|
17
|
+
function statusBadge(status) {
|
|
18
|
+
if (!status)
|
|
19
|
+
return `<span class="badge">unknown</span>`;
|
|
20
|
+
const cls = status === "implemented" ? "ok" : "";
|
|
21
|
+
return `<span class="badge ${cls}">${escapeHtml(status)}</span>`;
|
|
22
|
+
}
|
|
23
|
+
function driftBadge(drift) {
|
|
24
|
+
if (!drift)
|
|
25
|
+
return `<span class="badge">n/a</span>`;
|
|
26
|
+
const cls = drift === "in-sync" ? "ok" : drift === "never-implemented" ? "warn" : "bad";
|
|
27
|
+
return `<span class="badge ${cls}">${escapeHtml(drift)}</span>`;
|
|
28
|
+
}
|
|
29
|
+
/** Renders a doc's `implementedIn` value as a link when it looks like a URL
|
|
30
|
+
* (a PR/commit link — the common case per docs/slice-doc-schema.md), or as
|
|
31
|
+
* plain code text otherwise (a bare file path — no portal-side path
|
|
32
|
+
* resolution is attempted, since the target repo isn't necessarily the one
|
|
33
|
+
* the portal was built from). */
|
|
34
|
+
function implementedInHtml(implementedIn) {
|
|
35
|
+
if (!implementedIn)
|
|
36
|
+
return `<span class="no-doc">not linked</span>`;
|
|
37
|
+
if (/^https?:\/\//.test(implementedIn)) {
|
|
38
|
+
return `<a href="${escapeHtml(implementedIn)}">${escapeHtml(implementedIn)}</a>`;
|
|
39
|
+
}
|
|
40
|
+
return `<code>${escapeHtml(implementedIn)}</code>`;
|
|
41
|
+
}
|
|
42
|
+
/** `ratifiedBy`/`ratifiedOn` (schema 1.8, MIL-165) — who signed off on this
|
|
43
|
+
* doc's current status/version, and when. Both are hand-filled and often
|
|
44
|
+
* absent even on an `implemented` doc predating the feature (or ratified by
|
|
45
|
+
* hand before it existed) — that's routine, not a gap, so it renders as a
|
|
46
|
+
* plain "not recorded" note rather than a warning badge. */
|
|
47
|
+
function ratifiedByHtml(ratifiedBy, ratifiedOn) {
|
|
48
|
+
if (!ratifiedBy)
|
|
49
|
+
return `<span class="no-doc">not recorded</span>`;
|
|
50
|
+
return ratifiedOn ? `${escapeHtml(ratifiedBy)} <span class="pattern">(${escapeHtml(ratifiedOn)})</span>` : escapeHtml(ratifiedBy);
|
|
51
|
+
}
|
|
52
|
+
/** `owner`/`tracking` (schema 1.9, MIL-171) — rendered as one optional line
|
|
53
|
+
* beneath the stat row, omitted entirely when neither is set (same
|
|
54
|
+
* "nothing to report" convention `em status`'s own text report uses for
|
|
55
|
+
* its doc-issues line), rather than two more always-present "not set"
|
|
56
|
+
* tiles cluttering the common case. */
|
|
57
|
+
function ownerTrackingHtml(owner, tracking) {
|
|
58
|
+
if (!owner && !tracking)
|
|
59
|
+
return "";
|
|
60
|
+
const parts = [];
|
|
61
|
+
if (owner)
|
|
62
|
+
parts.push(`Owner: <strong>${escapeHtml(owner)}</strong>`);
|
|
63
|
+
if (tracking) {
|
|
64
|
+
parts.push(/^https?:\/\//.test(tracking)
|
|
65
|
+
? `Tracking: <a href="${escapeHtml(tracking)}">${escapeHtml(tracking)}</a>`
|
|
66
|
+
: `Tracking: <code>${escapeHtml(tracking)}</code>`);
|
|
67
|
+
}
|
|
68
|
+
return ` <p>${parts.join(" · ")}</p>\n`;
|
|
69
|
+
}
|
|
70
|
+
function formatFields(el) {
|
|
71
|
+
if (!el.fields || el.fields.length === 0)
|
|
72
|
+
return "";
|
|
73
|
+
return el.fields.map((f) => (f.type ? `${f.name}: ${f.type}` : f.name)).join(", ");
|
|
74
|
+
}
|
|
75
|
+
function elementDetail(el) {
|
|
76
|
+
const parts = [];
|
|
77
|
+
if (el.persona)
|
|
78
|
+
parts.push(`@${el.persona}`);
|
|
79
|
+
if (el.context)
|
|
80
|
+
parts.push(`@${el.context}`);
|
|
81
|
+
if (el.from && el.from.length > 0)
|
|
82
|
+
parts.push(`from ${el.from.map((f) => f.name).join(", ")}`);
|
|
83
|
+
if (el.again)
|
|
84
|
+
parts.push("again");
|
|
85
|
+
if (el.public)
|
|
86
|
+
parts.push("public");
|
|
87
|
+
const fields = formatFields(el);
|
|
88
|
+
if (fields)
|
|
89
|
+
parts.push(`{ ${fields} }`);
|
|
90
|
+
return parts.map(escapeHtml).join(" · ");
|
|
91
|
+
}
|
|
92
|
+
function renderElementsTable(elements, modelKey) {
|
|
93
|
+
const rows = elements
|
|
94
|
+
.map((el) => {
|
|
95
|
+
const annotations = [];
|
|
96
|
+
if (el.issue)
|
|
97
|
+
annotations.push(`<div><span class="badge warn">issue</span> ${escapeHtml(el.issue)}</div>`);
|
|
98
|
+
if (el.divergence)
|
|
99
|
+
annotations.push(`<div><span class="badge">divergence</span> ${escapeHtml(el.divergence)}</div>`);
|
|
100
|
+
// The fragment jump target for THIS page is always local ("#<ref>") — a
|
|
101
|
+
// relative deep link never needs the "<model-key>/slices/<key>.html"
|
|
102
|
+
// prefix when it's already pointing at the page it's sitting on. The
|
|
103
|
+
// full portable citation (what elementDeepLink returns) is shown as
|
|
104
|
+
// the visible, copyable permalink text instead, so a reader can grab
|
|
105
|
+
// the whole address without leaving the page.
|
|
106
|
+
const deepLink = elementDeepLink(modelKey, el.ref);
|
|
107
|
+
return ` <tr id="${escapeHtml(el.ref)}">
|
|
108
|
+
<td>${escapeHtml(el.kind)}</td>
|
|
109
|
+
<td>${escapeHtml(el.name)}</td>
|
|
110
|
+
<td>${elementDetail(el)}${annotations.join("")}</td>
|
|
111
|
+
<td class="permalink"><a href="#${escapeHtml(el.ref)}" title="Deep link: ${escapeHtml(deepLink)}">#${escapeHtml(el.ref)}</a></td>
|
|
112
|
+
</tr>`;
|
|
113
|
+
})
|
|
114
|
+
.join("\n");
|
|
115
|
+
return ` <table>
|
|
116
|
+
<thead><tr><th>Kind</th><th>Name</th><th>Detail</th><th>Ref</th></tr></thead>
|
|
117
|
+
<tbody>
|
|
118
|
+
${rows}
|
|
119
|
+
</tbody>
|
|
120
|
+
</table>`;
|
|
121
|
+
}
|
|
122
|
+
export function renderSlicePage(args) {
|
|
123
|
+
const { modelName, diagramFile, sliceDiagramFile, slice, pattern, doc, docBodyHtml } = args;
|
|
124
|
+
const docSection = docBodyHtml
|
|
125
|
+
? ` <div class="doc">${docBodyHtml}</div>`
|
|
126
|
+
: ` <p class="no-doc">${doc.found ? `Doc bound at <code>${escapeHtml(doc.path)}</code> but has no rendered body.` : `No slice doc bound. Expected at <code>${escapeHtml(doc.path)}</code>.`}</p>`;
|
|
127
|
+
const body = ` <h1>${escapeHtml(slice.name)}</h1>
|
|
128
|
+
<p class="pattern">${escapeHtml(PATTERN_LABEL[pattern])}</p>
|
|
129
|
+
<div class="stat-row">
|
|
130
|
+
<div class="stat"><span class="label">Status</span>${statusBadge(doc.status)}</div>
|
|
131
|
+
<div class="stat"><span class="label">Drift signal</span>${driftBadge(doc.driftSignal)}</div>
|
|
132
|
+
<div class="stat"><span class="label">Implemented in</span>${implementedInHtml(doc.implementedIn)}</div>
|
|
133
|
+
<div class="stat"><span class="label">Ratified by</span>${ratifiedByHtml(doc.ratifiedBy, doc.ratifiedOn)}</div>
|
|
134
|
+
</div>
|
|
135
|
+
${ownerTrackingHtml(doc.owner, doc.tracking)} <div class="diagram-frame"><object class="diagram" type="image/svg+xml" data="${escapeHtml(sliceDiagramFile)}"></object></div>
|
|
136
|
+
<p class="full-diagram-link"><a href="${escapeHtml(diagramFile)}">View full model diagram →</a></p>
|
|
137
|
+
${renderElementsTable(slice.elements, args.modelKey)}
|
|
138
|
+
${docSection}`;
|
|
139
|
+
return layout(`${slice.name} — ${modelName}`, body, "../../index.html", [
|
|
140
|
+
{ label: modelName, href: ".." },
|
|
141
|
+
{ label: slice.name, href: "." },
|
|
142
|
+
]);
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=slice.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slice.js","sourceRoot":"","sources":["../../src/pages/slice.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { SlicePattern } from "../em/exportDoc.js";
|
|
2
|
+
import { CrossModelLink } from "../crossModel.js";
|
|
3
|
+
export interface SliceSummary {
|
|
4
|
+
key: string;
|
|
5
|
+
name: string;
|
|
6
|
+
pattern: SlicePattern;
|
|
7
|
+
hasDoc: boolean;
|
|
8
|
+
status: string | null;
|
|
9
|
+
driftSignal: string | null;
|
|
10
|
+
}
|
|
11
|
+
export interface ModelSummary {
|
|
12
|
+
key: string;
|
|
13
|
+
name: string;
|
|
14
|
+
file: string;
|
|
15
|
+
sliceCount: number;
|
|
16
|
+
slices: SliceSummary[];
|
|
17
|
+
}
|
|
18
|
+
export interface PortalSummary {
|
|
19
|
+
title: string;
|
|
20
|
+
models: ModelSummary[];
|
|
21
|
+
crossModelLinks: CrossModelLink[];
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/pages/types.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,uEAAuE"}
|
package/dist/refs.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface ParsedElementRef {
|
|
2
|
+
sliceKey: string;
|
|
3
|
+
kind: string;
|
|
4
|
+
slug: string;
|
|
5
|
+
}
|
|
6
|
+
/** Splits an `em export` element ref (`<sliceKey>/<kind>.<slug>`) into its
|
|
7
|
+
* three parts. `sliceKey` never contains `/` or `.` (kebab-slug, dedupe
|
|
8
|
+
* suffix `~2`/`~3`/... only); `kind` is a single bare word (`ui`, `command`,
|
|
9
|
+
* `event`, ...) and never contains `.`, so splitting on the FIRST `.` after
|
|
10
|
+
* the slice-key boundary is always unambiguous even though `slug` itself
|
|
11
|
+
* can carry a `~2`-style suffix. Throws on a string that doesn't have the
|
|
12
|
+
* `/` + `.` shape at all — a caller should never see that for a ref that
|
|
13
|
+
* actually came from `em export`. */
|
|
14
|
+
export declare function parseElementRef(ref: string): ParsedElementRef;
|
|
15
|
+
/** The page URL for a whole slice, relative to the site root. */
|
|
16
|
+
export declare function sliceUrl(modelKey: string, sliceKey: string): string;
|
|
17
|
+
/** The full portable deep link to one element: the slice page's URL plus a
|
|
18
|
+
* `#`-fragment of its own `em export` ref. Portable in the sense that it's
|
|
19
|
+
* exactly what you'd bookmark, paste into a doc, or hand to another tool —
|
|
20
|
+
* resolving it never requires knowing anything beyond the model key (a
|
|
21
|
+
* portal-build-time choice) and the ref itself (an em-export-time one). */
|
|
22
|
+
export declare function elementDeepLink(modelKey: string, ref: string): string;
|
|
23
|
+
export interface ParsedDeepLink {
|
|
24
|
+
modelKey: string;
|
|
25
|
+
sliceKey: string;
|
|
26
|
+
/** The element ref's `<kind>.<slug>` fragment, or `null` for a slice-level
|
|
27
|
+
* link with no element fragment. */
|
|
28
|
+
elementRef: string | null;
|
|
29
|
+
}
|
|
30
|
+
/** The inverse of `sliceUrl`/`elementDeepLink` — parses a portal-relative
|
|
31
|
+
* deep link back into its model/slice/element parts. Returns `null` for
|
|
32
|
+
* anything that isn't shaped like a page this portal generates (the site's
|
|
33
|
+
* own `index.html`, an external URL, ...), rather than throwing — a caller
|
|
34
|
+
* resolving an arbitrary string should treat "not a portal deep link" as a
|
|
35
|
+
* normal outcome. */
|
|
36
|
+
export declare function parseDeepLink(link: string): ParsedDeepLink | null;
|
package/dist/refs.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// MIL-173: the portal's URL scheme, built entirely on `em export`'s own
|
|
3
|
+
// stable identifiers — a slice's `key` and an element's `ref`
|
|
4
|
+
// (`<sliceKey>/<kind>.<slug>`, docs/cli.md in the em repo). One addressing
|
|
5
|
+
// scheme for both audiences: an agent citing a ref via `em query`/MCP and a
|
|
6
|
+
// stakeholder clicking a portal link name the same element, and the scheme
|
|
7
|
+
// survives re-renders and model growth because it depends only on export's
|
|
8
|
+
// ref-stability guarantee (inserting/reordering slices never changes an
|
|
9
|
+
// existing ref) — never on layout, coordinates, or this portal's own
|
|
10
|
+
// directory-naming choices for a model (`src/slug.ts`, portal-local, not
|
|
11
|
+
// part of the addressing scheme itself).
|
|
12
|
+
//
|
|
13
|
+
// A slice page's URL already IS that slice's export key
|
|
14
|
+
// (`<model-key>/slices/<sliceKey>.html`) — no separate per-element page is
|
|
15
|
+
// needed, since an element's ref always starts with its own slice's key.
|
|
16
|
+
// An element-level deep link is that same page plus a `#`-fragment of the
|
|
17
|
+
// element's full ref, so `<model-key>/slices/<sliceKey>.html#<ref>` and
|
|
18
|
+
// `<model-key>/<ref>` carry the exact same three pieces of information
|
|
19
|
+
// (model, slice, element) — just spelled with `/slices/` and `.html#`
|
|
20
|
+
// standing in for the ref's own internal `/`.
|
|
21
|
+
/** Splits an `em export` element ref (`<sliceKey>/<kind>.<slug>`) into its
|
|
22
|
+
* three parts. `sliceKey` never contains `/` or `.` (kebab-slug, dedupe
|
|
23
|
+
* suffix `~2`/`~3`/... only); `kind` is a single bare word (`ui`, `command`,
|
|
24
|
+
* `event`, ...) and never contains `.`, so splitting on the FIRST `.` after
|
|
25
|
+
* the slice-key boundary is always unambiguous even though `slug` itself
|
|
26
|
+
* can carry a `~2`-style suffix. Throws on a string that doesn't have the
|
|
27
|
+
* `/` + `.` shape at all — a caller should never see that for a ref that
|
|
28
|
+
* actually came from `em export`. */
|
|
29
|
+
export function parseElementRef(ref) {
|
|
30
|
+
const slashIndex = ref.indexOf("/");
|
|
31
|
+
if (slashIndex === -1) {
|
|
32
|
+
throw new Error(`not an em export element ref (missing "/"): ${ref}`);
|
|
33
|
+
}
|
|
34
|
+
const sliceKey = ref.slice(0, slashIndex);
|
|
35
|
+
const rest = ref.slice(slashIndex + 1);
|
|
36
|
+
const dotIndex = rest.indexOf(".");
|
|
37
|
+
if (dotIndex === -1) {
|
|
38
|
+
throw new Error(`not an em export element ref (missing "." after "/"): ${ref}`);
|
|
39
|
+
}
|
|
40
|
+
return { sliceKey, kind: rest.slice(0, dotIndex), slug: rest.slice(dotIndex + 1) };
|
|
41
|
+
}
|
|
42
|
+
/** The page URL for a whole slice, relative to the site root. */
|
|
43
|
+
export function sliceUrl(modelKey, sliceKey) {
|
|
44
|
+
return `${modelKey}/slices/${sliceKey}.html`;
|
|
45
|
+
}
|
|
46
|
+
/** The full portable deep link to one element: the slice page's URL plus a
|
|
47
|
+
* `#`-fragment of its own `em export` ref. Portable in the sense that it's
|
|
48
|
+
* exactly what you'd bookmark, paste into a doc, or hand to another tool —
|
|
49
|
+
* resolving it never requires knowing anything beyond the model key (a
|
|
50
|
+
* portal-build-time choice) and the ref itself (an em-export-time one). */
|
|
51
|
+
export function elementDeepLink(modelKey, ref) {
|
|
52
|
+
const { sliceKey } = parseElementRef(ref);
|
|
53
|
+
return `${sliceUrl(modelKey, sliceKey)}#${ref}`;
|
|
54
|
+
}
|
|
55
|
+
const DEEP_LINK_PATTERN = /^([^/]+)\/slices\/([^/]+)\.html(?:#(.+))?$/;
|
|
56
|
+
/** The inverse of `sliceUrl`/`elementDeepLink` — parses a portal-relative
|
|
57
|
+
* deep link back into its model/slice/element parts. Returns `null` for
|
|
58
|
+
* anything that isn't shaped like a page this portal generates (the site's
|
|
59
|
+
* own `index.html`, an external URL, ...), rather than throwing — a caller
|
|
60
|
+
* resolving an arbitrary string should treat "not a portal deep link" as a
|
|
61
|
+
* normal outcome. */
|
|
62
|
+
export function parseDeepLink(link) {
|
|
63
|
+
const match = DEEP_LINK_PATTERN.exec(link);
|
|
64
|
+
if (!match)
|
|
65
|
+
return null;
|
|
66
|
+
const [, modelKey, sliceKey, elementRef] = match;
|
|
67
|
+
return { modelKey, sliceKey, elementRef: elementRef ?? null };
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=refs.js.map
|
package/dist/refs.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refs.js","sourceRoot":"","sources":["../src/refs.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,wEAAwE;AACxE,8DAA8D;AAC9D,2EAA2E;AAC3E,4EAA4E;AAC5E,2EAA2E;AAC3E,2EAA2E;AAC3E,wEAAwE;AACxE,qEAAqE;AACrE,yEAAyE;AACzE,yCAAyC;AACzC,EAAE;AACF,wDAAwD;AACxD,2EAA2E;AAC3E,yEAAyE;AACzE,0EAA0E;AAC1E,wEAAwE;AACxE,uEAAuE;AACvE,sEAAsE;AACtE,8CAA8C;AAQ9C;;;;;;;sCAOsC;AACtC,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,UAAU,KAAK,CAAC,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,+CAA+C,GAAG,EAAE,CAAC,CAAC;IACxE,CAAC;IACD,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC;IACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,yDAAyD,GAAG,EAAE,CAAC,CAAC;IAClF,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,EAAE,CAAC;AACrF,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,QAAQ,CAAC,QAAgB,EAAE,QAAgB;IACzD,OAAO,GAAG,QAAQ,WAAW,QAAQ,OAAO,CAAC;AAC/C,CAAC;AAED;;;;4EAI4E;AAC5E,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,GAAW;IAC3D,MAAM,EAAE,QAAQ,EAAE,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IAC1C,OAAO,GAAG,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,IAAI,GAAG,EAAE,CAAC;AAClD,CAAC;AAUD,MAAM,iBAAiB,GAAG,4CAA4C,CAAC;AAEvE;;;;;sBAKsB;AACtB,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3C,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,CAAC,GAAG,KAAK,CAAC;IACjD,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,IAAI,IAAI,EAAE,CAAC;AAChE,CAAC"}
|
package/dist/slug.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function kebabSlug(name: string): string;
|
|
2
|
+
/** Returns a slug unique within `used`, suffixing `~2`, `~3`, ... on collision
|
|
3
|
+
* (same separator em's own dedupe() uses, for a familiar convention) and
|
|
4
|
+
* records the chosen value into `used` before returning it. */
|
|
5
|
+
export declare function dedupe(candidate: string, used: Set<string>): string;
|
package/dist/slug.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Portal-local slug/dedupe helpers for naming output directories (one per
|
|
3
|
+
// input model, mirroring `em catalog`'s convention). Deliberately NOT shared
|
|
4
|
+
// code with em's own src/util/slug.ts — em-portal is a separate package with
|
|
5
|
+
// no access to em's internals (see docs/decisions/mil-162-teachable-navigator.md
|
|
6
|
+
// in the em repo); slice keys and element refs always come straight from
|
|
7
|
+
// `em export`'s own JSON instead of being re-derived here.
|
|
8
|
+
export function kebabSlug(name) {
|
|
9
|
+
return name
|
|
10
|
+
.trim()
|
|
11
|
+
.toLowerCase()
|
|
12
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
13
|
+
.replace(/^-+|-+$/g, "") || "model";
|
|
14
|
+
}
|
|
15
|
+
/** Returns a slug unique within `used`, suffixing `~2`, `~3`, ... on collision
|
|
16
|
+
* (same separator em's own dedupe() uses, for a familiar convention) and
|
|
17
|
+
* records the chosen value into `used` before returning it. */
|
|
18
|
+
export function dedupe(candidate, used) {
|
|
19
|
+
if (!used.has(candidate)) {
|
|
20
|
+
used.add(candidate);
|
|
21
|
+
return candidate;
|
|
22
|
+
}
|
|
23
|
+
let n = 2;
|
|
24
|
+
while (used.has(`${candidate}~${n}`))
|
|
25
|
+
n++;
|
|
26
|
+
const deduped = `${candidate}~${n}`;
|
|
27
|
+
used.add(deduped);
|
|
28
|
+
return deduped;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=slug.js.map
|
package/dist/slug.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slug.js","sourceRoot":"","sources":["../src/slug.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,0EAA0E;AAC1E,6EAA6E;AAC7E,6EAA6E;AAC7E,iFAAiF;AACjF,yEAAyE;AACzE,2DAA2D;AAE3D,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,IAAI;SACR,IAAI,EAAE;SACN,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC;AACxC,CAAC;AAED;;gEAEgE;AAChE,MAAM,UAAU,MAAM,CAAC,SAAiB,EAAE,IAAiB;IACzD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;QACzB,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACpB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,SAAS,IAAI,CAAC,EAAE,CAAC;QAAE,CAAC,EAAE,CAAC;IAC1C,MAAM,OAAO,GAAG,GAAG,SAAS,IAAI,CAAC,EAAE,CAAC;IACpC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAClB,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@milehimikey/em-portal",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Stakeholder-facing static portal for em event models — a multi-model, read-only browser built from `em export`/`em status --json`",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"em-portal": "./dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/cli.js",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc -p tsconfig.json",
|
|
17
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
18
|
+
"dev": "tsx src/cli.ts",
|
|
19
|
+
"em-portal": "tsx src/cli.ts",
|
|
20
|
+
"test": "vitest run",
|
|
21
|
+
"test:watch": "vitest",
|
|
22
|
+
"pretest": "npm run build",
|
|
23
|
+
"prepublishOnly": "npm run build && npm run typecheck && npm test"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18"
|
|
27
|
+
},
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"author": "milehimikey",
|
|
30
|
+
"homepage": "https://github.com/milehimikey/em-portal#readme",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "git+https://github.com/milehimikey/em-portal.git"
|
|
34
|
+
},
|
|
35
|
+
"bugs": {
|
|
36
|
+
"url": "https://github.com/milehimikey/em-portal/issues"
|
|
37
|
+
},
|
|
38
|
+
"keywords": [
|
|
39
|
+
"event-modeling",
|
|
40
|
+
"portal",
|
|
41
|
+
"static-site",
|
|
42
|
+
"dashboard",
|
|
43
|
+
"cli"
|
|
44
|
+
],
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"commander": "^12.1.0",
|
|
50
|
+
"marked": "^18.0.11"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@milehimikey/em": "file:vendor/milehimikey-em-1.8.1.tgz",
|
|
54
|
+
"@types/node": "^22.0.0",
|
|
55
|
+
"jsdom": "^26.1.0",
|
|
56
|
+
"tsx": "^4.19.0",
|
|
57
|
+
"typescript": "^5.6.0",
|
|
58
|
+
"vitest": "^4.1.10"
|
|
59
|
+
}
|
|
60
|
+
}
|