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