@the-package-labs/idocs-core 0.3.1 → 0.5.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/dist/browser.js +2 -2
- package/dist/chunk-P2X2XSBM.js +127 -0
- package/dist/{chunk-5BMICZRC.js → chunk-Q2NHZ6TV.js} +214 -40
- package/dist/{chunk-FRVCGXIG.js → chunk-ZYFFV7Y7.js} +35 -3
- package/dist/compiler.d.ts +11 -0
- package/dist/defaults.d.ts +2 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +338 -2
- package/dist/nested-layout.d.ts +69 -0
- package/dist/nesting.d.ts +24 -0
- package/dist/node.d.ts +1 -0
- package/dist/node.js +15 -3
- package/dist/outline.d.ts +63 -0
- package/dist/phases.d.ts +16 -0
- package/dist/schema.d.ts +69 -0
- package/dist/scrubber.d.ts +34 -0
- package/dist/start.d.ts +22 -0
- package/dist/suggest.d.ts +1 -0
- package/dist/types.d.ts +50 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
attachNested,
|
|
3
|
+
linkDiagrams,
|
|
4
|
+
nestedDiagrams
|
|
5
|
+
} from "./chunk-P2X2XSBM.js";
|
|
1
6
|
import {
|
|
2
7
|
BUILTIN_EDGE_KINDS,
|
|
3
8
|
BUILTIN_KINDS,
|
|
9
|
+
DEFAULT_ENTITY_WIDTH,
|
|
4
10
|
DEFAULT_NODE_WIDTH,
|
|
5
11
|
STEP_KIND_COLORS,
|
|
6
12
|
dist,
|
|
@@ -8,7 +14,7 @@ import {
|
|
|
8
14
|
pointAt,
|
|
9
15
|
polylineLength,
|
|
10
16
|
roundedPath
|
|
11
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-ZYFFV7Y7.js";
|
|
12
18
|
|
|
13
19
|
// src/layout.ts
|
|
14
20
|
import ELK from "elkjs/lib/elk.bundled.js";
|
|
@@ -951,6 +957,312 @@ function overlap(a, b, pad) {
|
|
|
951
957
|
return a.x < b.x + b.w + pad && a.x + a.w + pad > b.x && a.y < b.y + b.h + pad && a.y + a.h + pad > b.y;
|
|
952
958
|
}
|
|
953
959
|
|
|
960
|
+
// src/nested-layout.ts
|
|
961
|
+
var INLINE_PAD = { top: 40, left: 4, right: 4, bottom: 4 };
|
|
962
|
+
function openingView(diagram, ref) {
|
|
963
|
+
const has = (id) => diagram.views.some((v) => v.id === id);
|
|
964
|
+
const of = (scenario) => diagram.scenarios.find((s) => s.id === scenario)?.view;
|
|
965
|
+
return [ref.view, of(ref.scenario), of(diagram.defaults?.scenario), diagram.defaults?.view].find(
|
|
966
|
+
has
|
|
967
|
+
) ?? diagram.views[0].id;
|
|
968
|
+
}
|
|
969
|
+
var canExpand = (ref, diagrams) => !!ref && ref.mode !== "open" && !!diagrams[ref.name];
|
|
970
|
+
var canOpen = (ref, diagrams) => !!ref && ref.mode !== "expand" && !!diagrams[ref.name];
|
|
971
|
+
var pathJoin = (prefix, id) => `${prefix}${id}`;
|
|
972
|
+
function defaultExpanded(diagram, diagrams, prefix = "", seen = []) {
|
|
973
|
+
const out = [];
|
|
974
|
+
for (const node of Object.values(diagram.nodes)) {
|
|
975
|
+
const ref = node.diagram;
|
|
976
|
+
const child = ref && diagrams[ref.name];
|
|
977
|
+
if (!ref || !child || seen.includes(ref.name) || !ref.expanded || !canExpand(ref, diagrams))
|
|
978
|
+
continue;
|
|
979
|
+
const path = pathJoin(prefix, node.id);
|
|
980
|
+
out.push(path, ...defaultExpanded(child, diagrams, `${path}/`, [...seen, diagram.name]));
|
|
981
|
+
}
|
|
982
|
+
return out;
|
|
983
|
+
}
|
|
984
|
+
function measurable(diagram, viewId, expanded, diagrams, prefix = "") {
|
|
985
|
+
const view = diagram.views.find((v) => v.id === viewId);
|
|
986
|
+
if (!view) return [];
|
|
987
|
+
const out = [];
|
|
988
|
+
for (const id of view.nodeIds) {
|
|
989
|
+
const node = diagram.nodes[id];
|
|
990
|
+
const path = pathJoin(prefix, id);
|
|
991
|
+
out.push({ key: path, node });
|
|
992
|
+
const ref = node.diagram;
|
|
993
|
+
const child = ref && expanded.has(path) && canExpand(ref, diagrams) ? diagrams[ref.name] : void 0;
|
|
994
|
+
if (ref && child) {
|
|
995
|
+
out.push(...measurable(child, openingView(child, ref), expanded, diagrams, `${path}/`));
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
return out;
|
|
999
|
+
}
|
|
1000
|
+
async function layoutNested(diagram, viewId, { sizes = {}, expanded, diagrams = {}, prefix = "" } = {}) {
|
|
1001
|
+
const view = diagram.views.find((v) => v.id === viewId);
|
|
1002
|
+
if (!view) throw new Error(`Unknown view "${viewId}"`);
|
|
1003
|
+
const own = {};
|
|
1004
|
+
for (const id of view.nodeIds) {
|
|
1005
|
+
const size = sizes[pathJoin(prefix, id)];
|
|
1006
|
+
if (size) own[id] = size;
|
|
1007
|
+
}
|
|
1008
|
+
const inner = {};
|
|
1009
|
+
await Promise.all(
|
|
1010
|
+
view.nodeIds.map(async (id) => {
|
|
1011
|
+
const ref = diagram.nodes[id].diagram;
|
|
1012
|
+
const path = pathJoin(prefix, id);
|
|
1013
|
+
const child = ref && expanded?.has(path) && canExpand(ref, diagrams) ? diagrams[ref.name] : void 0;
|
|
1014
|
+
if (!ref || !child) return;
|
|
1015
|
+
const childView = openingView(child, ref);
|
|
1016
|
+
const layout = await layoutNested(child, childView, {
|
|
1017
|
+
sizes,
|
|
1018
|
+
expanded,
|
|
1019
|
+
diagrams,
|
|
1020
|
+
prefix: `${path}/`
|
|
1021
|
+
});
|
|
1022
|
+
inner[id] = {
|
|
1023
|
+
name: ref.name,
|
|
1024
|
+
viewId: childView,
|
|
1025
|
+
offset: { x: INLINE_PAD.left, y: INLINE_PAD.top },
|
|
1026
|
+
layout
|
|
1027
|
+
};
|
|
1028
|
+
own[id] = {
|
|
1029
|
+
w: layout.layout.width + INLINE_PAD.left + INLINE_PAD.right,
|
|
1030
|
+
h: layout.layout.height + INLINE_PAD.top + INLINE_PAD.bottom
|
|
1031
|
+
};
|
|
1032
|
+
})
|
|
1033
|
+
);
|
|
1034
|
+
return { layout: await layoutView(diagram, viewId, own), inner };
|
|
1035
|
+
}
|
|
1036
|
+
function rectOfPath(nested, path) {
|
|
1037
|
+
let level = nested;
|
|
1038
|
+
let at = { x: 0, y: 0 };
|
|
1039
|
+
const ids = path.split("/");
|
|
1040
|
+
for (const [i, id] of ids.entries()) {
|
|
1041
|
+
const r = level?.layout.nodes[id];
|
|
1042
|
+
if (!level || !r) return void 0;
|
|
1043
|
+
if (i === ids.length - 1) return { x: at.x + r.x, y: at.y + r.y, w: r.w, h: r.h };
|
|
1044
|
+
const inner = level.inner[id];
|
|
1045
|
+
if (!inner) return void 0;
|
|
1046
|
+
at = { x: at.x + r.x + inner.offset.x, y: at.y + r.y + inner.offset.y };
|
|
1047
|
+
level = inner.layout;
|
|
1048
|
+
}
|
|
1049
|
+
return void 0;
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
// src/outline.ts
|
|
1053
|
+
function buildOutline(diagram, view, { diagrams = {}, expanded = /* @__PURE__ */ new Set(), prefix = "", seen = [] } = {}) {
|
|
1054
|
+
const inView = new Set(view.nodeIds);
|
|
1055
|
+
const groups = new Set(view.groupIds);
|
|
1056
|
+
const drawn = view.edgeIds.map((id) => diagram.edges[id]).filter((e) => !e.hidden);
|
|
1057
|
+
const connectionsOf = (id) => {
|
|
1058
|
+
const out = [];
|
|
1059
|
+
for (const e of drawn) {
|
|
1060
|
+
const sends = e.from === id;
|
|
1061
|
+
const gets = e.to === id;
|
|
1062
|
+
if (!sends && !gets) continue;
|
|
1063
|
+
const other = sends ? e.to : e.from;
|
|
1064
|
+
out.push({
|
|
1065
|
+
edge: e.id,
|
|
1066
|
+
dir: e.both ? "both" : sends ? "out" : "in",
|
|
1067
|
+
other,
|
|
1068
|
+
otherTitle: diagram.nodes[other]?.title ?? other,
|
|
1069
|
+
label: e.label,
|
|
1070
|
+
kind: e.kind,
|
|
1071
|
+
status: e.status
|
|
1072
|
+
});
|
|
1073
|
+
}
|
|
1074
|
+
const rank = { out: 0, both: 1, in: 2 };
|
|
1075
|
+
return out.sort((a, b) => rank[a.dir] - rank[b.dir]);
|
|
1076
|
+
};
|
|
1077
|
+
const nodeItem = (id) => {
|
|
1078
|
+
const node = diagram.nodes[id];
|
|
1079
|
+
const path = pathJoin(prefix, id);
|
|
1080
|
+
const item = {
|
|
1081
|
+
type: "node",
|
|
1082
|
+
path,
|
|
1083
|
+
id,
|
|
1084
|
+
title: node.title,
|
|
1085
|
+
sub: node.sub,
|
|
1086
|
+
icon: node.icon,
|
|
1087
|
+
status: node.status,
|
|
1088
|
+
connections: connectionsOf(id)
|
|
1089
|
+
};
|
|
1090
|
+
const ref = node.diagram;
|
|
1091
|
+
const child = ref && diagrams[ref.name];
|
|
1092
|
+
if (ref && child && !seen.includes(ref.name) && (canExpand(ref, diagrams) || canOpen(ref, diagrams))) {
|
|
1093
|
+
const shown = canExpand(ref, diagrams) && expanded.has(path);
|
|
1094
|
+
const childView = child.views.find((v) => v.id === openingView(child, ref));
|
|
1095
|
+
item.inside = {
|
|
1096
|
+
title: child.title,
|
|
1097
|
+
expand: canExpand(ref, diagrams),
|
|
1098
|
+
open: canOpen(ref, diagrams),
|
|
1099
|
+
expanded: shown,
|
|
1100
|
+
items: shown && childView ? buildOutline(child, childView, {
|
|
1101
|
+
diagrams,
|
|
1102
|
+
expanded,
|
|
1103
|
+
prefix: `${path}/`,
|
|
1104
|
+
seen: [...seen, diagram.name]
|
|
1105
|
+
}) : []
|
|
1106
|
+
};
|
|
1107
|
+
}
|
|
1108
|
+
return item;
|
|
1109
|
+
};
|
|
1110
|
+
const childGroups = /* @__PURE__ */ new Map();
|
|
1111
|
+
for (const gid of view.groupIds) {
|
|
1112
|
+
const parent = diagram.groups[gid]?.parent;
|
|
1113
|
+
const key = parent && groups.has(parent) ? parent : "";
|
|
1114
|
+
childGroups.set(key, [...childGroups.get(key) ?? [], gid]);
|
|
1115
|
+
}
|
|
1116
|
+
const childNodes = /* @__PURE__ */ new Map();
|
|
1117
|
+
for (const id of view.nodeIds) {
|
|
1118
|
+
if (!inView.has(id)) continue;
|
|
1119
|
+
const group = diagram.nodes[id].group;
|
|
1120
|
+
const key = group && groups.has(group) ? group : "";
|
|
1121
|
+
childNodes.set(key, [...childNodes.get(key) ?? [], id]);
|
|
1122
|
+
}
|
|
1123
|
+
const position = new Map(view.nodeIds.map((id, i) => [id, i]));
|
|
1124
|
+
const firstNode = (gid) => Math.min(
|
|
1125
|
+
...(childNodes.get(gid) ?? []).map((n) => position.get(n)),
|
|
1126
|
+
...(childGroups.get(gid) ?? []).map(firstNode)
|
|
1127
|
+
);
|
|
1128
|
+
const groupItem = (gid) => {
|
|
1129
|
+
const g = diagram.groups[gid];
|
|
1130
|
+
const items = fill(gid);
|
|
1131
|
+
return {
|
|
1132
|
+
type: "group",
|
|
1133
|
+
path: pathJoin(prefix, `#${gid}`),
|
|
1134
|
+
id: gid,
|
|
1135
|
+
title: g.label,
|
|
1136
|
+
caption: g.caption,
|
|
1137
|
+
icon: g.icon,
|
|
1138
|
+
status: g.status,
|
|
1139
|
+
items,
|
|
1140
|
+
count: items.reduce((n, i) => n + (i.type === "group" ? i.count : 1), 0)
|
|
1141
|
+
};
|
|
1142
|
+
};
|
|
1143
|
+
function fill(key) {
|
|
1144
|
+
const ranked = [
|
|
1145
|
+
...(childGroups.get(key) ?? []).map((gid) => ({
|
|
1146
|
+
at: firstNode(gid),
|
|
1147
|
+
make: () => groupItem(gid)
|
|
1148
|
+
})),
|
|
1149
|
+
...(childNodes.get(key) ?? []).map((id) => ({
|
|
1150
|
+
at: position.get(id),
|
|
1151
|
+
make: () => nodeItem(id)
|
|
1152
|
+
}))
|
|
1153
|
+
];
|
|
1154
|
+
return ranked.sort((a, b) => a.at - b.at).map((r) => r.make());
|
|
1155
|
+
}
|
|
1156
|
+
return fill("");
|
|
1157
|
+
}
|
|
1158
|
+
function outlineNodes(items) {
|
|
1159
|
+
const out = [];
|
|
1160
|
+
for (const item of items) {
|
|
1161
|
+
if (item.type === "group") out.push(...outlineNodes(item.items));
|
|
1162
|
+
else out.push(item, ...outlineNodes(item.inside?.items ?? []));
|
|
1163
|
+
}
|
|
1164
|
+
return out;
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
// src/phases.ts
|
|
1168
|
+
var hasPhases = (scenario) => scenario.phases.some((p) => p.title);
|
|
1169
|
+
function phaseSpans(scenario) {
|
|
1170
|
+
const out = [];
|
|
1171
|
+
scenario.steps.forEach((step, i) => {
|
|
1172
|
+
const last = out[out.length - 1];
|
|
1173
|
+
if (last && last.index === step.phase) {
|
|
1174
|
+
last.to = i;
|
|
1175
|
+
last.count++;
|
|
1176
|
+
return;
|
|
1177
|
+
}
|
|
1178
|
+
const phase = scenario.phases[step.phase];
|
|
1179
|
+
out.push({
|
|
1180
|
+
index: step.phase,
|
|
1181
|
+
title: phase?.title ?? "",
|
|
1182
|
+
caption: phase?.caption,
|
|
1183
|
+
from: i,
|
|
1184
|
+
to: i,
|
|
1185
|
+
count: 1
|
|
1186
|
+
});
|
|
1187
|
+
});
|
|
1188
|
+
return out;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
// src/scrubber.ts
|
|
1192
|
+
function buildScrubber(tl) {
|
|
1193
|
+
const steps = tl.scenario.steps;
|
|
1194
|
+
const slots = [];
|
|
1195
|
+
let i = 0;
|
|
1196
|
+
while (i < steps.length) {
|
|
1197
|
+
let j = i + 1;
|
|
1198
|
+
const par = steps[i].par;
|
|
1199
|
+
if (par !== void 0) while (j < steps.length && steps[j].par === par) j++;
|
|
1200
|
+
const run = tl.steps.slice(i, j);
|
|
1201
|
+
slots.push({ from: i, to: j - 1, t0: Math.min(...run.map((s) => s.start)), t1: 0 });
|
|
1202
|
+
i = j;
|
|
1203
|
+
}
|
|
1204
|
+
slots.forEach((slot, k) => {
|
|
1205
|
+
slot.t1 = slots[k + 1]?.t0 ?? tl.duration;
|
|
1206
|
+
});
|
|
1207
|
+
if (slots[0]) slots[0].t0 = 0;
|
|
1208
|
+
const slotOf = (step) => slots.findIndex((s) => s.from <= step && step <= s.to);
|
|
1209
|
+
const sections = phaseSpans(tl.scenario).map((span) => ({
|
|
1210
|
+
phase: span.index,
|
|
1211
|
+
title: span.title,
|
|
1212
|
+
caption: span.caption,
|
|
1213
|
+
from: slotOf(span.from),
|
|
1214
|
+
to: slotOf(span.to)
|
|
1215
|
+
}));
|
|
1216
|
+
return { slots, sections, duration: tl.duration };
|
|
1217
|
+
}
|
|
1218
|
+
var clamp01 = (n) => Math.min(1, Math.max(0, n));
|
|
1219
|
+
function positionAt(s, t) {
|
|
1220
|
+
const n = s.slots.length;
|
|
1221
|
+
if (!n) return 0;
|
|
1222
|
+
let k = 0;
|
|
1223
|
+
s.slots.forEach((slot2, i) => {
|
|
1224
|
+
if (slot2.t0 <= t) k = i;
|
|
1225
|
+
});
|
|
1226
|
+
const slot = s.slots[k];
|
|
1227
|
+
const length = slot.t1 - slot.t0;
|
|
1228
|
+
return (k + (length > 0 ? clamp01((t - slot.t0) / length) : 0)) / n;
|
|
1229
|
+
}
|
|
1230
|
+
function timeAt(s, position) {
|
|
1231
|
+
const n = s.slots.length;
|
|
1232
|
+
if (!n) return 0;
|
|
1233
|
+
const x = clamp01(position) * n;
|
|
1234
|
+
const k = Math.min(n - 1, Math.floor(x));
|
|
1235
|
+
const slot = s.slots[k];
|
|
1236
|
+
return slot.t0 + (x - k) * (slot.t1 - slot.t0);
|
|
1237
|
+
}
|
|
1238
|
+
function slotAt(s, position) {
|
|
1239
|
+
const n = s.slots.length;
|
|
1240
|
+
return n ? Math.min(n - 1, Math.floor(clamp01(position) * n)) : -1;
|
|
1241
|
+
}
|
|
1242
|
+
function slotOfStep(s, index) {
|
|
1243
|
+
return s.slots.findIndex((slot) => slot.from <= index && index <= slot.to);
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
// src/start.ts
|
|
1247
|
+
var defaultMode = (diagram) => diagram.defaults?.mode ?? "flow";
|
|
1248
|
+
function startOf(diagram, want = {}) {
|
|
1249
|
+
const d = diagram.defaults ?? {};
|
|
1250
|
+
const scenarioById = (id) => diagram.scenarios.find((s) => s.id === id);
|
|
1251
|
+
const hasView = (id) => diagram.views.some((v) => v.id === id);
|
|
1252
|
+
const first = diagram.views[0].id;
|
|
1253
|
+
let view;
|
|
1254
|
+
let scenario;
|
|
1255
|
+
if (want.view !== void 0 || want.scenario !== void 0) {
|
|
1256
|
+
view = [want.view, scenarioById(want.scenario)?.view].find(hasView) ?? first;
|
|
1257
|
+
scenario = scenarioById(want.scenario)?.id ?? (scenarioById(d.scenario)?.view === view ? d.scenario ?? null : null);
|
|
1258
|
+
} else {
|
|
1259
|
+
scenario = scenarioById(d.scenario)?.id ?? null;
|
|
1260
|
+
view = [scenarioById(scenario ?? void 0)?.view, d.view].find(hasView) ?? first;
|
|
1261
|
+
}
|
|
1262
|
+
const mode = want.mode ?? scenarioById(scenario ?? void 0)?.mode ?? defaultMode(diagram);
|
|
1263
|
+
return { view, scenario, mode };
|
|
1264
|
+
}
|
|
1265
|
+
|
|
954
1266
|
// src/story.ts
|
|
955
1267
|
function buildStory(diagram, scenario) {
|
|
956
1268
|
const steps = scenario.steps;
|
|
@@ -1249,23 +1561,47 @@ function runBounds(tl, index) {
|
|
|
1249
1561
|
export {
|
|
1250
1562
|
BUILTIN_EDGE_KINDS,
|
|
1251
1563
|
BUILTIN_KINDS,
|
|
1564
|
+
DEFAULT_ENTITY_WIDTH,
|
|
1252
1565
|
DEFAULT_NODE_WIDTH,
|
|
1566
|
+
INLINE_PAD,
|
|
1253
1567
|
STEP_KIND_COLORS,
|
|
1568
|
+
attachNested,
|
|
1569
|
+
buildOutline,
|
|
1570
|
+
buildScrubber,
|
|
1254
1571
|
buildStory,
|
|
1255
1572
|
buildTimeline,
|
|
1573
|
+
canExpand,
|
|
1574
|
+
canOpen,
|
|
1575
|
+
defaultExpanded,
|
|
1576
|
+
defaultMode,
|
|
1256
1577
|
dist,
|
|
1257
1578
|
frameAt,
|
|
1579
|
+
hasPhases,
|
|
1258
1580
|
labelWidth,
|
|
1581
|
+
layoutNested,
|
|
1259
1582
|
layoutView,
|
|
1260
1583
|
letterKey,
|
|
1584
|
+
linkDiagrams,
|
|
1585
|
+
measurable,
|
|
1586
|
+
nestedDiagrams,
|
|
1587
|
+
openingView,
|
|
1588
|
+
outlineNodes,
|
|
1261
1589
|
packGrid,
|
|
1590
|
+
pathJoin,
|
|
1591
|
+
phaseSpans,
|
|
1262
1592
|
pointAt,
|
|
1263
1593
|
polylineLength,
|
|
1594
|
+
positionAt,
|
|
1595
|
+
rectOfPath,
|
|
1264
1596
|
roundedPath,
|
|
1265
1597
|
routeEdges,
|
|
1266
1598
|
runBounds,
|
|
1267
1599
|
scopeSvgIds,
|
|
1600
|
+
slotAt,
|
|
1601
|
+
slotOfStep,
|
|
1602
|
+
startOf,
|
|
1268
1603
|
stepAt,
|
|
1269
1604
|
stepEnd,
|
|
1270
|
-
stepStart
|
|
1605
|
+
stepStart,
|
|
1606
|
+
timeAt
|
|
1271
1607
|
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { type NodeSize } from './layout';
|
|
2
|
+
import type { CompiledDiagram, CompiledNode, Layout, NodeDiagram, Pt, Rect } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* What an expanded node adds around the inner diagram: the header that names it, and a margin.
|
|
5
|
+
* The inner layout already keeps a margin of its own, so the sides stay thin.
|
|
6
|
+
*/
|
|
7
|
+
export declare const INLINE_PAD: {
|
|
8
|
+
top: number;
|
|
9
|
+
left: number;
|
|
10
|
+
right: number;
|
|
11
|
+
bottom: number;
|
|
12
|
+
};
|
|
13
|
+
/** A diagram laid out together with the diagrams expanded inside it, at any depth. */
|
|
14
|
+
export interface NestedLayout {
|
|
15
|
+
layout: Layout;
|
|
16
|
+
/** By node id: the layout of the diagram that node shows in place. */
|
|
17
|
+
inner: Record<string, InnerLayout>;
|
|
18
|
+
}
|
|
19
|
+
export interface InnerLayout {
|
|
20
|
+
/** Name of the diagram shown. */
|
|
21
|
+
name: string;
|
|
22
|
+
viewId: string;
|
|
23
|
+
/** Where the inner diagram's origin sits inside the expanded node's rectangle. */
|
|
24
|
+
offset: Pt;
|
|
25
|
+
layout: NestedLayout;
|
|
26
|
+
}
|
|
27
|
+
export type Diagrams = Record<string, CompiledDiagram | undefined>;
|
|
28
|
+
/**
|
|
29
|
+
* The view a node's diagram shows when opened: the one the node names, its scenario's, the one the
|
|
30
|
+
* diagram opens on by itself, or the first.
|
|
31
|
+
*/
|
|
32
|
+
export declare function openingView(diagram: CompiledDiagram, ref: NodeDiagram): string;
|
|
33
|
+
/** Whether a reader may show this node's diagram in place: it is at hand and not limited to `open`. */
|
|
34
|
+
export declare const canExpand: (ref: NodeDiagram | undefined, diagrams: Diagrams) => boolean;
|
|
35
|
+
/** Whether a reader may move into this node's diagram: it is at hand and not limited to `expand`. */
|
|
36
|
+
export declare const canOpen: (ref: NodeDiagram | undefined, diagrams: Diagrams) => boolean;
|
|
37
|
+
/** Paths are node ids joined with `/` (ids cannot contain it): `orders`, `orders/stock`. */
|
|
38
|
+
export declare const pathJoin: (prefix: string, id: string) => string;
|
|
39
|
+
/**
|
|
40
|
+
* The paths the author asked to start expanded (`expanded: true`), at every depth. A node counts
|
|
41
|
+
* wherever it sits in its diagram, in whichever view, so switching views loses nothing.
|
|
42
|
+
*/
|
|
43
|
+
export declare function defaultExpanded(diagram: CompiledDiagram, diagrams: Diagrams, prefix?: string, seen?: readonly string[]): string[];
|
|
44
|
+
/**
|
|
45
|
+
* Every node whose card has to be measured to lay `viewId` out with these paths expanded: the
|
|
46
|
+
* view's own, and those of each diagram shown in place. `key` is the path, which is what the
|
|
47
|
+
* layout reads sizes by.
|
|
48
|
+
*/
|
|
49
|
+
export declare function measurable(diagram: CompiledDiagram, viewId: string, expanded: ReadonlySet<string>, diagrams: Diagrams, prefix?: string): {
|
|
50
|
+
key: string;
|
|
51
|
+
node: CompiledNode;
|
|
52
|
+
}[];
|
|
53
|
+
export interface NestedOptions {
|
|
54
|
+
/** Measured card sizes by path. A plain node id for the diagram itself, `orders/api` inside. */
|
|
55
|
+
sizes?: Record<string, Partial<NodeSize>>;
|
|
56
|
+
/** Paths shown in place. */
|
|
57
|
+
expanded?: ReadonlySet<string>;
|
|
58
|
+
/** Where the diagrams a node opens are found, by name. */
|
|
59
|
+
diagrams?: Diagrams;
|
|
60
|
+
prefix?: string;
|
|
61
|
+
}
|
|
62
|
+
/** Lay out `viewId` with the nodes in `expanded` shown in place, each as a group around its diagram. */
|
|
63
|
+
export declare function layoutNested(diagram: CompiledDiagram, viewId: string, { sizes, expanded, diagrams, prefix }?: NestedOptions): Promise<NestedLayout>;
|
|
64
|
+
/**
|
|
65
|
+
* Where a node sits in the world of the diagram laid out first, however deep it is: the rectangle
|
|
66
|
+
* of `orders/stock` is `stock`'s inside `orders`, moved to where `orders` is. Undefined when a
|
|
67
|
+
* step of the path is not laid out (it is not expanded, or not in the view).
|
|
68
|
+
*/
|
|
69
|
+
export declare function rectOfPath(nested: NestedLayout, path: string): Rect | undefined;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Diagnostic, Where } from './compiler';
|
|
2
|
+
import type { CompiledDiagram } from './types';
|
|
3
|
+
/** What the linker needs to know about one diagram folder. `diagram` is missing when it failed to compile. */
|
|
4
|
+
export interface LinkEntry {
|
|
5
|
+
diagram?: CompiledDiagram;
|
|
6
|
+
where?: Where;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Every diagram that `name` can reach by opening nodes, directly or through other diagrams, but
|
|
10
|
+
* not `name` itself.
|
|
11
|
+
*/
|
|
12
|
+
export declare function nestedDiagrams(all: Record<string, CompiledDiagram>, name: string): Record<string, CompiledDiagram>;
|
|
13
|
+
/**
|
|
14
|
+
* Give every diagram that opens others the diagrams it can reach, as `nested`, so wherever a
|
|
15
|
+
* compiled diagram goes its insides go with it and the viewer is told nothing. Diagrams that open
|
|
16
|
+
* nothing are returned as they are. Safe to call twice.
|
|
17
|
+
*/
|
|
18
|
+
export declare function attachNested(all: Record<string, CompiledDiagram>): Record<string, CompiledDiagram>;
|
|
19
|
+
/**
|
|
20
|
+
* Check what no single diagram can: that a node opens a diagram which exists, that the view and
|
|
21
|
+
* scenario it asks for exist there, and that diagrams do not open each other in a circle (a node
|
|
22
|
+
* cannot contain itself).
|
|
23
|
+
*/
|
|
24
|
+
export declare function linkDiagrams(entries: Record<string, LinkEntry>): Diagnostic[];
|
package/dist/node.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { CompiledDiagram } from './types';
|
|
|
3
3
|
export * from './compile';
|
|
4
4
|
export { loadIconSets, resolveIcon, searchIcons } from './icons';
|
|
5
5
|
export { renderMarkdown } from './markdown';
|
|
6
|
+
export { attachNested, type LinkEntry, linkDiagrams, nestedDiagrams } from './nesting';
|
|
6
7
|
export { authoringJsonSchema, FamilySchema, KNOWN_KEYS, RootSchema } from './schema';
|
|
7
8
|
export interface LoadedProject {
|
|
8
9
|
diagrams: Record<string, CompiledDiagram>;
|
package/dist/node.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
attachNested,
|
|
3
|
+
linkDiagrams,
|
|
4
|
+
nestedDiagrams
|
|
5
|
+
} from "./chunk-P2X2XSBM.js";
|
|
1
6
|
import {
|
|
2
7
|
FamilySchema,
|
|
3
8
|
KNOWN_KEYS,
|
|
@@ -6,8 +11,8 @@ import {
|
|
|
6
11
|
compileDiagram,
|
|
7
12
|
createIconResolver,
|
|
8
13
|
renderMarkdown
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
14
|
+
} from "./chunk-Q2NHZ6TV.js";
|
|
15
|
+
import "./chunk-ZYFFV7Y7.js";
|
|
11
16
|
|
|
12
17
|
// src/node.ts
|
|
13
18
|
import { existsSync, readdirSync, readFileSync as readFileSync2, statSync } from "node:fs";
|
|
@@ -48,6 +53,7 @@ function loadProject(root, dir = "diagrams") {
|
|
|
48
53
|
const base = diagramsDir(root, dir);
|
|
49
54
|
const result = { diagrams: {}, diagnostics: [], watch: [base] };
|
|
50
55
|
if (!existsSync(base)) return result;
|
|
56
|
+
const entries = {};
|
|
51
57
|
for (const name of readdirSync(base).sort()) {
|
|
52
58
|
const folder = join(base, name);
|
|
53
59
|
if (!statSync(folder).isDirectory()) continue;
|
|
@@ -59,7 +65,7 @@ function loadProject(root, dir = "diagrams") {
|
|
|
59
65
|
file: join(scenarioDir, f),
|
|
60
66
|
text: readFileSync2(join(scenarioDir, f), "utf8")
|
|
61
67
|
})) : [];
|
|
62
|
-
const { diagram, diagnostics } = compileDiagram2({
|
|
68
|
+
const { diagram, diagnostics, where } = compileDiagram2({
|
|
63
69
|
name,
|
|
64
70
|
file: relative(root, file),
|
|
65
71
|
text: readFileSync2(file, "utf8"),
|
|
@@ -68,8 +74,11 @@ function loadProject(root, dir = "diagrams") {
|
|
|
68
74
|
});
|
|
69
75
|
result.diagnostics.push(...diagnostics);
|
|
70
76
|
if (diagram) result.diagrams[name] = diagram;
|
|
77
|
+
entries[name] = { diagram, where };
|
|
71
78
|
result.watch.push(folder);
|
|
72
79
|
}
|
|
80
|
+
result.diagnostics.push(...linkDiagrams(entries));
|
|
81
|
+
result.diagrams = attachNested(result.diagrams);
|
|
73
82
|
return result;
|
|
74
83
|
}
|
|
75
84
|
function readInside(folder, rel) {
|
|
@@ -91,12 +100,15 @@ export {
|
|
|
91
100
|
FamilySchema,
|
|
92
101
|
KNOWN_KEYS,
|
|
93
102
|
RootSchema,
|
|
103
|
+
attachNested,
|
|
94
104
|
authoringJsonSchema,
|
|
95
105
|
compileDiagram2 as compileDiagram,
|
|
96
106
|
diagramsDir,
|
|
97
107
|
formatDiagnostic,
|
|
108
|
+
linkDiagrams,
|
|
98
109
|
loadIconSets,
|
|
99
110
|
loadProject,
|
|
111
|
+
nestedDiagrams,
|
|
100
112
|
renderMarkdown,
|
|
101
113
|
resolveIcon,
|
|
102
114
|
searchIcons
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { type Diagrams } from './nested-layout';
|
|
2
|
+
import type { CompiledDiagram, CompiledView, IconData, Status } from './types';
|
|
3
|
+
/** One edge of a node, seen from that node. */
|
|
4
|
+
export interface OutlineConnection {
|
|
5
|
+
edge: string;
|
|
6
|
+
/** `out`: this node sends to `other`; `in`: it receives from `other`; `both`: edge goes either way. */
|
|
7
|
+
dir: 'out' | 'in' | 'both';
|
|
8
|
+
/** Id of the node at the other end, in the same diagram. */
|
|
9
|
+
other: string;
|
|
10
|
+
/** Its title, so a row needs nothing else to be read. */
|
|
11
|
+
otherTitle: string;
|
|
12
|
+
label?: string;
|
|
13
|
+
kind: string;
|
|
14
|
+
status: Status;
|
|
15
|
+
}
|
|
16
|
+
export interface OutlineNode {
|
|
17
|
+
type: 'node';
|
|
18
|
+
/** The node id, or ids joined with `/` for a node inside one shown in place (`orders/stock`). */
|
|
19
|
+
path: string;
|
|
20
|
+
id: string;
|
|
21
|
+
title: string;
|
|
22
|
+
sub?: string;
|
|
23
|
+
icon?: IconData;
|
|
24
|
+
status: Status;
|
|
25
|
+
connections: OutlineConnection[];
|
|
26
|
+
/** Present when the node holds a diagram the reader can reach. */
|
|
27
|
+
inside?: {
|
|
28
|
+
title: string;
|
|
29
|
+
/** The reader may show it in place, and may move into it. */
|
|
30
|
+
expand: boolean;
|
|
31
|
+
open: boolean;
|
|
32
|
+
/** Shown in place right now; `items` are then the nodes of that diagram. */
|
|
33
|
+
expanded: boolean;
|
|
34
|
+
items: OutlineItem[];
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export interface OutlineGroup {
|
|
38
|
+
type: 'group';
|
|
39
|
+
/** Group id, prefixed like a node path so it is unique across the levels shown in place. */
|
|
40
|
+
path: string;
|
|
41
|
+
id: string;
|
|
42
|
+
title: string;
|
|
43
|
+
caption?: string;
|
|
44
|
+
icon?: IconData;
|
|
45
|
+
status: Status;
|
|
46
|
+
items: OutlineItem[];
|
|
47
|
+
/** How many nodes it holds, however deep. */
|
|
48
|
+
count: number;
|
|
49
|
+
}
|
|
50
|
+
export type OutlineItem = OutlineNode | OutlineGroup;
|
|
51
|
+
export interface OutlineOptions {
|
|
52
|
+
/** Where the diagrams a node holds are found, by name. */
|
|
53
|
+
diagrams?: Diagrams;
|
|
54
|
+
/** Paths shown in place. */
|
|
55
|
+
expanded?: ReadonlySet<string>;
|
|
56
|
+
prefix?: string;
|
|
57
|
+
/** Diagrams already on the way down, so a loop cannot run forever. */
|
|
58
|
+
seen?: readonly string[];
|
|
59
|
+
}
|
|
60
|
+
/** The nodes and groups of `view` as a tree, in the order the author wrote them. */
|
|
61
|
+
export declare function buildOutline(diagram: CompiledDiagram, view: CompiledView, { diagrams, expanded, prefix, seen }?: OutlineOptions): OutlineItem[];
|
|
62
|
+
/** Every node of an outline, in reading order, at any depth. */
|
|
63
|
+
export declare function outlineNodes(items: readonly OutlineItem[]): OutlineNode[];
|
package/dist/phases.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { CompiledScenario } from './types';
|
|
2
|
+
export interface PhaseSpan {
|
|
3
|
+
/** Index in `scenario.phases`. */
|
|
4
|
+
index: number;
|
|
5
|
+
title: string;
|
|
6
|
+
caption?: string;
|
|
7
|
+
/** Index of its first and last step in `scenario.steps`. */
|
|
8
|
+
from: number;
|
|
9
|
+
to: number;
|
|
10
|
+
/** How many steps it holds. */
|
|
11
|
+
count: number;
|
|
12
|
+
}
|
|
13
|
+
/** Whether the author named the phases. A scenario written as plain `steps` has one nameless phase. */
|
|
14
|
+
export declare const hasPhases: (scenario: CompiledScenario) => boolean;
|
|
15
|
+
/** The phases that hold steps, in order. Steps follow their phase, so each phase is one run. */
|
|
16
|
+
export declare function phaseSpans(scenario: CompiledScenario): PhaseSpan[];
|