@crazyhappyone/auto-graph 0.0.2 → 0.0.4
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/cli/index.cjs +737 -28
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +737 -28
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +737 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +737 -28
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.cjs
CHANGED
|
@@ -433,15 +433,30 @@ function renderSwimlane(swimlane) {
|
|
|
433
433
|
lines.push(
|
|
434
434
|
` <rect class="swimlane-lane" data-lane="${escapeAttribute(`${swimlane.id}.${lane.id}`)}" x="${formatNumber(lane.box.x)}" y="${formatNumber(lane.box.y)}" width="${formatNumber(lane.box.width)}" height="${formatNumber(lane.box.height)}" fill="none" stroke="${STROKE}"/>`
|
|
435
435
|
);
|
|
436
|
-
if (lane.
|
|
436
|
+
if (lane.headerBox !== void 0) {
|
|
437
437
|
lines.push(
|
|
438
|
-
` <
|
|
438
|
+
` <rect class="swimlane-header" data-lane-header="${escapeAttribute(`${swimlane.id}.${lane.id}`)}" x="${formatNumber(lane.headerBox.x)}" y="${formatNumber(lane.headerBox.y)}" width="${formatNumber(lane.headerBox.width)}" height="${formatNumber(lane.headerBox.height)}" fill="#f3f4f6" stroke="${STROKE}"/>`
|
|
439
439
|
);
|
|
440
440
|
}
|
|
441
|
+
if (lane.contentBox !== void 0) {
|
|
442
|
+
lines.push(
|
|
443
|
+
` <rect class="swimlane-content" data-lane-content="${escapeAttribute(`${swimlane.id}.${lane.id}`)}" x="${formatNumber(lane.contentBox.x)}" y="${formatNumber(lane.contentBox.y)}" width="${formatNumber(lane.contentBox.width)}" height="${formatNumber(lane.contentBox.height)}" fill="none" stroke="none"/>`
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
if (lane.label?.text !== void 0) {
|
|
447
|
+
const labelBox = lane.headerBox ?? lane.box;
|
|
448
|
+
lines.push(renderSwimlaneLabel(swimlane, lane.label.text, labelBox));
|
|
449
|
+
}
|
|
441
450
|
}
|
|
442
451
|
lines.push(" </g>");
|
|
443
452
|
return lines;
|
|
444
453
|
}
|
|
454
|
+
function renderSwimlaneLabel(swimlane, text, labelBox) {
|
|
455
|
+
const x = labelBox.x + labelBox.width / 2;
|
|
456
|
+
const y = labelBox.y + labelBox.height / 2;
|
|
457
|
+
const transform = swimlane.orientation === "horizontal" ? ` transform="rotate(-90 ${formatNumber(x)} ${formatNumber(y)})"` : "";
|
|
458
|
+
return ` <text class="swimlane-label" x="${formatNumber(x)}" y="${formatNumber(y)}" text-anchor="middle" dominant-baseline="middle"${transform} font-family="${FONT_FAMILY}" font-size="12" fill="#111827">${escapeXml(text)}</text>`;
|
|
459
|
+
}
|
|
445
460
|
function renderPorts(node) {
|
|
446
461
|
return (node.ports ?? []).flatMap((port) => [
|
|
447
462
|
` <rect class="port" data-kind="${escapeAttribute(port.kind)}" data-port="${escapeAttribute(`${node.id}.${port.id}`)}" x="${formatNumber(port.box.x)}" y="${formatNumber(port.box.y)}" width="${formatNumber(port.box.width)}" height="${formatNumber(port.box.height)}" fill="${escapeAttribute(port.style?.fill ?? "#d9ead3")}" stroke="${escapeAttribute(port.style?.stroke ?? STROKE)}"/>`,
|
|
@@ -507,7 +522,7 @@ function renderRect(box, attributes) {
|
|
|
507
522
|
function renderLabel(label, box, item) {
|
|
508
523
|
const labelLayout = item.labelLayout;
|
|
509
524
|
if (labelLayout?.lines !== void 0 && labelLayout.lines.length > 0) {
|
|
510
|
-
const offset =
|
|
525
|
+
const offset = { x: box.x, y: box.y };
|
|
511
526
|
return [
|
|
512
527
|
` <text class="label" data-for="${escapeAttribute(item.id)}" font-family="${FONT_FAMILY}" font-size="${formatNumber(labelLayout.font.fontSize)}" fill="#111827">`,
|
|
513
528
|
...labelLayout.lines.map(
|
|
@@ -606,9 +621,6 @@ function pathPointsBeforeArrowhead(points) {
|
|
|
606
621
|
};
|
|
607
622
|
return [...points.slice(0, -1), base];
|
|
608
623
|
}
|
|
609
|
-
function isAbsoluteLabelLayout(labelBox, itemBox) {
|
|
610
|
-
return labelBox.x >= itemBox.x && labelBox.y >= itemBox.y && labelBox.x + labelBox.width <= itemBox.x + itemBox.width && labelBox.y + labelBox.height <= itemBox.y + itemBox.height;
|
|
611
|
-
}
|
|
612
624
|
function shapePoints(shape, box) {
|
|
613
625
|
const left = box.x;
|
|
614
626
|
const right = box.x + box.width;
|
|
@@ -1720,6 +1732,19 @@ function solveDiagram(diagram, options = {}) {
|
|
|
1720
1732
|
constraints
|
|
1721
1733
|
});
|
|
1722
1734
|
diagnostics.push(...constrained.diagnostics);
|
|
1735
|
+
const swimlaneContracts = applySwimlaneLayoutContracts(
|
|
1736
|
+
diagram.swimlanes ?? [],
|
|
1737
|
+
constraints,
|
|
1738
|
+
edges,
|
|
1739
|
+
isTopToBottomReadingDirection(diagram.metadata?.primaryReadingDirection),
|
|
1740
|
+
constrained.boxes,
|
|
1741
|
+
constrained.locks,
|
|
1742
|
+
options?.overlapSpacing ?? 40
|
|
1743
|
+
);
|
|
1744
|
+
if (swimlaneContracts.layouts.size > 0) {
|
|
1745
|
+
removeResolvedOverlapDiagnostics(diagnostics, constrained.boxes);
|
|
1746
|
+
}
|
|
1747
|
+
diagnostics.push(...swimlaneContracts.diagnostics);
|
|
1723
1748
|
const coordinatedNodes = coordinateNodes(
|
|
1724
1749
|
nodes,
|
|
1725
1750
|
constrained.boxes,
|
|
@@ -1744,7 +1769,8 @@ function solveDiagram(diagram, options = {}) {
|
|
|
1744
1769
|
);
|
|
1745
1770
|
const coordinatedSwimlanes = coordinateSwimlanes(
|
|
1746
1771
|
diagram.swimlanes ?? [],
|
|
1747
|
-
constrained.boxes
|
|
1772
|
+
constrained.boxes,
|
|
1773
|
+
swimlaneContracts.layouts
|
|
1748
1774
|
);
|
|
1749
1775
|
const groupBoxes = new Map(
|
|
1750
1776
|
coordinatedGroups.map((group) => [group.id, group.box])
|
|
@@ -1786,6 +1812,591 @@ function solveDiagram(diagram, options = {}) {
|
|
|
1786
1812
|
...diagram.metadata === void 0 ? {} : { metadata: diagram.metadata }
|
|
1787
1813
|
};
|
|
1788
1814
|
}
|
|
1815
|
+
function applySwimlaneLayoutContracts(swimlanes, constraints, edges, topToBottomFlow, nodeBoxes, locks, overlapSpacing) {
|
|
1816
|
+
const layouts = /* @__PURE__ */ new Map();
|
|
1817
|
+
const diagnostics = [];
|
|
1818
|
+
const movedChildIds = /* @__PURE__ */ new Set();
|
|
1819
|
+
for (const swimlane of swimlanes) {
|
|
1820
|
+
if ((swimlane.layout ?? "overlay") !== "contract") {
|
|
1821
|
+
continue;
|
|
1822
|
+
}
|
|
1823
|
+
if (swimlane.lanes.length === 0) {
|
|
1824
|
+
continue;
|
|
1825
|
+
}
|
|
1826
|
+
const layout2 = applySingleSwimlaneContract(
|
|
1827
|
+
swimlane,
|
|
1828
|
+
edges,
|
|
1829
|
+
topToBottomFlow,
|
|
1830
|
+
nodeBoxes,
|
|
1831
|
+
locks,
|
|
1832
|
+
diagnostics,
|
|
1833
|
+
movedChildIds
|
|
1834
|
+
);
|
|
1835
|
+
if (layout2 !== void 0) {
|
|
1836
|
+
layouts.set(swimlane.id, layout2);
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1839
|
+
if (layouts.size > 0) {
|
|
1840
|
+
diagnostics.push(
|
|
1841
|
+
...reportSwimlaneOverlaps(nodeBoxes, locks, overlapSpacing),
|
|
1842
|
+
...reportSwimlaneConstraintInvalidations(
|
|
1843
|
+
constraints,
|
|
1844
|
+
nodeBoxes,
|
|
1845
|
+
movedChildIds
|
|
1846
|
+
)
|
|
1847
|
+
);
|
|
1848
|
+
}
|
|
1849
|
+
return { layouts, diagnostics, movedChildIds };
|
|
1850
|
+
}
|
|
1851
|
+
function applySingleSwimlaneContract(swimlane, edges, topToBottomFlow, nodeBoxes, locks, diagnostics, movedChildIds) {
|
|
1852
|
+
const headerHeight = swimlane.headerHeight ?? 28;
|
|
1853
|
+
const padding = swimlane.padding ?? 16;
|
|
1854
|
+
const laneBounds = swimlane.lanes.map((lane) => {
|
|
1855
|
+
const childBoxes = lane.children.map((child) => nodeBoxes.get(child)).filter((box) => box !== void 0);
|
|
1856
|
+
return childBoxes.length === 0 ? void 0 : unionBoxes(childBoxes);
|
|
1857
|
+
});
|
|
1858
|
+
const populatedBounds = laneBounds.filter(
|
|
1859
|
+
(box) => box !== void 0
|
|
1860
|
+
);
|
|
1861
|
+
if (populatedBounds.length === 0) {
|
|
1862
|
+
return void 0;
|
|
1863
|
+
}
|
|
1864
|
+
if (swimlane.orientation === "vertical") {
|
|
1865
|
+
return applyVerticalSwimlaneContract(
|
|
1866
|
+
swimlane,
|
|
1867
|
+
edges,
|
|
1868
|
+
topToBottomFlow,
|
|
1869
|
+
nodeBoxes,
|
|
1870
|
+
laneBounds,
|
|
1871
|
+
headerHeight,
|
|
1872
|
+
padding,
|
|
1873
|
+
locks,
|
|
1874
|
+
diagnostics,
|
|
1875
|
+
movedChildIds
|
|
1876
|
+
);
|
|
1877
|
+
}
|
|
1878
|
+
return applyHorizontalSwimlaneContract(
|
|
1879
|
+
swimlane,
|
|
1880
|
+
nodeBoxes,
|
|
1881
|
+
laneBounds,
|
|
1882
|
+
headerHeight,
|
|
1883
|
+
padding,
|
|
1884
|
+
locks,
|
|
1885
|
+
diagnostics,
|
|
1886
|
+
movedChildIds
|
|
1887
|
+
);
|
|
1888
|
+
}
|
|
1889
|
+
function applyVerticalSwimlaneContract(swimlane, edges, topToBottomFlow, nodeBoxes, laneBounds, headerHeight, padding, locks, diagnostics, movedChildIds) {
|
|
1890
|
+
const populatedBounds = laneBounds.filter(
|
|
1891
|
+
(box) => box !== void 0
|
|
1892
|
+
);
|
|
1893
|
+
const top = Math.min(...populatedBounds.map((box) => box.y));
|
|
1894
|
+
const left = Math.min(...populatedBounds.map((box) => box.x));
|
|
1895
|
+
const maxChildHeight = Math.max(...populatedBounds.map((box) => box.height));
|
|
1896
|
+
const flowRanks = topToBottomFlow ? rankVerticalSwimlaneChildren(swimlane, edges) : /* @__PURE__ */ new Map();
|
|
1897
|
+
const maxRank = flowRanks.size === 0 ? 0 : Math.max(...Array.from(flowRanks.values()));
|
|
1898
|
+
const rankStackGap = Math.max(8, padding / 2);
|
|
1899
|
+
const maxRankStackHeight = maxVerticalRankStackHeight(
|
|
1900
|
+
swimlane,
|
|
1901
|
+
nodeBoxes,
|
|
1902
|
+
flowRanks,
|
|
1903
|
+
rankStackGap
|
|
1904
|
+
);
|
|
1905
|
+
const rankSpacing = Math.max(96, maxRankStackHeight + padding);
|
|
1906
|
+
const contentHeight = maxRank === 0 ? maxChildHeight : maxRankStackHeight + maxRank * rankSpacing;
|
|
1907
|
+
const slotWidth = Math.max(...populatedBounds.map((box) => box.width)) + padding * 2;
|
|
1908
|
+
const laneContentTop = top + headerHeight + padding;
|
|
1909
|
+
for (let index = 0; index < swimlane.lanes.length; index += 1) {
|
|
1910
|
+
const lane = swimlane.lanes[index];
|
|
1911
|
+
const bounds = laneBounds[index];
|
|
1912
|
+
if (lane === void 0 || bounds === void 0) {
|
|
1913
|
+
continue;
|
|
1914
|
+
}
|
|
1915
|
+
const target = {
|
|
1916
|
+
x: left + slotWidth * index + padding,
|
|
1917
|
+
y: laneContentTop
|
|
1918
|
+
};
|
|
1919
|
+
if (maxRank === 0) {
|
|
1920
|
+
moveLaneChildren(
|
|
1921
|
+
lane.children,
|
|
1922
|
+
nodeBoxes,
|
|
1923
|
+
locks,
|
|
1924
|
+
diagnostics,
|
|
1925
|
+
movedChildIds,
|
|
1926
|
+
{
|
|
1927
|
+
x: target.x - bounds.x,
|
|
1928
|
+
y: target.y - bounds.y
|
|
1929
|
+
}
|
|
1930
|
+
);
|
|
1931
|
+
continue;
|
|
1932
|
+
}
|
|
1933
|
+
moveRankedVerticalLaneChildren(
|
|
1934
|
+
lane.children,
|
|
1935
|
+
nodeBoxes,
|
|
1936
|
+
locks,
|
|
1937
|
+
diagnostics,
|
|
1938
|
+
movedChildIds,
|
|
1939
|
+
flowRanks,
|
|
1940
|
+
rankSpacing,
|
|
1941
|
+
rankStackGap,
|
|
1942
|
+
{
|
|
1943
|
+
x: target.x - bounds.x,
|
|
1944
|
+
y: laneContentTop
|
|
1945
|
+
}
|
|
1946
|
+
);
|
|
1947
|
+
}
|
|
1948
|
+
return {
|
|
1949
|
+
box: {
|
|
1950
|
+
x: left,
|
|
1951
|
+
y: top,
|
|
1952
|
+
width: slotWidth * swimlane.lanes.length,
|
|
1953
|
+
height: contentHeight + padding * 2 + headerHeight
|
|
1954
|
+
},
|
|
1955
|
+
slotWidth,
|
|
1956
|
+
slotHeight: contentHeight + padding * 2 + headerHeight
|
|
1957
|
+
};
|
|
1958
|
+
}
|
|
1959
|
+
function isTopToBottomReadingDirection(value) {
|
|
1960
|
+
return value === "top_to_bottom" || value === "top-to-bottom";
|
|
1961
|
+
}
|
|
1962
|
+
function rankVerticalSwimlaneChildren(swimlane, edges) {
|
|
1963
|
+
const childOrder = /* @__PURE__ */ new Map();
|
|
1964
|
+
for (const lane of swimlane.lanes) {
|
|
1965
|
+
for (const childId of lane.children) {
|
|
1966
|
+
if (!childOrder.has(childId)) {
|
|
1967
|
+
childOrder.set(childId, childOrder.size);
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
if (childOrder.size === 0) {
|
|
1972
|
+
return /* @__PURE__ */ new Map();
|
|
1973
|
+
}
|
|
1974
|
+
const childIds = new Set(childOrder.keys());
|
|
1975
|
+
const relevantEdges = edges.filter(
|
|
1976
|
+
(edge) => childIds.has(edge.source.nodeId) && childIds.has(edge.target.nodeId) && edge.source.nodeId !== edge.target.nodeId
|
|
1977
|
+
);
|
|
1978
|
+
if (relevantEdges.length === 0) {
|
|
1979
|
+
return /* @__PURE__ */ new Map();
|
|
1980
|
+
}
|
|
1981
|
+
const ranks = new Map([...childIds].map((id) => [id, 0]));
|
|
1982
|
+
const outgoing = /* @__PURE__ */ new Map();
|
|
1983
|
+
const inDegree = new Map([...childIds].map((id) => [id, 0]));
|
|
1984
|
+
for (const edge of relevantEdges) {
|
|
1985
|
+
const targets = outgoing.get(edge.source.nodeId) ?? [];
|
|
1986
|
+
targets.push(edge.target.nodeId);
|
|
1987
|
+
outgoing.set(edge.source.nodeId, targets);
|
|
1988
|
+
inDegree.set(
|
|
1989
|
+
edge.target.nodeId,
|
|
1990
|
+
(inDegree.get(edge.target.nodeId) ?? 0) + 1
|
|
1991
|
+
);
|
|
1992
|
+
}
|
|
1993
|
+
const queue = [...childIds].filter((id) => (inDegree.get(id) ?? 0) === 0).sort((a, b) => (childOrder.get(a) ?? 0) - (childOrder.get(b) ?? 0));
|
|
1994
|
+
let visited = 0;
|
|
1995
|
+
for (let cursor = 0; cursor < queue.length; cursor += 1) {
|
|
1996
|
+
const sourceId = queue[cursor];
|
|
1997
|
+
if (sourceId === void 0) {
|
|
1998
|
+
continue;
|
|
1999
|
+
}
|
|
2000
|
+
visited += 1;
|
|
2001
|
+
for (const targetId of outgoing.get(sourceId) ?? []) {
|
|
2002
|
+
ranks.set(
|
|
2003
|
+
targetId,
|
|
2004
|
+
Math.max(ranks.get(targetId) ?? 0, (ranks.get(sourceId) ?? 0) + 1)
|
|
2005
|
+
);
|
|
2006
|
+
const nextInDegree = (inDegree.get(targetId) ?? 0) - 1;
|
|
2007
|
+
inDegree.set(targetId, nextInDegree);
|
|
2008
|
+
if (nextInDegree === 0) {
|
|
2009
|
+
queue.push(targetId);
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
return visited === childIds.size ? ranks : rankCyclicSwimlaneChildren(childIds, relevantEdges);
|
|
2014
|
+
}
|
|
2015
|
+
function rankCyclicSwimlaneChildren(childIds, edges) {
|
|
2016
|
+
const maxRank = Math.max(0, childIds.size - 1);
|
|
2017
|
+
const ranks = new Map([...childIds].map((id) => [id, 0]));
|
|
2018
|
+
for (let iteration = 0; iteration < childIds.size; iteration += 1) {
|
|
2019
|
+
let changed = false;
|
|
2020
|
+
for (const edge of edges) {
|
|
2021
|
+
const nextRank = Math.min(
|
|
2022
|
+
maxRank,
|
|
2023
|
+
(ranks.get(edge.source.nodeId) ?? 0) + 1
|
|
2024
|
+
);
|
|
2025
|
+
if (nextRank > (ranks.get(edge.target.nodeId) ?? 0)) {
|
|
2026
|
+
ranks.set(edge.target.nodeId, nextRank);
|
|
2027
|
+
changed = true;
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
if (!changed) {
|
|
2031
|
+
break;
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
return ranks;
|
|
2035
|
+
}
|
|
2036
|
+
function maxVerticalRankStackHeight(swimlane, nodeBoxes, flowRanks, gap) {
|
|
2037
|
+
let maxHeight = 0;
|
|
2038
|
+
for (const lane of swimlane.lanes) {
|
|
2039
|
+
for (const stack of rankStacks(
|
|
2040
|
+
lane.children,
|
|
2041
|
+
nodeBoxes,
|
|
2042
|
+
flowRanks
|
|
2043
|
+
).values()) {
|
|
2044
|
+
const height = stack.reduce(
|
|
2045
|
+
(total, item, index) => total + item.box.height + (index === 0 ? 0 : gap),
|
|
2046
|
+
0
|
|
2047
|
+
);
|
|
2048
|
+
maxHeight = Math.max(maxHeight, height);
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
return maxHeight;
|
|
2052
|
+
}
|
|
2053
|
+
function moveRankedVerticalLaneChildren(childIds, nodeBoxes, locks, diagnostics, movedChildIds, flowRanks, rankSpacing, rankStackGap, target) {
|
|
2054
|
+
for (const [rank, stack] of rankStacks(childIds, nodeBoxes, flowRanks)) {
|
|
2055
|
+
let yOffset = 0;
|
|
2056
|
+
for (const item of stack) {
|
|
2057
|
+
const { childId, box } = item;
|
|
2058
|
+
if (locks.has(childId)) {
|
|
2059
|
+
diagnostics.push({
|
|
2060
|
+
severity: "warning",
|
|
2061
|
+
code: "constraints.locked-target-not-moved",
|
|
2062
|
+
message: `Locked child ${childId} was not moved into contract swimlane slot.`,
|
|
2063
|
+
path: ["swimlanes"],
|
|
2064
|
+
detail: { nodeId: childId }
|
|
2065
|
+
});
|
|
2066
|
+
continue;
|
|
2067
|
+
}
|
|
2068
|
+
const next = {
|
|
2069
|
+
...box,
|
|
2070
|
+
x: box.x + target.x,
|
|
2071
|
+
y: target.y + rank * rankSpacing + yOffset
|
|
2072
|
+
};
|
|
2073
|
+
if (next.x !== box.x || next.y !== box.y) {
|
|
2074
|
+
movedChildIds.add(childId);
|
|
2075
|
+
}
|
|
2076
|
+
nodeBoxes.set(childId, next);
|
|
2077
|
+
yOffset += box.height + rankStackGap;
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
function rankStacks(childIds, nodeBoxes, flowRanks) {
|
|
2082
|
+
const stacks = /* @__PURE__ */ new Map();
|
|
2083
|
+
for (const childId of childIds) {
|
|
2084
|
+
const box = nodeBoxes.get(childId);
|
|
2085
|
+
if (box === void 0) {
|
|
2086
|
+
continue;
|
|
2087
|
+
}
|
|
2088
|
+
const rank = flowRanks.get(childId) ?? 0;
|
|
2089
|
+
const stack = stacks.get(rank) ?? [];
|
|
2090
|
+
stack.push({ childId, box });
|
|
2091
|
+
stacks.set(rank, stack);
|
|
2092
|
+
}
|
|
2093
|
+
for (const stack of stacks.values()) {
|
|
2094
|
+
stack.sort((a, b) => {
|
|
2095
|
+
const deltaY = a.box.y - b.box.y;
|
|
2096
|
+
return deltaY === 0 ? a.childId.localeCompare(b.childId) : deltaY;
|
|
2097
|
+
});
|
|
2098
|
+
}
|
|
2099
|
+
return stacks;
|
|
2100
|
+
}
|
|
2101
|
+
function applyHorizontalSwimlaneContract(swimlane, nodeBoxes, laneBounds, headerHeight, padding, locks, diagnostics, movedChildIds) {
|
|
2102
|
+
const populatedBounds = laneBounds.filter(
|
|
2103
|
+
(box) => box !== void 0
|
|
2104
|
+
);
|
|
2105
|
+
const top = Math.min(...populatedBounds.map((box) => box.y));
|
|
2106
|
+
const left = Math.min(...populatedBounds.map((box) => box.x));
|
|
2107
|
+
const slotWidth = Math.max(...populatedBounds.map((box) => box.width)) + headerHeight + padding * 2;
|
|
2108
|
+
const slotHeight = Math.max(...populatedBounds.map((box) => box.height)) + padding * 2;
|
|
2109
|
+
for (let index = 0; index < swimlane.lanes.length; index += 1) {
|
|
2110
|
+
const lane = swimlane.lanes[index];
|
|
2111
|
+
const bounds = laneBounds[index];
|
|
2112
|
+
if (lane === void 0 || bounds === void 0) {
|
|
2113
|
+
continue;
|
|
2114
|
+
}
|
|
2115
|
+
const target = {
|
|
2116
|
+
x: left + headerHeight + padding,
|
|
2117
|
+
y: top + slotHeight * index + padding
|
|
2118
|
+
};
|
|
2119
|
+
moveLaneChildren(
|
|
2120
|
+
lane.children,
|
|
2121
|
+
nodeBoxes,
|
|
2122
|
+
locks,
|
|
2123
|
+
diagnostics,
|
|
2124
|
+
movedChildIds,
|
|
2125
|
+
{
|
|
2126
|
+
x: target.x - bounds.x,
|
|
2127
|
+
y: target.y - bounds.y
|
|
2128
|
+
}
|
|
2129
|
+
);
|
|
2130
|
+
}
|
|
2131
|
+
return {
|
|
2132
|
+
box: {
|
|
2133
|
+
x: left,
|
|
2134
|
+
y: top,
|
|
2135
|
+
width: slotWidth,
|
|
2136
|
+
height: slotHeight * swimlane.lanes.length
|
|
2137
|
+
},
|
|
2138
|
+
slotWidth,
|
|
2139
|
+
slotHeight
|
|
2140
|
+
};
|
|
2141
|
+
}
|
|
2142
|
+
function moveLaneChildren(childIds, nodeBoxes, locks, diagnostics, movedChildIds, offset) {
|
|
2143
|
+
for (const childId of childIds) {
|
|
2144
|
+
const box = nodeBoxes.get(childId);
|
|
2145
|
+
if (box === void 0) {
|
|
2146
|
+
continue;
|
|
2147
|
+
}
|
|
2148
|
+
if (locks.has(childId)) {
|
|
2149
|
+
diagnostics.push({
|
|
2150
|
+
severity: "warning",
|
|
2151
|
+
code: "constraints.locked-target-not-moved",
|
|
2152
|
+
message: `Locked child ${childId} was not moved into contract swimlane slot.`,
|
|
2153
|
+
path: ["swimlanes"],
|
|
2154
|
+
detail: { nodeId: childId }
|
|
2155
|
+
});
|
|
2156
|
+
continue;
|
|
2157
|
+
}
|
|
2158
|
+
if (offset.x !== 0 || offset.y !== 0) {
|
|
2159
|
+
movedChildIds.add(childId);
|
|
2160
|
+
}
|
|
2161
|
+
nodeBoxes.set(childId, {
|
|
2162
|
+
...box,
|
|
2163
|
+
x: box.x + offset.x,
|
|
2164
|
+
y: box.y + offset.y
|
|
2165
|
+
});
|
|
2166
|
+
}
|
|
2167
|
+
}
|
|
2168
|
+
function removeResolvedOverlapDiagnostics(diagnostics, nodeBoxes) {
|
|
2169
|
+
for (let index = diagnostics.length - 1; index >= 0; index -= 1) {
|
|
2170
|
+
const diagnostic = diagnostics[index];
|
|
2171
|
+
if (diagnostic?.code !== "constraints.overlap.unresolved") {
|
|
2172
|
+
continue;
|
|
2173
|
+
}
|
|
2174
|
+
const firstId = detailString(diagnostic, "firstId");
|
|
2175
|
+
const secondId = detailString(diagnostic, "secondId");
|
|
2176
|
+
const first = firstId === void 0 ? void 0 : nodeBoxes.get(firstId);
|
|
2177
|
+
const second = secondId === void 0 ? void 0 : nodeBoxes.get(secondId);
|
|
2178
|
+
if (first !== void 0 && second !== void 0 && !intersectsAabb(first, second)) {
|
|
2179
|
+
diagnostics.splice(index, 1);
|
|
2180
|
+
}
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
function reportSwimlaneConstraintInvalidations(constraints, nodeBoxes, movedChildIds) {
|
|
2184
|
+
const diagnostics = [];
|
|
2185
|
+
for (const constraint of constraints) {
|
|
2186
|
+
const invalidatedNodeIds = movedConstraintNodeIds(
|
|
2187
|
+
constraint,
|
|
2188
|
+
nodeBoxes,
|
|
2189
|
+
movedChildIds
|
|
2190
|
+
);
|
|
2191
|
+
if (invalidatedNodeIds.length === 0) {
|
|
2192
|
+
continue;
|
|
2193
|
+
}
|
|
2194
|
+
diagnostics.push({
|
|
2195
|
+
severity: "warning",
|
|
2196
|
+
code: "constraints.swimlane-contract.invalidated",
|
|
2197
|
+
message: `Contract swimlane placement moved node(s) after ${constraint.kind} constraint solving; final geometry no longer satisfies that constraint.`,
|
|
2198
|
+
path: ["swimlanes"],
|
|
2199
|
+
detail: {
|
|
2200
|
+
constraintKind: constraint.kind,
|
|
2201
|
+
...constraint.id === void 0 ? {} : { constraintId: constraint.id },
|
|
2202
|
+
nodeIds: invalidatedNodeIds
|
|
2203
|
+
}
|
|
2204
|
+
});
|
|
2205
|
+
}
|
|
2206
|
+
return diagnostics;
|
|
2207
|
+
}
|
|
2208
|
+
function movedConstraintNodeIds(constraint, nodeBoxes, movedChildIds) {
|
|
2209
|
+
switch (constraint.kind) {
|
|
2210
|
+
case "exact-position":
|
|
2211
|
+
return [];
|
|
2212
|
+
case "containment":
|
|
2213
|
+
return movedContainmentViolations(constraint, nodeBoxes, movedChildIds);
|
|
2214
|
+
case "relative-position":
|
|
2215
|
+
return movedRelativeViolations(constraint, nodeBoxes, movedChildIds);
|
|
2216
|
+
case "align":
|
|
2217
|
+
return movedAlignViolations(constraint, nodeBoxes, movedChildIds);
|
|
2218
|
+
case "distribute":
|
|
2219
|
+
return movedDistributeViolations(constraint, nodeBoxes, movedChildIds);
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
function movedContainmentViolations(constraint, nodeBoxes, movedChildIds) {
|
|
2223
|
+
const container = nodeBoxes.get(constraint.containerId);
|
|
2224
|
+
if (container === void 0) {
|
|
2225
|
+
return [];
|
|
2226
|
+
}
|
|
2227
|
+
const content = paddedContentBox(container, constraint.padding);
|
|
2228
|
+
return constraint.childIds.filter((childId) => {
|
|
2229
|
+
if (!movedChildIds.has(childId)) {
|
|
2230
|
+
return false;
|
|
2231
|
+
}
|
|
2232
|
+
const child = nodeBoxes.get(childId);
|
|
2233
|
+
return child !== void 0 && !boxInside(child, content);
|
|
2234
|
+
});
|
|
2235
|
+
}
|
|
2236
|
+
function movedRelativeViolations(constraint, nodeBoxes, movedChildIds) {
|
|
2237
|
+
if (!movedChildIds.has(constraint.sourceId) && !movedChildIds.has(constraint.referenceId)) {
|
|
2238
|
+
return [];
|
|
2239
|
+
}
|
|
2240
|
+
const source = nodeBoxes.get(constraint.sourceId);
|
|
2241
|
+
const reference = nodeBoxes.get(constraint.referenceId);
|
|
2242
|
+
if (source === void 0 || reference === void 0) {
|
|
2243
|
+
return [];
|
|
2244
|
+
}
|
|
2245
|
+
return sameBoxPosition(
|
|
2246
|
+
source,
|
|
2247
|
+
expectedRelativeBox(source, reference, constraint)
|
|
2248
|
+
) ? [] : [constraint.sourceId];
|
|
2249
|
+
}
|
|
2250
|
+
function movedAlignViolations(constraint, nodeBoxes, movedChildIds) {
|
|
2251
|
+
if (!constraint.targetIds.some((id) => movedChildIds.has(id))) {
|
|
2252
|
+
return [];
|
|
2253
|
+
}
|
|
2254
|
+
const targets = constraint.targetIds.map((id) => ({ id, box: nodeBoxes.get(id) })).filter(
|
|
2255
|
+
(target) => target.box !== void 0
|
|
2256
|
+
);
|
|
2257
|
+
const anchor = targets[0];
|
|
2258
|
+
if (anchor === void 0) {
|
|
2259
|
+
return [];
|
|
2260
|
+
}
|
|
2261
|
+
const expected = alignmentValue2(anchor.box, constraint.axis);
|
|
2262
|
+
return targets.filter(
|
|
2263
|
+
(target) => movedChildIds.has(target.id) && !sameNumber(alignmentValue2(target.box, constraint.axis), expected)
|
|
2264
|
+
).map((target) => target.id);
|
|
2265
|
+
}
|
|
2266
|
+
function movedDistributeViolations(constraint, nodeBoxes, movedChildIds) {
|
|
2267
|
+
if (!constraint.targetIds.some((id) => movedChildIds.has(id))) {
|
|
2268
|
+
return [];
|
|
2269
|
+
}
|
|
2270
|
+
const targets = constraint.targetIds.map((id) => ({ id, box: nodeBoxes.get(id) })).filter(
|
|
2271
|
+
(target) => target.box !== void 0
|
|
2272
|
+
).sort((a, b) => {
|
|
2273
|
+
const delta = constraint.axis === "horizontal" ? a.box.x - b.box.x : a.box.y - b.box.y;
|
|
2274
|
+
return delta === 0 ? a.id.localeCompare(b.id) : delta;
|
|
2275
|
+
});
|
|
2276
|
+
if (targets.length < 3) {
|
|
2277
|
+
return [];
|
|
2278
|
+
}
|
|
2279
|
+
const first = targets[0];
|
|
2280
|
+
const last = targets.at(-1);
|
|
2281
|
+
if (first === void 0 || last === void 0) {
|
|
2282
|
+
return [];
|
|
2283
|
+
}
|
|
2284
|
+
const expectedSpacing = constraint.spacing ?? (distributionStart2(last.box, constraint.axis) - distributionStart2(first.box, constraint.axis)) / (targets.length - 1);
|
|
2285
|
+
return targets.slice(1).filter((target, index) => {
|
|
2286
|
+
const previous = targets[index];
|
|
2287
|
+
if (previous === void 0 || !movedChildIds.has(target.id)) {
|
|
2288
|
+
return false;
|
|
2289
|
+
}
|
|
2290
|
+
return !sameNumber(
|
|
2291
|
+
distributionStart2(target.box, constraint.axis) - distributionStart2(previous.box, constraint.axis),
|
|
2292
|
+
expectedSpacing
|
|
2293
|
+
);
|
|
2294
|
+
}).map((target) => target.id);
|
|
2295
|
+
}
|
|
2296
|
+
function expectedRelativeBox(source, reference, constraint) {
|
|
2297
|
+
const offset = constraint.offset ?? { x: 0, y: 0 };
|
|
2298
|
+
switch (constraint.relation) {
|
|
2299
|
+
case "above":
|
|
2300
|
+
return {
|
|
2301
|
+
...source,
|
|
2302
|
+
x: reference.x + offset.x,
|
|
2303
|
+
y: reference.y - source.height + offset.y
|
|
2304
|
+
};
|
|
2305
|
+
case "right-of":
|
|
2306
|
+
return {
|
|
2307
|
+
...source,
|
|
2308
|
+
x: reference.x + reference.width + offset.x,
|
|
2309
|
+
y: reference.y + offset.y
|
|
2310
|
+
};
|
|
2311
|
+
case "below":
|
|
2312
|
+
return {
|
|
2313
|
+
...source,
|
|
2314
|
+
x: reference.x + offset.x,
|
|
2315
|
+
y: reference.y + reference.height + offset.y
|
|
2316
|
+
};
|
|
2317
|
+
case "left-of":
|
|
2318
|
+
return {
|
|
2319
|
+
...source,
|
|
2320
|
+
x: reference.x - source.width + offset.x,
|
|
2321
|
+
y: reference.y + offset.y
|
|
2322
|
+
};
|
|
2323
|
+
}
|
|
2324
|
+
}
|
|
2325
|
+
function paddedContentBox(container, padding) {
|
|
2326
|
+
const margin = padding ?? { top: 0, right: 0, bottom: 0, left: 0 };
|
|
2327
|
+
return {
|
|
2328
|
+
x: container.x + margin.left,
|
|
2329
|
+
y: container.y + margin.top,
|
|
2330
|
+
width: container.width - margin.left - margin.right,
|
|
2331
|
+
height: container.height - margin.top - margin.bottom
|
|
2332
|
+
};
|
|
2333
|
+
}
|
|
2334
|
+
function boxInside(child, container) {
|
|
2335
|
+
return child.x >= container.x && child.y >= container.y && child.x + child.width <= container.x + container.width && child.y + child.height <= container.y + container.height;
|
|
2336
|
+
}
|
|
2337
|
+
function sameBoxPosition(first, second) {
|
|
2338
|
+
return sameNumber(first.x, second.x) && sameNumber(first.y, second.y);
|
|
2339
|
+
}
|
|
2340
|
+
function sameNumber(first, second) {
|
|
2341
|
+
return Math.abs(first - second) < 1e-3;
|
|
2342
|
+
}
|
|
2343
|
+
function alignmentValue2(box, axis) {
|
|
2344
|
+
switch (axis) {
|
|
2345
|
+
case "x":
|
|
2346
|
+
case "left":
|
|
2347
|
+
return box.x;
|
|
2348
|
+
case "y":
|
|
2349
|
+
case "top":
|
|
2350
|
+
return box.y;
|
|
2351
|
+
case "center-x":
|
|
2352
|
+
return box.x + box.width / 2;
|
|
2353
|
+
case "center-y":
|
|
2354
|
+
return box.y + box.height / 2;
|
|
2355
|
+
case "right":
|
|
2356
|
+
return box.x + box.width;
|
|
2357
|
+
case "bottom":
|
|
2358
|
+
return box.y + box.height;
|
|
2359
|
+
}
|
|
2360
|
+
}
|
|
2361
|
+
function distributionStart2(box, axis) {
|
|
2362
|
+
return axis === "horizontal" ? box.x : box.y;
|
|
2363
|
+
}
|
|
2364
|
+
function detailString(diagnostic, key) {
|
|
2365
|
+
const value = diagnostic.detail?.[key];
|
|
2366
|
+
return typeof value === "string" ? value : void 0;
|
|
2367
|
+
}
|
|
2368
|
+
function reportSwimlaneOverlaps(nodeBoxes, locks, overlapSpacing) {
|
|
2369
|
+
const diagnostics = [];
|
|
2370
|
+
const ids = [...nodeBoxes.keys()].sort();
|
|
2371
|
+
for (const firstId of ids) {
|
|
2372
|
+
for (const secondId of ids) {
|
|
2373
|
+
if (firstId >= secondId) {
|
|
2374
|
+
continue;
|
|
2375
|
+
}
|
|
2376
|
+
const first = nodeBoxes.get(firstId);
|
|
2377
|
+
const second = nodeBoxes.get(secondId);
|
|
2378
|
+
if (first === void 0 || second === void 0) {
|
|
2379
|
+
continue;
|
|
2380
|
+
}
|
|
2381
|
+
if (!intersectsAabb(first, second)) {
|
|
2382
|
+
continue;
|
|
2383
|
+
}
|
|
2384
|
+
diagnostics.push({
|
|
2385
|
+
severity: "warning",
|
|
2386
|
+
code: "constraints.overlap.unresolved",
|
|
2387
|
+
message: `Boxes ${firstId} and ${secondId} still overlap after contract swimlane placement with configured spacing ${overlapSpacing}.`,
|
|
2388
|
+
path: ["swimlanes"],
|
|
2389
|
+
detail: {
|
|
2390
|
+
firstId,
|
|
2391
|
+
secondId,
|
|
2392
|
+
firstLocked: locks.has(firstId),
|
|
2393
|
+
secondLocked: locks.has(secondId)
|
|
2394
|
+
}
|
|
2395
|
+
});
|
|
2396
|
+
}
|
|
2397
|
+
}
|
|
2398
|
+
return diagnostics;
|
|
2399
|
+
}
|
|
1789
2400
|
function coordinateNodes(nodes, boxes, options, diagnostics) {
|
|
1790
2401
|
const coordinated = [];
|
|
1791
2402
|
for (const node of nodes) {
|
|
@@ -1900,16 +2511,70 @@ function portLabelBox(port) {
|
|
|
1900
2511
|
height
|
|
1901
2512
|
};
|
|
1902
2513
|
}
|
|
1903
|
-
function coordinateSwimlanes(swimlanes, nodeBoxes) {
|
|
1904
|
-
const titleSize = 28;
|
|
1905
|
-
const padding = 16;
|
|
2514
|
+
function coordinateSwimlanes(swimlanes, nodeBoxes, layouts) {
|
|
1906
2515
|
return swimlanes.map((swimlane) => {
|
|
1907
|
-
const
|
|
2516
|
+
const layout2 = swimlane.layout ?? "overlay";
|
|
2517
|
+
const headerHeight = swimlane.headerHeight ?? 28;
|
|
2518
|
+
const padding = swimlane.padding ?? 16;
|
|
2519
|
+
const contractLayout = layouts.get(swimlane.id);
|
|
2520
|
+
if (layout2 === "contract" && contractLayout !== void 0) {
|
|
2521
|
+
const lanes2 = swimlane.lanes.map((lane, index) => {
|
|
2522
|
+
const box = swimlane.orientation === "vertical" ? {
|
|
2523
|
+
x: contractLayout.box.x + contractLayout.slotWidth * index,
|
|
2524
|
+
y: contractLayout.box.y,
|
|
2525
|
+
width: contractLayout.slotWidth,
|
|
2526
|
+
height: contractLayout.box.height
|
|
2527
|
+
} : {
|
|
2528
|
+
x: contractLayout.box.x,
|
|
2529
|
+
y: contractLayout.box.y + contractLayout.slotHeight * index,
|
|
2530
|
+
width: contractLayout.box.width,
|
|
2531
|
+
height: contractLayout.slotHeight
|
|
2532
|
+
};
|
|
2533
|
+
const headerBox = swimlane.orientation === "vertical" ? {
|
|
2534
|
+
x: box.x,
|
|
2535
|
+
y: box.y,
|
|
2536
|
+
width: box.width,
|
|
2537
|
+
height: headerHeight
|
|
2538
|
+
} : {
|
|
2539
|
+
x: box.x,
|
|
2540
|
+
y: box.y,
|
|
2541
|
+
width: headerHeight,
|
|
2542
|
+
height: box.height
|
|
2543
|
+
};
|
|
2544
|
+
const contentBox2 = swimlane.orientation === "vertical" ? {
|
|
2545
|
+
x: box.x,
|
|
2546
|
+
y: box.y + headerHeight,
|
|
2547
|
+
width: box.width,
|
|
2548
|
+
height: Math.max(0, box.height - headerHeight)
|
|
2549
|
+
} : {
|
|
2550
|
+
x: box.x + headerHeight,
|
|
2551
|
+
y: box.y,
|
|
2552
|
+
width: Math.max(0, box.width - headerHeight),
|
|
2553
|
+
height: box.height
|
|
2554
|
+
};
|
|
2555
|
+
return {
|
|
2556
|
+
...lane,
|
|
2557
|
+
box,
|
|
2558
|
+
headerBox,
|
|
2559
|
+
contentBox: contentBox2
|
|
2560
|
+
};
|
|
2561
|
+
});
|
|
2562
|
+
return {
|
|
2563
|
+
...swimlane,
|
|
2564
|
+
lanes: lanes2,
|
|
2565
|
+
box: contractLayout.box,
|
|
2566
|
+
...headerHeight === void 0 ? {} : { headerHeight },
|
|
2567
|
+
...padding === void 0 ? {} : { padding }
|
|
2568
|
+
};
|
|
2569
|
+
}
|
|
2570
|
+
const laneContentBoxes = swimlane.lanes.map((lane) => {
|
|
1908
2571
|
const childBoxes = lane.children.map((child) => nodeBoxes.get(child)).filter((box) => box !== void 0);
|
|
1909
|
-
return childBoxes.length === 0 ?
|
|
2572
|
+
return childBoxes.length === 0 ? void 0 : unionBoxes(childBoxes);
|
|
1910
2573
|
});
|
|
1911
|
-
const laneUnion =
|
|
1912
|
-
|
|
2574
|
+
const laneUnion = laneContentBoxes.filter((box) => box !== void 0).length === 0 ? { x: 0, y: 0, width: 120, height: 80 } : unionBoxes(
|
|
2575
|
+
laneContentBoxes.filter((box) => box !== void 0)
|
|
2576
|
+
);
|
|
2577
|
+
const outer = expand(laneUnion, padding, headerHeight);
|
|
1913
2578
|
const laneCount = Math.max(1, swimlane.lanes.length);
|
|
1914
2579
|
const lanes = swimlane.lanes.map((lane, index) => {
|
|
1915
2580
|
const box = swimlane.orientation === "vertical" ? {
|
|
@@ -1923,9 +2588,42 @@ function coordinateSwimlanes(swimlanes, nodeBoxes) {
|
|
|
1923
2588
|
width: outer.width,
|
|
1924
2589
|
height: outer.height / laneCount
|
|
1925
2590
|
};
|
|
1926
|
-
|
|
2591
|
+
const headerBox = layout2 === "contract" ? swimlane.orientation === "vertical" ? {
|
|
2592
|
+
x: box.x,
|
|
2593
|
+
y: box.y,
|
|
2594
|
+
width: box.width,
|
|
2595
|
+
height: headerHeight
|
|
2596
|
+
} : {
|
|
2597
|
+
x: box.x,
|
|
2598
|
+
y: box.y,
|
|
2599
|
+
width: headerHeight,
|
|
2600
|
+
height: box.height
|
|
2601
|
+
} : void 0;
|
|
2602
|
+
const contentBox2 = layout2 === "contract" ? swimlane.orientation === "vertical" ? {
|
|
2603
|
+
x: box.x,
|
|
2604
|
+
y: box.y + headerHeight,
|
|
2605
|
+
width: box.width,
|
|
2606
|
+
height: Math.max(0, box.height - headerHeight)
|
|
2607
|
+
} : {
|
|
2608
|
+
x: box.x + headerHeight,
|
|
2609
|
+
y: box.y,
|
|
2610
|
+
width: Math.max(0, box.width - headerHeight),
|
|
2611
|
+
height: box.height
|
|
2612
|
+
} : void 0;
|
|
2613
|
+
return {
|
|
2614
|
+
...lane,
|
|
2615
|
+
box,
|
|
2616
|
+
...headerBox === void 0 ? {} : { headerBox },
|
|
2617
|
+
...contentBox2 === void 0 ? {} : { contentBox: contentBox2 }
|
|
2618
|
+
};
|
|
1927
2619
|
});
|
|
1928
|
-
return {
|
|
2620
|
+
return {
|
|
2621
|
+
...swimlane,
|
|
2622
|
+
lanes,
|
|
2623
|
+
box: outer,
|
|
2624
|
+
...headerHeight === void 0 ? {} : { headerHeight },
|
|
2625
|
+
...padding === void 0 ? {} : { padding }
|
|
2626
|
+
};
|
|
1929
2627
|
});
|
|
1930
2628
|
}
|
|
1931
2629
|
function coordinateFrame(frame, contentBounds) {
|
|
@@ -2464,6 +3162,7 @@ function normalizeDiagramDsl(dslValue, options = {}) {
|
|
|
2464
3162
|
const measurer = options.textMeasurer ?? createDefaultTextMeasurer();
|
|
2465
3163
|
const routeKind = dsl.routing?.kind ?? "orthogonal";
|
|
2466
3164
|
const portShifting = normalizePortShifting(dsl.routing?.portShifting);
|
|
3165
|
+
const primaryReadingDirection = dsl.layout?.primaryReadingDirection;
|
|
2467
3166
|
const diagram = {
|
|
2468
3167
|
id: options.id ?? dsl.id ?? "diagram",
|
|
2469
3168
|
...dsl.title === void 0 ? {} : { title: dsl.title },
|
|
@@ -2477,6 +3176,7 @@ function normalizeDiagramDsl(dslValue, options = {}) {
|
|
|
2477
3176
|
...dsl.frame === void 0 ? {} : { frame: normalizeFrame(dsl.frame) },
|
|
2478
3177
|
metadata: {
|
|
2479
3178
|
routeKind,
|
|
3179
|
+
...primaryReadingDirection === void 0 ? {} : { primaryReadingDirection },
|
|
2480
3180
|
...portShifting === void 0 ? {} : { portShifting }
|
|
2481
3181
|
}
|
|
2482
3182
|
};
|
|
@@ -2647,14 +3347,17 @@ function formatCompartmentEntry(value) {
|
|
|
2647
3347
|
return `${entry[0]}: ${entry[1]}`;
|
|
2648
3348
|
}
|
|
2649
3349
|
function normalizeSwimlanes(dsl) {
|
|
2650
|
-
return Object.keys(dsl.swimlanes ?? {}).
|
|
3350
|
+
return Object.keys(dsl.swimlanes ?? {}).map((id) => {
|
|
2651
3351
|
const swimlane = dsl.swimlanes?.[id];
|
|
2652
3352
|
const label = toLabel(swimlane?.label);
|
|
2653
3353
|
return {
|
|
2654
3354
|
id,
|
|
2655
3355
|
...label === void 0 ? {} : { label },
|
|
2656
3356
|
orientation: swimlane?.orientation ?? "vertical",
|
|
2657
|
-
|
|
3357
|
+
layout: swimlane?.layout ?? "overlay",
|
|
3358
|
+
...swimlane?.headerHeight === void 0 ? {} : { headerHeight: swimlane.headerHeight },
|
|
3359
|
+
...swimlane?.padding === void 0 ? {} : { padding: swimlane.padding },
|
|
3360
|
+
lanes: Object.keys(swimlane?.lanes ?? {}).map((laneId) => {
|
|
2658
3361
|
const lane = swimlane?.lanes[laneId];
|
|
2659
3362
|
const laneLabel = toLabel(lane?.label);
|
|
2660
3363
|
return {
|
|
@@ -2732,11 +3435,6 @@ function validateReferences(dsl) {
|
|
|
2732
3435
|
const diagnostics = [];
|
|
2733
3436
|
const nodeIds = new Set(Object.keys(dsl.nodes));
|
|
2734
3437
|
const groupIds = new Set(Object.keys(dsl.groups ?? {}));
|
|
2735
|
-
const swimlaneLaneIds = new Set(
|
|
2736
|
-
Object.entries(dsl.swimlanes ?? {}).flatMap(
|
|
2737
|
-
([swimlaneId, swimlane]) => Object.keys(swimlane.lanes).map((laneId) => `${swimlaneId}.${laneId}`)
|
|
2738
|
-
)
|
|
2739
|
-
);
|
|
2740
3438
|
(dsl.edges ?? []).forEach((edge, index) => {
|
|
2741
3439
|
if (typeof edge === "string") {
|
|
2742
3440
|
return;
|
|
@@ -2844,10 +3542,12 @@ function validateReferences(dsl) {
|
|
|
2844
3542
|
break;
|
|
2845
3543
|
case "containment": {
|
|
2846
3544
|
const container = constraint.containerId ?? constraint.container;
|
|
2847
|
-
if (container !== void 0
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
3545
|
+
if (container !== void 0) {
|
|
3546
|
+
if (!nodeIds.has(container)) {
|
|
3547
|
+
diagnostics.push(
|
|
3548
|
+
referenceMissing(["constraints", index, "container"], container)
|
|
3549
|
+
);
|
|
3550
|
+
}
|
|
2851
3551
|
}
|
|
2852
3552
|
(constraint.childIds ?? constraint.children ?? []).forEach(
|
|
2853
3553
|
(child, childIndex) => {
|
|
@@ -2965,6 +3665,10 @@ var routeKindSchema = zod.z.enum(["orthogonal", "straight"]);
|
|
|
2965
3665
|
var outputFormatSchema = zod.z.enum(["svg", "excalidraw"]);
|
|
2966
3666
|
var edgeStrokeStyleSchema = zod.z.enum(["solid", "dashed"]);
|
|
2967
3667
|
var edgeArrowheadSchema = zod.z.enum(["triangle", "hollowTriangle"]);
|
|
3668
|
+
var primaryReadingDirectionSchema = zod.z.enum([
|
|
3669
|
+
"top_to_bottom",
|
|
3670
|
+
"top-to-bottom"
|
|
3671
|
+
]);
|
|
2968
3672
|
var nodeShapeSchema = zod.z.enum([
|
|
2969
3673
|
"rectangle",
|
|
2970
3674
|
"rounded-rectangle",
|
|
@@ -2975,6 +3679,7 @@ var nodeShapeSchema = zod.z.enum([
|
|
|
2975
3679
|
"cylinder"
|
|
2976
3680
|
]);
|
|
2977
3681
|
var finiteNumberSchema = zod.z.number().finite();
|
|
3682
|
+
var nonNegativeNumberSchema = finiteNumberSchema.min(0);
|
|
2978
3683
|
var pointSchema = zod.z.object({
|
|
2979
3684
|
x: finiteNumberSchema,
|
|
2980
3685
|
y: finiteNumberSchema
|
|
@@ -3061,6 +3766,9 @@ var groupSchema = zod.z.object({
|
|
|
3061
3766
|
var swimlaneSchema = zod.z.object({
|
|
3062
3767
|
label: labelSchema.optional(),
|
|
3063
3768
|
orientation: zod.z.enum(["vertical", "horizontal"]).optional(),
|
|
3769
|
+
layout: zod.z.enum(["overlay", "contract"]).optional(),
|
|
3770
|
+
headerHeight: nonNegativeNumberSchema.optional(),
|
|
3771
|
+
padding: nonNegativeNumberSchema.optional(),
|
|
3064
3772
|
lanes: zod.z.record(
|
|
3065
3773
|
zod.z.string(),
|
|
3066
3774
|
zod.z.object({
|
|
@@ -3126,7 +3834,8 @@ var diagramDslSchema = zod.z.object({
|
|
|
3126
3834
|
title: zod.z.string().optional(),
|
|
3127
3835
|
direction: directionSchema.optional(),
|
|
3128
3836
|
layout: zod.z.object({
|
|
3129
|
-
direction: directionSchema.optional()
|
|
3837
|
+
direction: directionSchema.optional(),
|
|
3838
|
+
primaryReadingDirection: primaryReadingDirectionSchema.optional()
|
|
3130
3839
|
}).optional(),
|
|
3131
3840
|
routing: zod.z.object({
|
|
3132
3841
|
kind: routeKindSchema.optional(),
|