@pipelex/mthds-ui 0.29.0 → 0.30.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.
Files changed (33) hide show
  1. package/README.md +14 -8
  2. package/dist/{chunk-ZTXSDTVF.js → chunk-3BXB6HSF.js} +1304 -31
  3. package/dist/chunk-3BXB6HSF.js.map +1 -0
  4. package/dist/{chunk-Y46574OW.js → chunk-GAOBB3UT.js} +5 -2
  5. package/dist/chunk-GAOBB3UT.js.map +1 -0
  6. package/dist/chunk-KB2DIEVF.js +1 -0
  7. package/dist/{chunk-3I3ZPYMW.js → chunk-PJTYQURQ.js} +33 -1
  8. package/dist/chunk-PJTYQURQ.js.map +1 -0
  9. package/dist/form/react/index.d.ts +1 -1
  10. package/dist/form/react/index.js +2 -2
  11. package/dist/graph/index.d.ts +336 -9
  12. package/dist/graph/index.js +98 -4
  13. package/dist/graph/react/index.d.ts +26 -2
  14. package/dist/graph/react/index.js +975 -371
  15. package/dist/graph/react/index.js.map +1 -1
  16. package/dist/graph/react/styles/simple/SimpleStyle.css +434 -0
  17. package/dist/graph/react/viewer/GraphToolbar.css +114 -0
  18. package/dist/index.d.ts +2 -2
  19. package/dist/index.js +98 -4
  20. package/dist/standalone/graph-standalone.html +714 -165
  21. package/dist/standalone/graph-viewer.css +549 -0
  22. package/dist/standalone/graph-viewer.js +164 -164
  23. package/dist/static-graph/index.d.ts +1 -1
  24. package/dist/static-graph/index.js +1 -1
  25. package/dist/{types-BaFWy56P.d.ts → types-BNqjYF_x.d.ts} +152 -1
  26. package/package.json +2 -1
  27. package/dist/chunk-3I3ZPYMW.js.map +0 -1
  28. package/dist/chunk-F6TZIJ7A.js +0 -1
  29. package/dist/chunk-Y46574OW.js.map +0 -1
  30. package/dist/chunk-ZTXSDTVF.js.map +0 -1
  31. package/dist/graph/react/index.css +0 -749
  32. package/dist/graph/react/index.css.map +0 -1
  33. /package/dist/{chunk-F6TZIJ7A.js.map → chunk-KB2DIEVF.js.map} +0 -0
@@ -1,25 +1,37 @@
1
1
  import {
2
- makePipeRef
2
+ makePipeRef,
3
+ parsePipeRef
3
4
  } from "./chunk-2N65P32H.js";
5
+ import {
6
+ DEFAULT_GRAPH_CONFIG
7
+ } from "./chunk-GAOBB3UT.js";
4
8
  import {
5
9
  ARROW_CLOSED_MARKER,
6
10
  BINDING_STEP_TYPE,
7
11
  CONTROLLER_PADDING_BOTTOM,
8
12
  CONTROLLER_PADDING_TOP,
9
13
  CONTROLLER_PADDING_X,
14
+ EDGE_TYPE_ROUTED,
15
+ GRAPH_STYLE,
10
16
  KNOWN_PIPE_TYPES,
11
17
  NODE_TYPE_CONTROLLER,
12
18
  NODE_TYPE_PIPE_CARD,
19
+ NODE_TYPE_SIMPLE_DECISION,
20
+ NODE_TYPE_SIMPLE_FRAME,
21
+ NODE_TYPE_SIMPLE_STEP,
22
+ NODE_TYPE_SIMPLE_TERMINAL,
13
23
  NODE_TYPE_STUFF,
24
+ STEP_CATEGORY,
14
25
  graphSpecMode,
15
26
  isBindingNode,
27
+ isPluralMultiplicity,
16
28
  isStuffNodeId,
17
29
  multiplicitySuffix,
18
30
  nodeHeight,
19
31
  nodeWidth,
20
32
  stuffDigestFromId,
21
33
  stuffNodeId
22
- } from "./chunk-3I3ZPYMW.js";
34
+ } from "./chunk-PJTYQURQ.js";
23
35
  import {
24
36
  __objRest,
25
37
  __spreadProps,
@@ -934,13 +946,12 @@ function issueTargetIds(issue, graphspec) {
934
946
  }
935
947
  return [];
936
948
  }
937
- function buildValidationDecorations(issues, graphspec, childToCtrl, foldedSet) {
938
- var _a;
949
+ function buildValidationDecorations(issues, graphspec, childToCtrl, foldedSet, standIns) {
939
950
  const decorations = /* @__PURE__ */ new Map();
940
951
  if (!issues || issues.length === 0 || !graphspec) return decorations;
941
952
  for (const issue of issues) {
942
953
  for (const targetId of issueTargetIds(issue, graphspec)) {
943
- const visibleId = (_a = outermostFoldedAncestor(targetId, childToCtrl, foldedSet)) != null ? _a : targetId;
954
+ const visibleId = visibleNodeId(targetId, childToCtrl, foldedSet, standIns);
944
955
  const existing = decorations.get(visibleId);
945
956
  const lines = [issue.message, ...issue.suggestedFix ? [`Fix: ${issue.suggestedFix}`] : []];
946
957
  if (existing) {
@@ -954,11 +965,15 @@ function buildValidationDecorations(issues, graphspec, childToCtrl, foldedSet) {
954
965
  }
955
966
  return decorations;
956
967
  }
957
- function resolveIssueTargetNodeId(issue, graphspec, childToCtrl, foldedSet, renderedNodeIds) {
958
- var _a;
968
+ function visibleNodeId(targetId, childToCtrl, foldedSet, standIns) {
969
+ var _a, _b;
970
+ const unfolded = (_a = outermostFoldedAncestor(targetId, childToCtrl, foldedSet)) != null ? _a : targetId;
971
+ return (_b = standIns == null ? void 0 : standIns.get(unfolded)) != null ? _b : unfolded;
972
+ }
973
+ function resolveIssueTargetNodeId(issue, graphspec, childToCtrl, foldedSet, renderedNodeIds, standIns) {
959
974
  if (!graphspec) return null;
960
975
  for (const targetId of issueTargetIds(issue, graphspec)) {
961
- const visibleId = (_a = outermostFoldedAncestor(targetId, childToCtrl, foldedSet)) != null ? _a : targetId;
976
+ const visibleId = visibleNodeId(targetId, childToCtrl, foldedSet, standIns);
962
977
  if (renderedNodeIds.has(visibleId)) return visibleId;
963
978
  }
964
979
  return null;
@@ -1133,6 +1148,7 @@ function countTbPillRows(pills, cardWidth) {
1133
1148
  function estimateNodeDimensions(node, isHorizontal) {
1134
1149
  var _a, _b, _c;
1135
1150
  const nodeData = node.data || {};
1151
+ if (nodeData.layoutSize) return __spreadValues({}, nodeData.layoutSize);
1136
1152
  const isStuff = nodeData.isStuff;
1137
1153
  const labelText = nodeData.labelText || "";
1138
1154
  const isPipeCard = node.type === NODE_TYPE_PIPE_CARD;
@@ -1217,11 +1233,35 @@ function makeLeafNode(nodeId, dims, direction) {
1217
1233
  }
1218
1234
  };
1219
1235
  }
1236
+ function makeElkEdge(edge, routeEdges) {
1237
+ const elkEdge = {
1238
+ id: edge.id,
1239
+ sources: [outputPortId(edge.source)],
1240
+ targets: [inputPortId(edge.target)]
1241
+ };
1242
+ if (routeEdges && edge.label && edge.labelSize) {
1243
+ elkEdge.labels = [
1244
+ {
1245
+ id: `${edge.id}_label`,
1246
+ text: edge.label,
1247
+ width: edge.labelSize.width,
1248
+ height: edge.labelSize.height
1249
+ }
1250
+ ];
1251
+ }
1252
+ return elkEdge;
1253
+ }
1220
1254
  function buildElkGraph(nodes, edges, graphspec, analysis, direction, layoutConfig) {
1221
- var _a, _b, _c;
1255
+ var _a, _b, _c, _d, _e;
1222
1256
  const isHorizontal = direction === "LR" || direction === "RL";
1223
1257
  const nodesep = (_a = layoutConfig == null ? void 0 : layoutConfig.nodesep) != null ? _a : 80;
1224
1258
  const ranksep = (_b = layoutConfig == null ? void 0 : layoutConfig.ranksep) != null ? _b : 70;
1259
+ const routeEdges = (_c = layoutConfig == null ? void 0 : layoutConfig.routeEdges) != null ? _c : false;
1260
+ const groupPadding = (_d = layoutConfig == null ? void 0 : layoutConfig.groupPadding) != null ? _d : {
1261
+ x: CONTROLLER_PADDING_X,
1262
+ top: CONTROLLER_PADDING_TOP,
1263
+ bottom: CONTROLLER_PADDING_BOTTOM
1264
+ };
1225
1265
  const elkDir = elkDirection(direction);
1226
1266
  const edgeNodeSpacing = "30";
1227
1267
  const rootLayoutOptions = {
@@ -1236,6 +1276,9 @@ function buildElkGraph(nodes, edges, graphspec, analysis, direction, layoutConfi
1236
1276
  "elk.layered.spacing.edgeEdgeBetweenLayers": "15",
1237
1277
  "elk.layered.nodePlacement.favorStraightEdges": "true"
1238
1278
  };
1279
+ if (routeEdges) {
1280
+ rootLayoutOptions["elk.json.edgeCoords"] = "ROOT";
1281
+ }
1239
1282
  if (!graphspec || !analysis || analysis.controllerNodeIds.size === 0) {
1240
1283
  const dimensionMap2 = {};
1241
1284
  const elkChildren = nodes.map((node) => {
@@ -1243,11 +1286,7 @@ function buildElkGraph(nodes, edges, graphspec, analysis, direction, layoutConfi
1243
1286
  dimensionMap2[node.id] = dims;
1244
1287
  return makeLeafNode(node.id, dims, direction);
1245
1288
  });
1246
- const elkEdges2 = edges.map((edge) => ({
1247
- id: edge.id,
1248
- sources: [outputPortId(edge.source)],
1249
- targets: [inputPortId(edge.target)]
1250
- }));
1289
+ const elkEdges2 = edges.map((edge) => makeElkEdge(edge, routeEdges));
1251
1290
  return {
1252
1291
  elkGraph: {
1253
1292
  id: "root",
@@ -1270,11 +1309,11 @@ function buildElkGraph(nodes, edges, graphspec, analysis, direction, layoutConfi
1270
1309
  return ((_a2 = depths[a]) != null ? _a2 : 0) - ((_b2 = depths[b]) != null ? _b2 : 0);
1271
1310
  });
1272
1311
  for (const ctrlId of controllerIds) {
1273
- const depth = (_c = depths[ctrlId]) != null ? _c : 0;
1312
+ const depth = (_e = depths[ctrlId]) != null ? _e : 0;
1274
1313
  const depthScale = 1 + depth * 0.15;
1275
- const padX = Math.round(CONTROLLER_PADDING_X * depthScale);
1276
- const padTop = Math.round(CONTROLLER_PADDING_TOP * depthScale);
1277
- const padBottom = Math.round(CONTROLLER_PADDING_BOTTOM * depthScale);
1314
+ const padX = Math.round(groupPadding.x * depthScale);
1315
+ const padTop = Math.round(groupPadding.top * depthScale);
1316
+ const padBottom = Math.round(groupPadding.bottom * depthScale);
1278
1317
  const ctrlLayoutOptions = {
1279
1318
  "elk.padding": `[top=${padTop},left=${padX},bottom=${padBottom},right=${padX}]`,
1280
1319
  "elk.spacing.nodeNode": String(nodesep),
@@ -1327,11 +1366,7 @@ function buildElkGraph(nodes, edges, graphspec, analysis, direction, layoutConfi
1327
1366
  }
1328
1367
  }
1329
1368
  const nodeIdSet = new Set(nodes.map((n) => n.id));
1330
- const elkEdges = edges.filter((e) => nodeIdSet.has(e.source) && nodeIdSet.has(e.target)).map((edge) => ({
1331
- id: edge.id,
1332
- sources: [outputPortId(edge.source)],
1333
- targets: [inputPortId(edge.target)]
1334
- }));
1369
+ const elkEdges = edges.filter((e) => nodeIdSet.has(e.source) && nodeIdSet.has(e.target)).map((edge) => makeElkEdge(edge, routeEdges));
1335
1370
  return {
1336
1371
  elkGraph: {
1337
1372
  id: "root",
@@ -1363,6 +1398,38 @@ function extractAbsolutePositions(elkResult) {
1363
1398
  walk(elkResult, 0, 0);
1364
1399
  return positions;
1365
1400
  }
1401
+ function extractEdgeRoutes(elkResult) {
1402
+ const routes = {};
1403
+ function walk(node) {
1404
+ var _a, _b, _c, _d, _e, _f, _g;
1405
+ for (const edge of (_a = node.edges) != null ? _a : []) {
1406
+ const points = [];
1407
+ for (const section of (_b = edge.sections) != null ? _b : []) {
1408
+ for (const point of [section.startPoint, ...(_c = section.bendPoints) != null ? _c : [], section.endPoint]) {
1409
+ const last = points[points.length - 1];
1410
+ if (!last || last.x !== point.x || last.y !== point.y) {
1411
+ points.push({ x: point.x, y: point.y });
1412
+ }
1413
+ }
1414
+ }
1415
+ if (points.length < 2) continue;
1416
+ const route = { points };
1417
+ const label = (_d = edge.labels) == null ? void 0 : _d[0];
1418
+ if (label && label.x !== void 0 && label.y !== void 0) {
1419
+ route.label = {
1420
+ x: label.x,
1421
+ y: label.y,
1422
+ width: (_e = label.width) != null ? _e : 0,
1423
+ height: (_f = label.height) != null ? _f : 0
1424
+ };
1425
+ }
1426
+ routes[edge.id] = route;
1427
+ }
1428
+ for (const child of (_g = node.children) != null ? _g : []) walk(child);
1429
+ }
1430
+ walk(elkResult);
1431
+ return routes;
1432
+ }
1366
1433
 
1367
1434
  // src/graph/graphLayout.ts
1368
1435
  import ELK from "elkjs/lib/elk.bundled.js";
@@ -1422,7 +1489,98 @@ async function getLayoutedElements(nodes, edges, direction, layoutConfig, graphs
1422
1489
  targetPosition: isHorizontal ? direction === "LR" ? "left" : "right" : direction === "TB" ? "top" : "bottom"
1423
1490
  });
1424
1491
  });
1425
- return { nodes: result, edges, controllerPositions };
1492
+ if (!(layoutConfig == null ? void 0 : layoutConfig.routeEdges)) return { nodes: result, edges, controllerPositions };
1493
+ const routes = extractEdgeRoutes(layoutResult);
1494
+ const routedEdges = edges.map((edge) => {
1495
+ const route = routes[edge.id];
1496
+ return route ? __spreadProps(__spreadValues({}, edge), { route }) : edge;
1497
+ });
1498
+ return { nodes: result, edges: routedEdges, controllerPositions };
1499
+ }
1500
+
1501
+ // src/graph/edgeRoutes.ts
1502
+ var ROUTE_ENDPOINT_TOLERANCE_PX = 8;
1503
+ var ROUTE_CORNER_RADIUS_PX = 8;
1504
+ var SAME_AXIS_EPSILON = 0.5;
1505
+ function near(a, b, tolerance) {
1506
+ return Math.abs(a.x - b.x) <= tolerance && Math.abs(a.y - b.y) <= tolerance;
1507
+ }
1508
+ function fitRoute(points, source, target, tolerance = ROUTE_ENDPOINT_TOLERANCE_PX) {
1509
+ if (points.length < 2) return null;
1510
+ const first = points[0];
1511
+ const last = points[points.length - 1];
1512
+ if (!near(first, source, tolerance) || !near(last, target, tolerance)) return null;
1513
+ const fitted = points.map((p) => ({ x: p.x, y: p.y }));
1514
+ const end = fitted.length - 1;
1515
+ if (fitted.length > 2) {
1516
+ alignNeighbour(fitted, 0, 1, source);
1517
+ alignNeighbour(fitted, end, end - 1, target);
1518
+ }
1519
+ fitted[0] = { x: source.x, y: source.y };
1520
+ fitted[end] = { x: target.x, y: target.y };
1521
+ return fitted;
1522
+ }
1523
+ function alignNeighbour(points, endIndex, neighbourIndex, to) {
1524
+ const end = points[endIndex];
1525
+ const neighbour = points[neighbourIndex];
1526
+ if (Math.abs(end.y - neighbour.y) <= SAME_AXIS_EPSILON) neighbour.y = to.y;
1527
+ else if (Math.abs(end.x - neighbour.x) <= SAME_AXIS_EPSILON) neighbour.x = to.x;
1528
+ }
1529
+ function roundedPolylinePath(points, radius = ROUTE_CORNER_RADIUS_PX) {
1530
+ if (points.length === 0) return "";
1531
+ const parts = [`M ${points[0].x},${points[0].y}`];
1532
+ for (let i = 1; i < points.length - 1; i++) {
1533
+ const previous = points[i - 1];
1534
+ const bend = points[i];
1535
+ const next = points[i + 1];
1536
+ const inLength = Math.hypot(bend.x - previous.x, bend.y - previous.y);
1537
+ const outLength = Math.hypot(next.x - bend.x, next.y - bend.y);
1538
+ const r = Math.min(radius, inLength / 2, outLength / 2);
1539
+ if (r <= 0) {
1540
+ parts.push(`L ${bend.x},${bend.y}`);
1541
+ continue;
1542
+ }
1543
+ const before = {
1544
+ x: bend.x + (previous.x - bend.x) / inLength * r,
1545
+ y: bend.y + (previous.y - bend.y) / inLength * r
1546
+ };
1547
+ const after = {
1548
+ x: bend.x + (next.x - bend.x) / outLength * r,
1549
+ y: bend.y + (next.y - bend.y) / outLength * r
1550
+ };
1551
+ parts.push(`L ${before.x},${before.y}`, `Q ${bend.x},${bend.y} ${after.x},${after.y}`);
1552
+ }
1553
+ const last = points[points.length - 1];
1554
+ parts.push(`L ${last.x},${last.y}`);
1555
+ return parts.join(" ");
1556
+ }
1557
+ function polylineMidpoint(points) {
1558
+ if (points.length === 0) return { x: 0, y: 0 };
1559
+ let total = 0;
1560
+ for (let i = 1; i < points.length; i++) {
1561
+ total += Math.hypot(points[i].x - points[i - 1].x, points[i].y - points[i - 1].y);
1562
+ }
1563
+ let remaining = total / 2;
1564
+ for (let i = 1; i < points.length; i++) {
1565
+ const a = points[i - 1];
1566
+ const b = points[i];
1567
+ const length = Math.hypot(b.x - a.x, b.y - a.y);
1568
+ if (length >= remaining && length > 0) {
1569
+ const t = remaining / length;
1570
+ return { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t };
1571
+ }
1572
+ remaining -= length;
1573
+ }
1574
+ return points[points.length - 1];
1575
+ }
1576
+ function routeLabelCenter(route, fitted) {
1577
+ if (route.label) {
1578
+ return {
1579
+ x: route.label.x + route.label.width / 2,
1580
+ y: route.label.y + route.label.height / 2
1581
+ };
1582
+ }
1583
+ return polylineMidpoint(fitted);
1426
1584
  }
1427
1585
 
1428
1586
  // src/graph/graphControllers.ts
@@ -1655,9 +1813,11 @@ function applyControllers(layoutedNodes, layoutedEdges, graphspec, analysis, sho
1655
1813
  cn.data.onToggleFold = (options) => onToggleFold(id, options);
1656
1814
  }
1657
1815
  }
1658
- const allNodes = [...controllerNodes, ...filteredNodes];
1816
+ return { nodes: sortParentsFirst([...controllerNodes, ...filteredNodes]), edges: filteredEdges };
1817
+ }
1818
+ function sortParentsFirst(nodes) {
1659
1819
  const nodeMap = {};
1660
- for (const n of allNodes) nodeMap[n.id] = n;
1820
+ for (const n of nodes) nodeMap[n.id] = n;
1661
1821
  const depthOf = {};
1662
1822
  const depthVisiting = /* @__PURE__ */ new Set();
1663
1823
  function getContainmentDepth(id) {
@@ -1673,11 +1833,1084 @@ function applyControllers(layoutedNodes, layoutedEdges, graphspec, analysis, sho
1673
1833
  depthVisiting.delete(id);
1674
1834
  return depthOf[id];
1675
1835
  }
1676
- for (const n of allNodes) getContainmentDepth(n.id);
1677
- allNodes.sort((a, b) => depthOf[a.id] - depthOf[b.id]);
1678
- return { nodes: allNodes, edges: filteredEdges };
1836
+ for (const n of nodes) getContainmentDepth(n.id);
1837
+ return [...nodes].sort((a, b) => depthOf[a.id] - depthOf[b.id]);
1838
+ }
1839
+
1840
+ // src/graph/styles/graphStyles.ts
1841
+ var GRAPH_STYLES = {
1842
+ [GRAPH_STYLE.DETAILED]: {
1843
+ id: GRAPH_STYLE.DETAILED,
1844
+ name: "Detailed",
1845
+ description: "Every pipe with its inputs, outputs and settings",
1846
+ capabilities: { controllerFrameToggle: true, foldAll: true }
1847
+ },
1848
+ [GRAPH_STYLE.SIMPLE]: {
1849
+ id: GRAPH_STYLE.SIMPLE,
1850
+ name: "Simple",
1851
+ description: "The method's steps in plain words",
1852
+ capabilities: { controllerFrameToggle: false, foldAll: true },
1853
+ layout: {
1854
+ nodesep: 28,
1855
+ ranksep: 44,
1856
+ routeEdges: true,
1857
+ groupPadding: { x: 20, top: 40, bottom: 16 }
1858
+ }
1859
+ }
1860
+ };
1861
+ var GRAPH_STYLE_IDS = [GRAPH_STYLE.DETAILED, GRAPH_STYLE.SIMPLE];
1862
+ function isGraphStyleId(value) {
1863
+ return typeof value === "string" && Object.hasOwn(GRAPH_STYLES, value);
1864
+ }
1865
+ function resolveGraphStyle(styleProp, configStyle) {
1866
+ if (isGraphStyleId(styleProp)) return styleProp;
1867
+ if (isGraphStyleId(configStyle)) return configStyle;
1868
+ return DEFAULT_GRAPH_CONFIG.graphStyle;
1869
+ }
1870
+ function resolveStyleMenu(styleMenu) {
1871
+ if (styleMenu === void 0 || styleMenu === false) return [];
1872
+ const requested = styleMenu === true ? GRAPH_STYLE_IDS : styleMenu;
1873
+ const offered = [];
1874
+ for (const id of requested) {
1875
+ if (isGraphStyleId(id) && !offered.includes(id)) offered.push(id);
1876
+ }
1877
+ return offered.length >= 2 ? offered : [];
1878
+ }
1879
+
1880
+ // src/graph/styles/humanize.ts
1881
+ var VOWELED_ACRONYMS = /* @__PURE__ */ new Set([
1882
+ "ai",
1883
+ "api",
1884
+ "faq",
1885
+ "iban",
1886
+ "id",
1887
+ "io",
1888
+ "ip",
1889
+ "json",
1890
+ "kpi",
1891
+ "ocr",
1892
+ "roi",
1893
+ "seo",
1894
+ "ui",
1895
+ "uri",
1896
+ "url",
1897
+ "uuid",
1898
+ "ux"
1899
+ ]);
1900
+ var VOWELS = /[aeiouy]/;
1901
+ var VOWELLESS_WORDS = /* @__PURE__ */ new Set([
1902
+ "cfg",
1903
+ "cm",
1904
+ "cnt",
1905
+ "ctx",
1906
+ "dr",
1907
+ "dst",
1908
+ "fn",
1909
+ "ft",
1910
+ "hmm",
1911
+ "hr",
1912
+ "kg",
1913
+ "km",
1914
+ "lb",
1915
+ "mg",
1916
+ "ml",
1917
+ "mm",
1918
+ "mr",
1919
+ "mrs",
1920
+ "ms",
1921
+ "msg",
1922
+ "nd",
1923
+ "nth",
1924
+ "pkg",
1925
+ "pt",
1926
+ "rd",
1927
+ "src",
1928
+ "st",
1929
+ "th",
1930
+ "tmp",
1931
+ "vs"
1932
+ ]);
1933
+ var SINGULAR_S_ACRONYMS = /* @__PURE__ */ new Set([
1934
+ "cms",
1935
+ "css",
1936
+ "dns",
1937
+ "gps",
1938
+ "rss",
1939
+ "sms"
1940
+ ]);
1941
+ var NATIVE_PLAIN_NAMES = {
1942
+ Html: "HTML",
1943
+ JSON: "JSON",
1944
+ TextAndImages: "Text and images",
1945
+ YesNo: "Yes or no",
1946
+ SearchResult: "Search result",
1947
+ Composite: "Combined results",
1948
+ Dynamic: "Data"
1949
+ };
1950
+ var GENERIC_NATIVES = /* @__PURE__ */ new Set(["Anything", "Dynamic", "Composite"]);
1951
+ function isAcronymWord(lower) {
1952
+ if (lower.length < 2 || !/^[a-z]+$/.test(lower)) return false;
1953
+ if (VOWELLESS_WORDS.has(lower)) return false;
1954
+ if (lower.endsWith("s") && VOWELLESS_WORDS.has(lower.slice(0, -1))) return false;
1955
+ return !VOWELS.test(lower) || VOWELED_ACRONYMS.has(lower);
1956
+ }
1957
+ function spellWord(lower, wasAllCaps) {
1958
+ if (/^\d+$/.test(lower)) return lower;
1959
+ if (wasAllCaps && lower.length >= 2) return lower.toUpperCase();
1960
+ if (lower.endsWith("s") && !SINGULAR_S_ACRONYMS.has(lower) && isAcronymWord(lower.slice(0, -1))) {
1961
+ return lower.slice(0, -1).toUpperCase() + "s";
1962
+ }
1963
+ if (isAcronymWord(lower)) return lower.toUpperCase();
1964
+ return lower;
1965
+ }
1966
+ function splitIdentifier(identifier) {
1967
+ const parts = identifier.replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/([A-Za-z])(\d)/g, "$1 $2").split(/[\s_\-.]+/).filter((p) => p.length > 0);
1968
+ return parts.map((p) => ({
1969
+ word: p.toLowerCase(),
1970
+ wasAllCaps: p.length >= 2 && p === p.toUpperCase() && /[A-Z]/.test(p)
1971
+ }));
1972
+ }
1973
+ function capitalizeFirst(text) {
1974
+ return text.length === 0 ? text : text.charAt(0).toUpperCase() + text.slice(1);
1975
+ }
1976
+ function stripDomain(ref) {
1977
+ const dot = ref.lastIndexOf(".");
1978
+ return dot === -1 ? ref : ref.slice(dot + 1);
1979
+ }
1980
+ function humanizeIdentifier(identifier) {
1981
+ const words = splitIdentifier(stripDomain(identifier.trim()));
1982
+ if (words.length === 0) return "";
1983
+ return capitalizeFirst(words.map((w) => spellWord(w.word, w.wasAllCaps)).join(" "));
1984
+ }
1985
+ function conceptPlainName(conceptRef) {
1986
+ var _a;
1987
+ const code = stripDomain(conceptRef.trim());
1988
+ return (_a = NATIVE_PLAIN_NAMES[code]) != null ? _a : humanizeIdentifier(code);
1989
+ }
1990
+ function isGenericConcept(conceptRef) {
1991
+ return GENERIC_NATIVES.has(stripDomain(conceptRef.trim()));
1992
+ }
1993
+ function sentenceCase(text) {
1994
+ const collapsed = text.replace(/\s+/g, " ").trim();
1995
+ const trimmed = collapsed.endsWith(".") && !collapsed.endsWith("..") ? collapsed.slice(0, -1) : collapsed;
1996
+ return capitalizeFirst(trimmed);
1997
+ }
1998
+ var OUTCOME_WORDS = {
1999
+ true: "Yes",
2000
+ false: "No",
2001
+ default: "Otherwise"
2002
+ };
2003
+ function outcomeLabel(outcome) {
2004
+ const outcomes = outcome.split("|").map((o) => o.trim()).filter((o) => o.length > 0);
2005
+ const labels = outcomes.map((o, index) => {
2006
+ var _a;
2007
+ const label = (_a = OUTCOME_WORDS[o.toLowerCase()]) != null ? _a : humanizeIdentifier(o);
2008
+ return index === 0 ? label : label.charAt(0).toLowerCase() + label.slice(1);
2009
+ });
2010
+ return labels.join(" or ");
2011
+ }
2012
+
2013
+ // src/graph/styles/textMetrics.ts
2014
+ var GLYPH_EM_GROUPS = [
2015
+ [0.28, "il .,'"],
2016
+ [0.33, "fjt:;!()"],
2017
+ [0.35, "/"],
2018
+ [0.39, "I"],
2019
+ [0.44, "r-"],
2020
+ [0.51, "1z"],
2021
+ [0.56, '7aceksvxyJ"'],
2022
+ [0.59, "25"],
2023
+ [0.6, "8"],
2024
+ [0.61, "369bdghnopquF?"],
2025
+ [0.64, "04"],
2026
+ [0.67, "ELPSTZ"],
2027
+ [0.72, "ABCDNRUVXY"],
2028
+ [0.78, "GHKOQ"],
2029
+ [0.8, "w"],
2030
+ [0.83, "&"],
2031
+ [0.89, "m"],
2032
+ [0.94, "M"],
2033
+ [1, "W%"]
2034
+ ];
2035
+ var GLYPH_EM = new Map(
2036
+ GLYPH_EM_GROUPS.flatMap(([em, glyphs]) => [...glyphs].map((glyph) => [glyph, em]))
2037
+ );
2038
+ var UNLISTED_LOWER_EM = 0.62;
2039
+ var UNLISTED_UPPER_EM = 0.78;
2040
+ function glyphEm(glyph) {
2041
+ const listed = GLYPH_EM.get(glyph);
2042
+ if (listed !== void 0) return listed;
2043
+ return glyph !== glyph.toLowerCase() ? UNLISTED_UPPER_EM : UNLISTED_LOWER_EM;
2044
+ }
2045
+ function textWidthPx(text, fontPx) {
2046
+ let em = 0;
2047
+ for (const glyph of text) em += glyphEm(glyph);
2048
+ return em * fontPx;
2049
+ }
2050
+ function estimateWrap(text, lineWidthPx, fontPx, maxLines) {
2051
+ const words = text.split(/\s+/).filter((w) => w.length > 0);
2052
+ const spacePx = textWidthPx(" ", fontPx);
2053
+ let lines = words.length === 0 ? 0 : 1;
2054
+ let used = 0;
2055
+ for (const word of words) {
2056
+ const wordPx = textWidthPx(word, fontPx);
2057
+ if (wordPx > lineWidthPx) {
2058
+ if (used > 0) lines += 1;
2059
+ used = 0;
2060
+ for (const glyph of word) {
2061
+ const glyphPx = textWidthPx(glyph, fontPx);
2062
+ if (used > 0 && used + glyphPx > lineWidthPx) {
2063
+ lines += 1;
2064
+ used = 0;
2065
+ }
2066
+ used += glyphPx;
2067
+ }
2068
+ continue;
2069
+ }
2070
+ const needed = used === 0 ? wordPx : used + spacePx + wordPx;
2071
+ if (needed <= lineWidthPx) {
2072
+ used = needed;
2073
+ } else {
2074
+ lines += 1;
2075
+ used = wordPx;
2076
+ }
2077
+ }
2078
+ const drawnLines = Math.min(lines, maxLines);
2079
+ return { lines, drawnLines, clamped: lines > maxLines };
2080
+ }
2081
+
2082
+ // src/graph/styles/simpleStyle.ts
2083
+ var NATIVE_DOMAIN = "native";
2084
+ var SIMPLE_STEP_WIDTH = 160;
2085
+ var SIMPLE_STEP_WIDE_WIDTH = 200;
2086
+ var STEP_PADDING_X = 12;
2087
+ var STEP_PADDING_Y = 10;
2088
+ var STEP_BORDER = 1.5;
2089
+ var STEP_HEADER_HEIGHT = 16;
2090
+ var STEP_GAP = 6;
2091
+ var SIMPLE_STEP_TITLE_FONT_PX = 15;
2092
+ var STEP_TITLE_LINE_HEIGHT = 20;
2093
+ var SIMPLE_TITLE_MAX_LINES = 3;
2094
+ var STEP_MARKER_HEIGHT = 18;
2095
+ var STEP_INNER_HEIGHT = 22;
2096
+ var EDGE_LABEL_FONT_PX = 11;
2097
+ var EDGE_LABEL_LINE_HEIGHT = 13;
2098
+ var EDGE_LABEL_PADDING = [5, 3];
2099
+ var SIMPLE_TERMINAL_WIDTH = 124;
2100
+ var TERMINAL_PADDING_X = 12;
2101
+ var TERMINAL_PADDING_TOP = 10;
2102
+ var TERMINAL_PADDING_BOTTOM = 16;
2103
+ var TERMINAL_TITLE_FONT_PX = 13;
2104
+ var TERMINAL_TITLE_LINE_HEIGHT = 17;
2105
+ var TERMINAL_TITLE_MAX_LINES = 2;
2106
+ var TERMINAL_SUBTITLE_HEIGHT = 17;
2107
+ var TERMINAL_MIN_HEIGHT = 52;
2108
+ var SIMPLE_DECISION_WIDTHS = [188, 220, 252, 284];
2109
+ var DECISION_TITLE_FONT_PX = 13;
2110
+ var DECISION_TITLE_LINE_HEIGHT = 16;
2111
+ var DECISION_TEXT_WIDTH_SHARE = 0.56;
2112
+ var DECISION_TEXT_HEIGHT_SHARE = 0.4;
2113
+ var DECISION_MIN_HEIGHT = 84;
2114
+ var WRAP_SLACK_PX = 2;
2115
+ function stepTitleWidth(boxWidth) {
2116
+ return boxWidth - 2 * (STEP_PADDING_X + STEP_BORDER) - WRAP_SLACK_PX;
2117
+ }
2118
+ var TERMINAL_TITLE_WIDTH = SIMPLE_TERMINAL_WIDTH - 2 * TERMINAL_PADDING_X - WRAP_SLACK_PX;
2119
+ function decisionTextWidth(diamondWidth) {
2120
+ return Math.floor(diamondWidth * DECISION_TEXT_WIDTH_SHARE) - WRAP_SLACK_PX;
2121
+ }
2122
+ var SIMPLE_FOLD_DEPTH = 3;
2123
+ var STEP_CATEGORY_BY_PIPE_TYPE = {
2124
+ PipeLLM: STEP_CATEGORY.AI,
2125
+ PipeStructure: STEP_CATEGORY.AI,
2126
+ PipeJudge: STEP_CATEGORY.JUDGE,
2127
+ PipeExtract: STEP_CATEGORY.EXTRACT,
2128
+ PipeImgGen: STEP_CATEGORY.IMAGE,
2129
+ PipeSearch: STEP_CATEGORY.SEARCH,
2130
+ PipeFunc: STEP_CATEGORY.CODE,
2131
+ PipeCompose: STEP_CATEGORY.TEMPLATE,
2132
+ PipeDocGen: STEP_CATEGORY.DOCUMENT,
2133
+ PipeSignature: STEP_CATEGORY.PLANNED,
2134
+ PipeSequence: STEP_CATEGORY.STEPS,
2135
+ PipeParallel: STEP_CATEGORY.PARALLEL,
2136
+ PipeCondition: STEP_CATEGORY.DECISION,
2137
+ PipeBatch: STEP_CATEGORY.REPEAT,
2138
+ BindingStep: STEP_CATEGORY.PICK
2139
+ };
2140
+ var STEP_CATEGORY_WORDS = {
2141
+ ai: "AI",
2142
+ extract: "Extract",
2143
+ image: "Image",
2144
+ search: "Search",
2145
+ code: "Code",
2146
+ template: "Template",
2147
+ document: "Document",
2148
+ judge: "Judge",
2149
+ planned: "To build",
2150
+ steps: "Steps",
2151
+ parallel: "Side by side",
2152
+ decision: "Decision",
2153
+ repeat: "For each",
2154
+ pick: "Pick"
2155
+ };
2156
+ function simpleStepSize(title, options = {}) {
2157
+ let width = SIMPLE_STEP_WIDTH;
2158
+ let wrap = simpleTitleWrap(title);
2159
+ if (wrap.clamped) {
2160
+ const wide = simpleTitleWrap(title, SIMPLE_STEP_WIDE_WIDTH);
2161
+ if (!wide.clamped) {
2162
+ width = SIMPLE_STEP_WIDE_WIDTH;
2163
+ wrap = wide;
2164
+ }
2165
+ }
2166
+ let height = 2 * STEP_PADDING_Y + STEP_HEADER_HEIGHT + STEP_GAP + Math.max(1, wrap.drawnLines) * STEP_TITLE_LINE_HEIGHT;
2167
+ if (options.forEach) height += STEP_GAP + STEP_MARKER_HEIGHT;
2168
+ if (options.innerSteps) height += STEP_GAP + STEP_INNER_HEIGHT;
2169
+ return { width, height: Math.ceil(height + 2 * STEP_BORDER) };
2170
+ }
2171
+ function simpleTerminalSize(title, hasSubtitle) {
2172
+ const wrap = estimateWrap(
2173
+ title,
2174
+ TERMINAL_TITLE_WIDTH,
2175
+ TERMINAL_TITLE_FONT_PX,
2176
+ TERMINAL_TITLE_MAX_LINES
2177
+ );
2178
+ const height = TERMINAL_PADDING_TOP + Math.max(1, wrap.drawnLines) * TERMINAL_TITLE_LINE_HEIGHT + (hasSubtitle ? TERMINAL_SUBTITLE_HEIGHT : 0) + TERMINAL_PADDING_BOTTOM;
2179
+ return { width: SIMPLE_TERMINAL_WIDTH, height: Math.max(TERMINAL_MIN_HEIGHT, height) };
2180
+ }
2181
+ function simpleDecisionSize(title) {
2182
+ let width = SIMPLE_DECISION_WIDTHS[0];
2183
+ let wrap = estimateWrap(
2184
+ title,
2185
+ decisionTextWidth(width),
2186
+ DECISION_TITLE_FONT_PX,
2187
+ SIMPLE_TITLE_MAX_LINES
2188
+ );
2189
+ for (const candidate of SIMPLE_DECISION_WIDTHS.slice(1)) {
2190
+ if (!wrap.clamped) break;
2191
+ width = candidate;
2192
+ wrap = estimateWrap(
2193
+ title,
2194
+ decisionTextWidth(width),
2195
+ DECISION_TITLE_FONT_PX,
2196
+ SIMPLE_TITLE_MAX_LINES
2197
+ );
2198
+ }
2199
+ const textHeight = Math.max(1, wrap.drawnLines) * DECISION_TITLE_LINE_HEIGHT;
2200
+ const height = Math.max(DECISION_MIN_HEIGHT, Math.ceil(textHeight / DECISION_TEXT_HEIGHT_SHARE));
2201
+ return { width, height };
2202
+ }
2203
+ function simpleTitleWrap(title, boxWidth = SIMPLE_STEP_WIDTH) {
2204
+ return estimateWrap(
2205
+ title,
2206
+ stepTitleWidth(boxWidth),
2207
+ SIMPLE_STEP_TITLE_FONT_PX,
2208
+ SIMPLE_TITLE_MAX_LINES
2209
+ );
2210
+ }
2211
+ var STATUS_PRECEDENCE = [
2212
+ "failed",
2213
+ "running",
2214
+ "scheduled",
2215
+ "canceled",
2216
+ "skipped",
2217
+ "succeeded"
2218
+ ];
2219
+ function aggregateStatus(statuses) {
2220
+ for (const status of STATUS_PRECEDENCE) {
2221
+ if (statuses.includes(status)) return status;
2222
+ }
2223
+ return void 0;
2224
+ }
2225
+ function parentMap(containmentTree) {
2226
+ const parentOf = {};
2227
+ for (const [ctrlId, children] of Object.entries(containmentTree)) {
2228
+ for (const child of children) parentOf[child] = ctrlId;
2229
+ }
2230
+ return parentOf;
2231
+ }
2232
+ function unique(items) {
2233
+ return [...new Set(items)];
2234
+ }
2235
+ function batchRepresentatives(graphspec, analysis, drawability) {
2236
+ var _a;
2237
+ const specById = new Map(graphspec.nodes.map((n) => [n.id, n]));
2238
+ const runsWithPath = /* @__PURE__ */ new Map();
2239
+ const representativeOf = /* @__PURE__ */ new Map();
2240
+ const order = [];
2241
+ function visit(ids, parentPath, inBatch) {
2242
+ var _a2, _b;
2243
+ const seen = /* @__PURE__ */ new Map();
2244
+ for (const id of ids) {
2245
+ const spec = specById.get(id);
2246
+ const pipe = spec ? stepIdentity(spec) : id;
2247
+ const occurrence = (_a2 = seen.get(pipe)) != null ? _a2 : 0;
2248
+ seen.set(pipe, occurrence + 1);
2249
+ const path = `${parentPath}/${pipe}#${inBatch ? "*" : occurrence}`;
2250
+ const runs = runsWithPath.get(path);
2251
+ if (runs) runs.push(id);
2252
+ else runsWithPath.set(path, [id]);
2253
+ order.push(id);
2254
+ visit((_b = analysis.containmentTree[id]) != null ? _b : [], path, (spec == null ? void 0 : spec.pipe_type) === "PipeBatch");
2255
+ }
2256
+ }
2257
+ visit(
2258
+ graphspec.nodes.filter((n) => !analysis.childNodeIds.has(n.id)).map((n) => n.id),
2259
+ "",
2260
+ false
2261
+ );
2262
+ for (const runs of runsWithPath.values()) {
2263
+ if (runs.length < 2) continue;
2264
+ const best = Math.max(...runs.map(drawability));
2265
+ const representative = (_a = runs.find((id) => drawability(id) === best)) != null ? _a : runs[0];
2266
+ for (const id of runs) if (id !== representative) representativeOf.set(id, representative);
2267
+ }
2268
+ return { representativeOf, order };
2269
+ }
2270
+ function stepIdentity(spec) {
2271
+ var _a;
2272
+ const ref = spec.domain_code && spec.pipe_code ? makePipeRef(spec.domain_code, spec.pipe_code) : (_a = spec.pipe_code) != null ? _a : spec.pipe_type;
2273
+ return `${spec.kind}:${ref}`;
2274
+ }
2275
+ function forEachLabel(itemName) {
2276
+ var _a;
2277
+ const words = humanizeIdentifier(itemName);
2278
+ const first = (_a = words.split(" ")[0]) != null ? _a : "";
2279
+ const inSentence = first.length >= 2 && first === first.toUpperCase() ? words : words.charAt(0).toLowerCase() + words.slice(1);
2280
+ return `For each ${inSentence}`;
2281
+ }
2282
+ function projectSimpleGraph(input) {
2283
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2284
+ const { graphspec, nodes, analysis, rawAnalysis } = input;
2285
+ const graphMode = graphSpecMode(graphspec);
2286
+ const specById = new Map(graphspec.nodes.map((n) => [n.id, n]));
2287
+ const cards = /* @__PURE__ */ new Map();
2288
+ for (const node of nodes) {
2289
+ if (node.type === NODE_TYPE_PIPE_CARD) cards.set(node.id, node);
2290
+ }
2291
+ const liveControllers = analysis.controllerNodeIds;
2292
+ const pipeTypeOf = (id) => {
2293
+ var _a2;
2294
+ return (_a2 = specById.get(id)) == null ? void 0 : _a2.pipe_type;
2295
+ };
2296
+ const { representativeOf, order } = batchRepresentatives(graphspec, rawAnalysis, (id) => {
2297
+ var _a2;
2298
+ if (liveControllers.has(id)) return 2;
2299
+ const card = cards.get(id);
2300
+ if (!card) return 0;
2301
+ return card.data.isController !== true && ((_a2 = specById.get(id)) == null ? void 0 : _a2.kind) === "controller" ? 1 : 2;
2302
+ });
2303
+ const repOf = (id) => {
2304
+ var _a2;
2305
+ return (_a2 = representativeOf.get(id)) != null ? _a2 : id;
2306
+ };
2307
+ const parentOf = {};
2308
+ for (const [id, parent] of Object.entries(parentMap(rawAnalysis.containmentTree))) {
2309
+ parentOf[id] = repOf(parent);
2310
+ }
2311
+ const foldedAbove = /* @__PURE__ */ new Map();
2312
+ for (const id of order) {
2313
+ for (let current = parentOf[id]; current; current = parentOf[current]) {
2314
+ if (((_a = cards.get(current)) == null ? void 0 : _a.data.isController) === true) {
2315
+ foldedAbove.set(id, current);
2316
+ break;
2317
+ }
2318
+ }
2319
+ }
2320
+ const drawnAs = (id) => {
2321
+ var _a2;
2322
+ return (_a2 = foldedAbove.get(id)) != null ? _a2 : repOf(id);
2323
+ };
2324
+ const hidden = /* @__PURE__ */ new Set([...representativeOf.keys(), ...foldedAbove.keys()]);
2325
+ const childrenOf = {};
2326
+ for (const id of order) {
2327
+ const parent = parentOf[id];
2328
+ if (parent && !hidden.has(id)) ((_b = childrenOf[parent]) != null ? _b : childrenOf[parent] = []).push(id);
2329
+ }
2330
+ function isInside(id, ancestorId) {
2331
+ let current = parentOf[id];
2332
+ while (current) {
2333
+ if (current === ancestorId) return true;
2334
+ current = parentOf[current];
2335
+ }
2336
+ return false;
2337
+ }
2338
+ const batchBranch = {};
2339
+ for (const ctrlId of liveControllers) {
2340
+ if (hidden.has(ctrlId) || pipeTypeOf(ctrlId) !== "PipeBatch") continue;
2341
+ const first = (_c = analysis.containmentTree[ctrlId]) == null ? void 0 : _c[0];
2342
+ if (first) batchBranch[ctrlId] = repOf(first);
2343
+ }
2344
+ const decisions = [...liveControllers].filter(
2345
+ (id) => !hidden.has(id) && pipeTypeOf(id) === "PipeCondition"
2346
+ );
2347
+ const decisionSet = new Set(decisions);
2348
+ const frameSet = new Set(
2349
+ Object.entries(batchBranch).filter(([batchId, branchId]) => !hidden.has(batchId) && liveControllers.has(branchId)).map(([batchId]) => batchId)
2350
+ );
2351
+ const markedSteps = {};
2352
+ for (const [batchId, branchId] of Object.entries(batchBranch)) {
2353
+ if (!hidden.has(batchId) && cards.has(branchId)) markedSteps[branchId] = batchId;
2354
+ }
2355
+ const runStatuses = /* @__PURE__ */ new Map();
2356
+ for (const spec of graphspec.nodes) {
2357
+ const rep = repOf(spec.id);
2358
+ const statuses = runStatuses.get(rep);
2359
+ if (statuses) statuses.push(spec.status);
2360
+ else runStatuses.set(rep, [spec.status]);
2361
+ }
2362
+ function stepStatus(spec) {
2363
+ var _a2, _b2;
2364
+ return (_b2 = aggregateStatus((_a2 = runStatuses.get(spec.id)) != null ? _a2 : [])) != null ? _b2 : spec.status;
2365
+ }
2366
+ const drawnSteps = [...cards.values()].filter(
2367
+ (card) => {
2368
+ var _a2;
2369
+ return !hidden.has(card.id) && (card.data.pipeType !== BINDING_STEP_TYPE || aggregateStatus((_a2 = runStatuses.get(card.id)) != null ? _a2 : []) === "failed");
2370
+ }
2371
+ );
2372
+ const drawnStepIds = new Set(drawnSteps.map((card) => card.id));
2373
+ const roots = graphspec.nodes.filter(
2374
+ (n) => !rawAnalysis.childNodeIds.has(n.id) && (n.kind === "controller" || n.kind === "operator")
2375
+ );
2376
+ const rootReads = new Set(roots.flatMap((r) => r.io.inputs.map((item) => item.digest)));
2377
+ const rootWrites = new Set(roots.flatMap((r) => r.io.outputs.map((item) => item.digest)));
2378
+ const inputItems = /* @__PURE__ */ new Map();
2379
+ const outputItems = /* @__PURE__ */ new Map();
2380
+ for (const root of roots) {
2381
+ for (const item of root.io.inputs) {
2382
+ if (!item.digest || inputItems.has(item.digest) || rootWrites.has(item.digest)) continue;
2383
+ inputItems.set(item.digest, item);
2384
+ }
2385
+ }
2386
+ for (const root of roots) {
2387
+ for (const item of root.io.outputs) {
2388
+ if (!item.digest || inputItems.has(item.digest) || outputItems.has(item.digest)) continue;
2389
+ if (rootReads.has(item.digest)) continue;
2390
+ outputItems.set(item.digest, item);
2391
+ }
2392
+ }
2393
+ const combinedFrom = /* @__PURE__ */ new Map();
2394
+ for (const edge of graphspec.edges) {
2395
+ const from = edge.source_stuff_digest;
2396
+ const into = edge.target_stuff_digest;
2397
+ if (!from || !into || from === into) continue;
2398
+ if (edge.kind !== "parallel_combine" && edge.kind !== "batch_aggregate" && edge.kind !== "batch_item") {
2399
+ continue;
2400
+ }
2401
+ const list = combinedFrom.get(into);
2402
+ if (list) list.push(from);
2403
+ else combinedFrom.set(into, [from]);
2404
+ }
2405
+ const sourceMemo = /* @__PURE__ */ new Map();
2406
+ function sourcesOf(digest, visiting = /* @__PURE__ */ new Set()) {
2407
+ var _a2, _b2, _c2, _d2;
2408
+ const memo = sourceMemo.get(digest);
2409
+ if (memo) return memo;
2410
+ if (inputItems.has(digest)) return [stuffNodeId(digest)];
2411
+ if (visiting.has(digest)) return [];
2412
+ visiting.add(digest);
2413
+ const found = [];
2414
+ const producers = (_a2 = analysis.stuffProducers[digest]) != null ? _a2 : [];
2415
+ for (const producerId of producers) {
2416
+ const card = cards.get(drawnAs(producerId));
2417
+ if (!card) continue;
2418
+ if (card.data.pipeType === BINDING_STEP_TYPE && !drawnStepIds.has(card.id)) {
2419
+ for (const item of (_c2 = (_b2 = specById.get(producerId)) == null ? void 0 : _b2.io.inputs) != null ? _c2 : []) {
2420
+ if (item.digest) found.push(...sourcesOf(item.digest, visiting));
2421
+ }
2422
+ } else {
2423
+ found.push(card.id);
2424
+ }
2425
+ }
2426
+ if (producers.length === 0) {
2427
+ for (const from of (_d2 = combinedFrom.get(digest)) != null ? _d2 : []) found.push(...sourcesOf(from, visiting));
2428
+ }
2429
+ visiting.delete(digest);
2430
+ const result = unique(found);
2431
+ sourceMemo.set(digest, result);
2432
+ return result;
2433
+ }
2434
+ function branchOf(decisionId, nodeId) {
2435
+ let current = nodeId;
2436
+ while (parentOf[current] && parentOf[current] !== decisionId) current = parentOf[current];
2437
+ return current;
2438
+ }
2439
+ function outcomeFor(decisionId, branchId) {
2440
+ var _a2;
2441
+ const branch = specById.get(branchId);
2442
+ const tagged = (_a2 = branch == null ? void 0 : branch.tags) == null ? void 0 : _a2.outcome;
2443
+ if (tagged) return outcomeLabel(tagged);
2444
+ const contains = graphspec.edges.find(
2445
+ (e) => e.kind === "contains" && repOf(e.source) === decisionId && e.target === branchId && e.label
2446
+ );
2447
+ if (contains == null ? void 0 : contains.label) return outcomeLabel(contains.label);
2448
+ const decision = specById.get(decisionId);
2449
+ if (!(decision == null ? void 0 : decision.domain_code) || !decision.pipe_code || !(branch == null ? void 0 : branch.pipe_code)) return void 0;
2450
+ const blueprint = getPipeBlueprint(
2451
+ graphspec,
2452
+ makePipeRef(decision.domain_code, decision.pipe_code)
2453
+ );
2454
+ if ((blueprint == null ? void 0 : blueprint.type) !== "PipeCondition") return void 0;
2455
+ const conditionDomain = decision.domain_code;
2456
+ const branchCode = branch.pipe_code;
2457
+ function namesBranch(pipeRef) {
2458
+ var _a3;
2459
+ const parsed = parsePipeRef(pipeRef);
2460
+ if (!parsed) return stripDomain(pipeRef) === branchCode;
2461
+ if (parsed.pipeCode !== branchCode) return false;
2462
+ const domain = (_a3 = parsed.domainPath) != null ? _a3 : conditionDomain;
2463
+ return (branch == null ? void 0 : branch.domain_code) === void 0 || branch.domain_code === domain;
2464
+ }
2465
+ const outcomes = Object.entries(blueprint.outcome_map).filter(([, pipeRef]) => namesBranch(pipeRef)).map(([outcome]) => outcome);
2466
+ if (blueprint.default_outcome && namesBranch(blueprint.default_outcome)) {
2467
+ outcomes.push("default");
2468
+ }
2469
+ return outcomes.length > 0 ? outcomeLabel(outcomes.join("|")) : void 0;
2470
+ }
2471
+ function decisionsAbove(nodeId) {
2472
+ const chain = [];
2473
+ let current = parentOf[nodeId];
2474
+ while (current) {
2475
+ if (decisionSet.has(current)) chain.unshift(current);
2476
+ current = parentOf[current];
2477
+ }
2478
+ return chain;
2479
+ }
2480
+ const edges = /* @__PURE__ */ new Map();
2481
+ let edgeCount = 0;
2482
+ function addEdge(source, target) {
2483
+ if (source === target) return;
2484
+ const key = `${source}->${target}`;
2485
+ if (edges.has(key)) return;
2486
+ const label = decisionSet.has(source) ? outcomeFor(source, branchOf(source, target)) : void 0;
2487
+ edges.set(key, simpleEdge(`simple_edge_${edgeCount++}`, source, target, label));
2488
+ }
2489
+ function route(sources, target) {
2490
+ let froms = [...sources];
2491
+ for (const decisionId of decisionsAbove(target)) {
2492
+ const outside = froms.filter((s) => !isInside(s, decisionId));
2493
+ if (outside.length === 0) continue;
2494
+ for (const source of outside) addEdge(source, decisionId);
2495
+ froms = [decisionId, ...froms.filter((s) => isInside(s, decisionId))];
2496
+ }
2497
+ for (const source of froms) addEdge(source, target);
2498
+ }
2499
+ const danglingInputs = /* @__PURE__ */ new Map();
2500
+ function sourcesOrDangling(digest) {
2501
+ const sources = sourcesOf(digest);
2502
+ if (sources.length > 0) return sources;
2503
+ const entry = analysis.stuffRegistry[digest];
2504
+ if (!entry) return [];
2505
+ danglingInputs.set(digest, __spreadValues(__spreadValues({
2506
+ name: entry.name,
2507
+ digest
2508
+ }, entry.concept !== void 0 ? { concept: entry.concept } : {}), entry.multiplicity !== void 0 ? { multiplicity: entry.multiplicity } : {}));
2509
+ return [stuffNodeId(digest)];
2510
+ }
2511
+ function routeRead(digest, readerId) {
2512
+ const target = drawnAs(readerId);
2513
+ if (target === readerId) route(sourcesOrDangling(digest), target);
2514
+ else route(sourcesOf(digest), target);
2515
+ }
2516
+ for (const [digest, consumers] of Object.entries(analysis.stuffConsumers)) {
2517
+ for (const consumerId of consumers) {
2518
+ if (drawnStepIds.has(drawnAs(consumerId))) routeRead(digest, consumerId);
2519
+ }
2520
+ }
2521
+ for (const conditionId of liveControllers) {
2522
+ if (!decisionSet.has(drawnAs(conditionId))) continue;
2523
+ for (const item of (_e = (_d = specById.get(conditionId)) == null ? void 0 : _d.io.inputs) != null ? _e : []) {
2524
+ if (item.digest) routeRead(item.digest, conditionId);
2525
+ }
2526
+ }
2527
+ for (const digest of outputItems.keys()) {
2528
+ for (const source of sourcesOf(digest)) addEdge(source, stuffNodeId(digest));
2529
+ }
2530
+ for (const [key, edge] of [...edges]) {
2531
+ if (!decisionSet.has(edge.source)) continue;
2532
+ const branchId = branchOf(edge.source, edge.target);
2533
+ const followsInBranch = [...edges.values()].some(
2534
+ (other) => other.target === edge.target && other.source !== edge.source && isInside(other.source, branchId)
2535
+ );
2536
+ if (followsInBranch) edges.delete(key);
2537
+ }
2538
+ function firstDrawnIn(id) {
2539
+ var _a2;
2540
+ if (drawnStepIds.has(id) || decisionSet.has(id)) return id;
2541
+ for (const child of (_a2 = childrenOf[id]) != null ? _a2 : []) {
2542
+ const found = firstDrawnIn(child);
2543
+ if (found) return found;
2544
+ }
2545
+ return void 0;
2546
+ }
2547
+ for (const decisionId of decisions) {
2548
+ for (const branchId of (_f = childrenOf[decisionId]) != null ? _f : []) {
2549
+ const reached = [...edges.values()].some(
2550
+ (e) => e.source === decisionId && (e.target === branchId || isInside(e.target, branchId))
2551
+ );
2552
+ const entry = reached ? void 0 : firstDrawnIn(branchId);
2553
+ if (entry) addEdge(decisionId, entry);
2554
+ }
2555
+ }
2556
+ const simpleNodes = [];
2557
+ function isBuiltInConcept(conceptRef) {
2558
+ const info = resolveConceptRef(graphspec, conceptRef);
2559
+ if (info) return info.domain_code === NATIVE_DOMAIN;
2560
+ return conceptRef.startsWith(`${NATIVE_DOMAIN}.`) || isGenericConcept(conceptRef);
2561
+ }
2562
+ function terminalNode(item, kind) {
2563
+ const digest = item.digest;
2564
+ const concept = item.concept;
2565
+ const isList = isPluralMultiplicity(item.multiplicity);
2566
+ let title;
2567
+ let subtitle;
2568
+ if (kind === "output" && concept && !isBuiltInConcept(concept)) {
2569
+ title = conceptPlainName(concept);
2570
+ } else {
2571
+ title = humanizeIdentifier(item.name);
2572
+ const plain = concept ? conceptPlainName(concept) : void 0;
2573
+ subtitle = plain && plain.toLowerCase() !== title.toLowerCase() ? plain : void 0;
2574
+ }
2575
+ const simple = __spreadValues({ kind, title, isList }, subtitle ? { subtitle } : {});
2576
+ return {
2577
+ id: stuffNodeId(digest),
2578
+ type: NODE_TYPE_SIMPLE_TERMINAL,
2579
+ data: {
2580
+ isPipe: false,
2581
+ isStuff: true,
2582
+ labelText: title,
2583
+ stuffRole: kind,
2584
+ stuffDigest: digest,
2585
+ graphMode,
2586
+ simple,
2587
+ layoutSize: simpleTerminalSize(title, subtitle !== void 0)
2588
+ },
2589
+ position: { x: 0, y: 0 }
2590
+ };
2591
+ }
2592
+ for (const item of [...inputItems.values(), ...danglingInputs.values()]) {
2593
+ simpleNodes.push(terminalNode(item, "input"));
2594
+ }
2595
+ function itemName(batchId) {
2596
+ var _a2, _b2, _c2, _d2;
2597
+ const batch = specById.get(batchId);
2598
+ if ((batch == null ? void 0 : batch.domain_code) && batch.pipe_code) {
2599
+ const blueprint = getPipeBlueprint(
2600
+ graphspec,
2601
+ makePipeRef(batch.domain_code, batch.pipe_code)
2602
+ );
2603
+ if ((blueprint == null ? void 0 : blueprint.type) === "PipeBatch" && blueprint.batch_params.input_item_stuff_name) {
2604
+ return blueprint.batch_params.input_item_stuff_name;
2605
+ }
2606
+ }
2607
+ const runsOfBatch = /* @__PURE__ */ new Set([batchId]);
2608
+ for (const [id, representative] of representativeOf) {
2609
+ if (representative === batchId) runsOfBatch.add(id);
2610
+ }
2611
+ const itemEdges = graphspec.edges.filter(
2612
+ (e) => e.kind === "batch_item" && runsOfBatch.has(e.source) && e.target_stuff_digest
2613
+ );
2614
+ const itemDigests = new Set(itemEdges.map((e) => e.target_stuff_digest));
2615
+ const branchId = (_b2 = batchBranch[batchId]) != null ? _b2 : (_a2 = rawAnalysis.containmentTree[batchId]) == null ? void 0 : _a2[0];
2616
+ const branch = branchId ? specById.get(branchId) : void 0;
2617
+ const read = branch == null ? void 0 : branch.io.inputs.find((i) => itemDigests.has(i.digest));
2618
+ if (read == null ? void 0 : read.name) return read.name;
2619
+ const firstItem = (_c2 = itemEdges.find((e) => e.source === batchId)) != null ? _c2 : itemEdges[0];
2620
+ return (firstItem == null ? void 0 : firstItem.target_stuff_digest) ? ((_d2 = analysis.stuffRegistry[firstItem.target_stuff_digest]) == null ? void 0 : _d2.name) || void 0 : void 0;
2621
+ }
2622
+ function stepsInside(id) {
2623
+ var _a2;
2624
+ const spec = specById.get(id);
2625
+ const children = (_a2 = rawAnalysis.containmentTree[id]) != null ? _a2 : [];
2626
+ if (children.length === 0) return spec && spec.kind === "operator" ? 1 : 0;
2627
+ const counted = (spec == null ? void 0 : spec.pipe_type) === "PipeBatch" ? children.slice(0, 1) : children;
2628
+ return counted.reduce((sum, child) => sum + stepsInside(child), 0);
2629
+ }
2630
+ function stepTitle(spec, folded) {
2631
+ var _a2, _b2, _c2, _d2, _e2, _f2;
2632
+ if (spec.pipe_type === BINDING_STEP_TYPE) {
2633
+ return humanizeIdentifier((_b2 = (_a2 = spec.pipe_code) == null ? void 0 : _a2.split(".").pop()) != null ? _b2 : "");
2634
+ }
2635
+ let source = spec;
2636
+ if (folded && spec.pipe_type === "PipeBatch") {
2637
+ const branch = specById.get((_d2 = (_c2 = rawAnalysis.containmentTree[spec.id]) == null ? void 0 : _c2[0]) != null ? _d2 : "");
2638
+ if (branch) source = branch;
2639
+ }
2640
+ const described = sentenceCase((_e2 = source.description) != null ? _e2 : "");
2641
+ return described || humanizeIdentifier((_f2 = source.pipe_code) != null ? _f2 : "");
2642
+ }
2643
+ const stepById = new Map(drawnSteps.map((card) => [card.id, card]));
2644
+ for (const spec of graphspec.nodes) {
2645
+ const card = stepById.get(spec.id);
2646
+ if (card) {
2647
+ const folded = card.data.isController === true;
2648
+ const pipeType = spec.pipe_type;
2649
+ const title = stepTitle(spec, folded);
2650
+ const markerBatch = (_g = markedSteps[spec.id]) != null ? _g : folded && pipeType === "PipeBatch" ? spec.id : void 0;
2651
+ const markerItem = markerBatch ? itemName(markerBatch) : void 0;
2652
+ const forEach = markerBatch ? forEachLabel(markerItem || "item") : void 0;
2653
+ const innerStepCount = folded ? stepsInside(spec.id) : void 0;
2654
+ const onExpand = (_h = card.data.pipeCardData) == null ? void 0 : _h.onExpand;
2655
+ const simple = __spreadValues(__spreadValues(__spreadValues(__spreadValues({
2656
+ kind: "step",
2657
+ title,
2658
+ category: STEP_CATEGORY_BY_PIPE_TYPE[pipeType],
2659
+ status: stepStatus(spec)
2660
+ }, graphMode !== void 0 ? { graphMode } : {}), forEach ? { forEach } : {}), innerStepCount !== void 0 ? { innerStepCount } : {}), onExpand ? { onExpand } : {});
2661
+ simpleNodes.push({
2662
+ id: spec.id,
2663
+ type: NODE_TYPE_SIMPLE_STEP,
2664
+ data: {
2665
+ nodeData: spec,
2666
+ isPipe: !folded,
2667
+ isStuff: false,
2668
+ isController: folded,
2669
+ labelText: title,
2670
+ pipeCode: spec.pipe_code,
2671
+ pipeType: spec.pipe_type,
2672
+ graphMode,
2673
+ simple,
2674
+ layoutSize: simpleStepSize(title, {
2675
+ forEach: forEach !== void 0,
2676
+ innerSteps: innerStepCount !== void 0
2677
+ })
2678
+ },
2679
+ position: { x: 0, y: 0 }
2680
+ });
2681
+ continue;
2682
+ }
2683
+ if (decisionSet.has(spec.id)) {
2684
+ const title = sentenceCase((_i = spec.description) != null ? _i : "") || humanizeIdentifier((_j = spec.pipe_code) != null ? _j : "");
2685
+ simpleNodes.push({
2686
+ id: spec.id,
2687
+ type: NODE_TYPE_SIMPLE_DECISION,
2688
+ data: {
2689
+ nodeData: spec,
2690
+ isPipe: false,
2691
+ isStuff: false,
2692
+ isController: true,
2693
+ labelText: title,
2694
+ pipeCode: spec.pipe_code,
2695
+ pipeType: spec.pipe_type,
2696
+ graphMode,
2697
+ simple: __spreadValues({
2698
+ kind: "decision",
2699
+ title,
2700
+ status: stepStatus(spec)
2701
+ }, graphMode !== void 0 ? { graphMode } : {}),
2702
+ layoutSize: simpleDecisionSize(title)
2703
+ },
2704
+ position: { x: 0, y: 0 }
2705
+ });
2706
+ }
2707
+ }
2708
+ for (const item of outputItems.values()) {
2709
+ simpleNodes.push(terminalNode(item, "output"));
2710
+ }
2711
+ const nearestFrame = (id) => {
2712
+ let current = parentOf[id];
2713
+ while (current) {
2714
+ if (frameSet.has(current)) return current;
2715
+ current = parentOf[current];
2716
+ }
2717
+ return void 0;
2718
+ };
2719
+ const containmentTree = {};
2720
+ for (const frameId of frameSet) containmentTree[frameId] = [];
2721
+ for (const node of simpleNodes) {
2722
+ const frameId = node.data.isStuff ? void 0 : nearestFrame(node.id);
2723
+ if (frameId) containmentTree[frameId].push(node.id);
2724
+ }
2725
+ for (const frameId of frameSet) {
2726
+ const outer = nearestFrame(frameId);
2727
+ if (outer) containmentTree[outer].push(frameId);
2728
+ }
2729
+ const childNodeIds = new Set(Object.values(containmentTree).flat());
2730
+ for (const frameId of frameSet) {
2731
+ const spec = specById.get(frameId);
2732
+ if (!spec) continue;
2733
+ const title = forEachLabel(itemName(frameId) || "item");
2734
+ simpleNodes.push({
2735
+ id: frameId,
2736
+ type: NODE_TYPE_SIMPLE_FRAME,
2737
+ data: {
2738
+ nodeData: spec,
2739
+ isPipe: false,
2740
+ isStuff: false,
2741
+ isController: true,
2742
+ labelText: title,
2743
+ pipeCode: spec.pipe_code,
2744
+ pipeType: spec.pipe_type,
2745
+ graphMode,
2746
+ simple: __spreadValues({
2747
+ kind: "frame",
2748
+ title,
2749
+ status: stepStatus(spec)
2750
+ }, graphMode !== void 0 ? { graphMode } : {})
2751
+ },
2752
+ position: { x: 0, y: 0 }
2753
+ });
2754
+ }
2755
+ const drawnIds = new Set(simpleNodes.map((n) => n.id));
2756
+ const standIns = /* @__PURE__ */ new Map();
2757
+ const resolving = /* @__PURE__ */ new Set();
2758
+ function standIn(id) {
2759
+ var _a2, _b2, _c2, _d2, _e2;
2760
+ if (drawnIds.has(id)) return id;
2761
+ if (standIns.has(id)) return standIns.get(id);
2762
+ if (resolving.has(id)) return void 0;
2763
+ resolving.add(id);
2764
+ let found;
2765
+ const representative = (_a2 = foldedAbove.get(id)) != null ? _a2 : representativeOf.get(id);
2766
+ const branch = batchBranch[id];
2767
+ if (representative) {
2768
+ found = standIn(representative);
2769
+ } else if (branch && markedSteps[branch] === id) {
2770
+ found = standIn(branch);
2771
+ } else if (pipeTypeOf(id) === BINDING_STEP_TYPE) {
2772
+ for (const item of (_c2 = (_b2 = specById.get(id)) == null ? void 0 : _b2.io.outputs) != null ? _c2 : []) {
2773
+ if (!item.digest) continue;
2774
+ for (const reader of (_d2 = rawAnalysis.stuffConsumers[item.digest]) != null ? _d2 : []) {
2775
+ found != null ? found : found = standIn(reader);
2776
+ }
2777
+ if (!found && drawnIds.has(stuffNodeId(item.digest))) found = stuffNodeId(item.digest);
2778
+ if (found) break;
2779
+ }
2780
+ const parent = parentOf[id];
2781
+ if (!found && parent) found = standIn(parent);
2782
+ } else {
2783
+ for (const child of (_e2 = childrenOf[id]) != null ? _e2 : []) {
2784
+ found = standIn(child);
2785
+ if (found) break;
2786
+ }
2787
+ }
2788
+ resolving.delete(id);
2789
+ if (found) standIns.set(id, found);
2790
+ return found;
2791
+ }
2792
+ for (const spec of graphspec.nodes) standIn(spec.id);
2793
+ return {
2794
+ nodes: simpleNodes,
2795
+ edges: [...edges.values()],
2796
+ standIns,
2797
+ analysis: {
2798
+ stuffRegistry: analysis.stuffRegistry,
2799
+ stuffProducers: {},
2800
+ stuffConsumers: {},
2801
+ controllerNodeIds: frameSet,
2802
+ childNodeIds,
2803
+ containmentTree
2804
+ }
2805
+ };
2806
+ }
2807
+ function simpleEdgeLabelSize(label) {
2808
+ const [padX, padY] = EDGE_LABEL_PADDING;
2809
+ return {
2810
+ width: Math.ceil(textWidthPx(label, EDGE_LABEL_FONT_PX)) + 2 * padX,
2811
+ height: EDGE_LABEL_LINE_HEIGHT + 2 * padY
2812
+ };
2813
+ }
2814
+ function simpleEdge(id, source, target, label) {
2815
+ const edge = {
2816
+ id,
2817
+ source,
2818
+ target,
2819
+ type: EDGE_TYPE_ROUTED,
2820
+ animated: false,
2821
+ style: { stroke: "var(--color-edge)", strokeWidth: 1.5 },
2822
+ markerEnd: { type: ARROW_CLOSED_MARKER, color: "var(--color-edge)" }
2823
+ };
2824
+ if (label) {
2825
+ edge.label = label;
2826
+ edge.labelStyle = {
2827
+ fontSize: `${EDGE_LABEL_FONT_PX}px`,
2828
+ fontFamily: "var(--font-sans)",
2829
+ fontWeight: 600,
2830
+ fill: "var(--ctrl-condition-text)"
2831
+ };
2832
+ edge.labelBgStyle = { fill: "var(--color-bg)", fillOpacity: 0.92 };
2833
+ edge.labelBgPadding = [...EDGE_LABEL_PADDING];
2834
+ edge.labelBgBorderRadius = 4;
2835
+ edge.labelSize = simpleEdgeLabelSize(label);
2836
+ }
2837
+ return edge;
2838
+ }
2839
+ function simpleDefaultFolds(graphspec, rawAnalysis) {
2840
+ const parentOf = parentMap(rawAnalysis.containmentTree);
2841
+ const sequenceIds = new Set(
2842
+ graphspec.nodes.filter((n) => n.pipe_type === "PipeSequence").map((n) => n.id)
2843
+ );
2844
+ const folded = /* @__PURE__ */ new Set();
2845
+ for (const ctrlId of rawAnalysis.controllerNodeIds) {
2846
+ let depth = 0;
2847
+ let current = parentOf[ctrlId];
2848
+ while (current) {
2849
+ depth += 1;
2850
+ current = parentOf[current];
2851
+ }
2852
+ if (depth >= SIMPLE_FOLD_DEPTH && sequenceIds.has(ctrlId)) folded.add(ctrlId);
2853
+ }
2854
+ return folded;
2855
+ }
2856
+ function applySimpleFrames(args) {
2857
+ const { nodes, edges, graphspec, analysis, controllerPositions, onToggleFold } = args;
2858
+ const placeholders = /* @__PURE__ */ new Map();
2859
+ const content = [];
2860
+ for (const node of nodes) {
2861
+ if (node.type === NODE_TYPE_SIMPLE_FRAME) placeholders.set(node.id, node);
2862
+ else content.push(node);
2863
+ }
2864
+ if (analysis.controllerNodeIds.size === 0) return { nodes: content, edges };
2865
+ const groups = buildControllerNodes(graphspec, analysis, content, controllerPositions);
2866
+ const frames = groups.map((group) => {
2867
+ var _a;
2868
+ const placeholder = placeholders.get(group.id);
2869
+ const id = group.id;
2870
+ const simple = placeholder == null ? void 0 : placeholder.data.simple;
2871
+ const withFold = (simple == null ? void 0 : simple.kind) === "frame" && onToggleFold ? __spreadProps(__spreadValues({}, simple), { onFold: (options) => onToggleFold(id, options) }) : simple;
2872
+ return __spreadProps(__spreadValues({}, group), {
2873
+ type: NODE_TYPE_SIMPLE_FRAME,
2874
+ data: __spreadProps(__spreadValues({}, (_a = placeholder == null ? void 0 : placeholder.data) != null ? _a : group.data), { simple: withFold })
2875
+ });
2876
+ });
2877
+ return { nodes: sortParentsFirst([...frames, ...content]), edges };
1679
2878
  }
1680
2879
 
2880
+ // src/graph/styles/stylePipelines.ts
2881
+ var GRAPH_STYLE_PIPELINES = {
2882
+ // Today's drawing: the dataflow graph as built, framed by controller groups
2883
+ // when the viewer shows them.
2884
+ [GRAPH_STYLE.DETAILED]: {
2885
+ defaultFolds: () => /* @__PURE__ */ new Set(),
2886
+ project: ({ nodes, edges, analysis }) => ({ nodes, edges, analysis }),
2887
+ frame: (args) => applyControllers(
2888
+ args.nodes,
2889
+ args.edges,
2890
+ args.graphspec,
2891
+ args.analysis,
2892
+ args.showControllers,
2893
+ args.expandedControllers,
2894
+ args.onToggleCollapse,
2895
+ args.controllerPositions,
2896
+ args.onToggleFold
2897
+ )
2898
+ },
2899
+ [GRAPH_STYLE.SIMPLE]: {
2900
+ defaultFolds: simpleDefaultFolds,
2901
+ project: ({ graphspec, nodes, analysis, rawAnalysis }) => analysis && rawAnalysis ? projectSimpleGraph({ graphspec, nodes, analysis, rawAnalysis }) : { nodes: [], edges: [], analysis: null },
2902
+ // Its frames are its own decision, whatever the controllers toggle says.
2903
+ frame: (args) => args.graphspec && args.analysis ? applySimpleFrames({
2904
+ nodes: args.nodes,
2905
+ edges: args.edges,
2906
+ graphspec: args.graphspec,
2907
+ analysis: args.analysis,
2908
+ controllerPositions: args.controllerPositions,
2909
+ onToggleFold: args.onToggleFold
2910
+ }) : { nodes: args.nodes, edges: args.edges }
2911
+ }
2912
+ };
2913
+
1681
2914
  export {
1682
2915
  GraphSpecValidationError,
1683
2916
  validateGraphSpec,
@@ -1705,9 +2938,49 @@ export {
1705
2938
  estimateNodeDimensions,
1706
2939
  buildElkGraph,
1707
2940
  extractAbsolutePositions,
2941
+ extractEdgeRoutes,
1708
2942
  getLayoutedElements,
2943
+ ROUTE_ENDPOINT_TOLERANCE_PX,
2944
+ ROUTE_CORNER_RADIUS_PX,
2945
+ fitRoute,
2946
+ roundedPolylinePath,
2947
+ polylineMidpoint,
2948
+ routeLabelCenter,
1709
2949
  MAX_VISIBLE_CONTROLLER_CHILDREN,
1710
2950
  buildControllerNodes,
1711
- applyControllers
2951
+ applyControllers,
2952
+ sortParentsFirst,
2953
+ GRAPH_STYLES,
2954
+ GRAPH_STYLE_IDS,
2955
+ isGraphStyleId,
2956
+ resolveGraphStyle,
2957
+ resolveStyleMenu,
2958
+ stripDomain,
2959
+ humanizeIdentifier,
2960
+ conceptPlainName,
2961
+ isGenericConcept,
2962
+ sentenceCase,
2963
+ outcomeLabel,
2964
+ textWidthPx,
2965
+ estimateWrap,
2966
+ SIMPLE_STEP_WIDTH,
2967
+ SIMPLE_STEP_WIDE_WIDTH,
2968
+ SIMPLE_STEP_TITLE_FONT_PX,
2969
+ SIMPLE_TITLE_MAX_LINES,
2970
+ SIMPLE_TERMINAL_WIDTH,
2971
+ SIMPLE_DECISION_WIDTHS,
2972
+ SIMPLE_FOLD_DEPTH,
2973
+ STEP_CATEGORY_BY_PIPE_TYPE,
2974
+ STEP_CATEGORY_WORDS,
2975
+ simpleStepSize,
2976
+ simpleTerminalSize,
2977
+ simpleDecisionSize,
2978
+ simpleTitleWrap,
2979
+ aggregateStatus,
2980
+ projectSimpleGraph,
2981
+ simpleEdgeLabelSize,
2982
+ simpleDefaultFolds,
2983
+ applySimpleFrames,
2984
+ GRAPH_STYLE_PIPELINES
1712
2985
  };
1713
- //# sourceMappingURL=chunk-ZTXSDTVF.js.map
2986
+ //# sourceMappingURL=chunk-3BXB6HSF.js.map