@crazyhappyone/auto-graph 0.0.1 → 0.0.21
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/README.md +2 -2
- package/README.zh-CN.md +2 -2
- package/dist/cli/index.cjs +907 -69
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +906 -69
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +846 -76
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +87 -1
- package/dist/index.d.ts +87 -1
- package/dist/index.js +844 -77
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/cli/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { CommanderError, Command } from 'commander';
|
|
3
3
|
import { Graph, layout } from '@dagrejs/dagre';
|
|
4
|
+
import { createRequire } from 'module';
|
|
5
|
+
import { prepareWithSegments, layoutWithLines, measureNaturalWidth } from '@chenglou/pretext';
|
|
4
6
|
import { Buffer as Buffer$1 } from 'buffer';
|
|
5
7
|
import { parseDocument } from 'yaml';
|
|
6
8
|
import { z } from 'zod';
|
|
@@ -194,11 +196,12 @@ function renderArrow(edge) {
|
|
|
194
196
|
height: box.height
|
|
195
197
|
}),
|
|
196
198
|
backgroundColor: "transparent",
|
|
199
|
+
strokeStyle: edge.style ?? "solid",
|
|
197
200
|
points: relativePoints,
|
|
198
201
|
startBinding: { elementId: `node:${edge.source.nodeId}`, focus: 0, gap: 0 },
|
|
199
202
|
endBinding: { elementId: `node:${edge.target.nodeId}`, focus: 0, gap: 0 },
|
|
200
203
|
startArrowhead: null,
|
|
201
|
-
endArrowhead:
|
|
204
|
+
endArrowhead: mapArrowhead(edge.arrowhead)
|
|
202
205
|
};
|
|
203
206
|
}
|
|
204
207
|
function renderText(id, label, box, containerId, groupIds) {
|
|
@@ -276,6 +279,16 @@ function mapShape(shape) {
|
|
|
276
279
|
return "cylinder";
|
|
277
280
|
}
|
|
278
281
|
}
|
|
282
|
+
function mapArrowhead(arrowhead) {
|
|
283
|
+
switch (arrowhead) {
|
|
284
|
+
case void 0:
|
|
285
|
+
return "arrow";
|
|
286
|
+
case "triangle":
|
|
287
|
+
return "triangle";
|
|
288
|
+
case "hollowTriangle":
|
|
289
|
+
return "triangle_outline";
|
|
290
|
+
}
|
|
291
|
+
}
|
|
279
292
|
function createGroupMembership(groups) {
|
|
280
293
|
const membership = /* @__PURE__ */ new Map();
|
|
281
294
|
for (const group of groups) {
|
|
@@ -342,19 +355,28 @@ function exportSvg(diagram, options = {}) {
|
|
|
342
355
|
`<svg xmlns="http://www.w3.org/2000/svg" role="img" viewBox="${formatBoxViewBox(diagram.bounds)}">`,
|
|
343
356
|
...title === void 0 ? [] : [` <title>${escapeXml(title)}</title>`],
|
|
344
357
|
` <rect class="background" x="${formatNumber(diagram.bounds.x)}" y="${formatNumber(diagram.bounds.y)}" width="${formatNumber(diagram.bounds.width)}" height="${formatNumber(diagram.bounds.height)}" fill="#ffffff"/>`,
|
|
358
|
+
...diagram.frame === void 0 ? [] : [indent(renderFrame(diagram.frame))],
|
|
359
|
+
...(diagram.swimlanes ?? []).flatMap(
|
|
360
|
+
(swimlane) => renderSwimlane(swimlane)
|
|
361
|
+
),
|
|
345
362
|
...diagram.groups.map((group) => indent(renderGroup2(group))),
|
|
346
363
|
...diagram.edges.flatMap((edge) => {
|
|
347
|
-
const path = renderEdgePath(edge
|
|
364
|
+
const path = renderEdgePath(edge);
|
|
348
365
|
if (path === void 0) {
|
|
349
366
|
return [];
|
|
350
367
|
}
|
|
351
|
-
return [indent(path), indent(renderArrowhead(edge
|
|
368
|
+
return [indent(path), indent(renderArrowhead(edge))];
|
|
352
369
|
}),
|
|
353
370
|
...diagram.nodes.map((node) => indent(renderNode2(node))),
|
|
371
|
+
...diagram.nodes.flatMap((node) => renderCompartments(node)),
|
|
372
|
+
...diagram.nodes.flatMap((node) => renderPorts(node)),
|
|
354
373
|
...diagram.groups.flatMap(
|
|
355
374
|
(group) => renderLabel(group.label, group.box, group)
|
|
356
375
|
),
|
|
357
|
-
...diagram.nodes.flatMap(
|
|
376
|
+
...diagram.nodes.flatMap(
|
|
377
|
+
(node) => node.compartments === void 0 ? renderLabel(node.label, node.box, node) : []
|
|
378
|
+
),
|
|
379
|
+
...diagram.edges.flatMap((edge) => renderEdgeLabel(edge)),
|
|
358
380
|
"</svg>"
|
|
359
381
|
];
|
|
360
382
|
return `${lines.join("\n")}
|
|
@@ -364,7 +386,9 @@ function renderGroup2(group) {
|
|
|
364
386
|
return `<rect class="group" data-id="${escapeAttribute(group.id)}" x="${formatNumber(group.box.x)}" y="${formatNumber(group.box.y)}" width="${formatNumber(group.box.width)}" height="${formatNumber(group.box.height)}" fill="${GROUP_FILL}" stroke="${STROKE}" stroke-dasharray="6 4"/>`;
|
|
365
387
|
}
|
|
366
388
|
function renderNode2(node) {
|
|
367
|
-
const
|
|
389
|
+
const fill = node.style?.fill ?? NODE_FILL;
|
|
390
|
+
const stroke = node.style?.stroke ?? STROKE;
|
|
391
|
+
const common = `class="node node-${node.shape}" data-id="${escapeAttribute(node.id)}" fill="${escapeAttribute(fill)}" stroke="${escapeAttribute(stroke)}"`;
|
|
368
392
|
switch (node.shape) {
|
|
369
393
|
case "rectangle":
|
|
370
394
|
return renderRect(node.box, common);
|
|
@@ -380,16 +404,111 @@ function renderNode2(node) {
|
|
|
380
404
|
return `<path ${common} d="${formatCylinderPath(node.box)}"/>`;
|
|
381
405
|
}
|
|
382
406
|
}
|
|
407
|
+
function renderFrame(frame) {
|
|
408
|
+
const stroke = frame.style?.stroke ?? "#6b7280";
|
|
409
|
+
const fill = frame.style?.fill ?? "transparent";
|
|
410
|
+
return [
|
|
411
|
+
`<g class="sysml-frame" data-kind="${escapeAttribute(frame.kind)}">`,
|
|
412
|
+
` <rect class="sysml-frame-border" x="${formatNumber(frame.box.x)}" y="${formatNumber(frame.box.y)}" width="${formatNumber(frame.box.width)}" height="${formatNumber(frame.box.height)}" fill="${escapeAttribute(fill)}" stroke="${escapeAttribute(stroke)}"/>`,
|
|
413
|
+
` <path class="sysml-title-tab" d="M ${formatNumber(frame.titleBox.x)} ${formatNumber(frame.titleBox.y + frame.titleBox.height)} L ${formatNumber(frame.titleBox.x)} ${formatNumber(frame.titleBox.y)} L ${formatNumber(frame.titleBox.x + frame.titleBox.width - 16)} ${formatNumber(frame.titleBox.y)} L ${formatNumber(frame.titleBox.x + frame.titleBox.width)} ${formatNumber(frame.titleBox.y + frame.titleBox.height)} Z" fill="#f3f4f6" stroke="${escapeAttribute(stroke)}"/>`,
|
|
414
|
+
` <text class="sysml-title-tab-label" x="${formatNumber(frame.titleBox.x + 8)}" y="${formatNumber(frame.titleBox.y + frame.titleBox.height / 2)}" dominant-baseline="middle" font-family="${FONT_FAMILY}" font-size="12" fill="#111827">${escapeXml(frame.titleTab)}</text>`,
|
|
415
|
+
"</g>"
|
|
416
|
+
].join("\n");
|
|
417
|
+
}
|
|
418
|
+
function renderSwimlane(swimlane) {
|
|
419
|
+
if (swimlane.box === void 0) {
|
|
420
|
+
return [];
|
|
421
|
+
}
|
|
422
|
+
const lines = [
|
|
423
|
+
` <g class="swimlane" data-id="${escapeAttribute(swimlane.id)}">`,
|
|
424
|
+
` <rect class="swimlane-frame" x="${formatNumber(swimlane.box.x)}" y="${formatNumber(swimlane.box.y)}" width="${formatNumber(swimlane.box.width)}" height="${formatNumber(swimlane.box.height)}" fill="#ffffff" stroke="${STROKE}"/>`
|
|
425
|
+
];
|
|
426
|
+
for (const lane of swimlane.lanes) {
|
|
427
|
+
if (lane.box === void 0) {
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
430
|
+
lines.push(
|
|
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
|
+
);
|
|
433
|
+
if (lane.label?.text !== void 0) {
|
|
434
|
+
lines.push(
|
|
435
|
+
` <text class="swimlane-label" x="${formatNumber(lane.box.x + lane.box.width / 2)}" y="${formatNumber(lane.box.y + 16)}" text-anchor="middle" font-family="${FONT_FAMILY}" font-size="12" fill="#111827">${escapeXml(lane.label.text)}</text>`
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
lines.push(" </g>");
|
|
440
|
+
return lines;
|
|
441
|
+
}
|
|
442
|
+
function renderPorts(node) {
|
|
443
|
+
return (node.ports ?? []).flatMap((port) => [
|
|
444
|
+
` <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)}"/>`,
|
|
445
|
+
...port.label?.text === void 0 ? [] : [
|
|
446
|
+
` <text class="port-label" data-for="${escapeAttribute(`${node.id}.${port.id}`)}" x="${formatNumber(portLabelX(port.anchor.x, port.side))}" y="${formatNumber(port.anchor.y - 8)}" text-anchor="${port.side === "left" ? "end" : "start"}" font-family="${FONT_FAMILY}" font-size="10" fill="#111827">${escapeXml(port.label.text)}</text>`
|
|
447
|
+
]
|
|
448
|
+
]);
|
|
449
|
+
}
|
|
450
|
+
function renderCompartments(node) {
|
|
451
|
+
const compartments2 = node.compartments;
|
|
452
|
+
if (compartments2 === void 0) {
|
|
453
|
+
return [];
|
|
454
|
+
}
|
|
455
|
+
const rows = [
|
|
456
|
+
...compartments2.stereotype === void 0 ? [] : [{ className: "stereotype", text: compartments2.stereotype }],
|
|
457
|
+
{
|
|
458
|
+
className: "name",
|
|
459
|
+
text: compartments2.name ?? node.label?.text ?? node.id
|
|
460
|
+
},
|
|
461
|
+
...(compartments2.properties ?? []).map((text) => ({
|
|
462
|
+
className: "properties",
|
|
463
|
+
text
|
|
464
|
+
})),
|
|
465
|
+
...(compartments2.constraints ?? []).map((text) => ({
|
|
466
|
+
className: "constraints",
|
|
467
|
+
text
|
|
468
|
+
}))
|
|
469
|
+
];
|
|
470
|
+
const lineHeight = 16;
|
|
471
|
+
const lines = [
|
|
472
|
+
` <g class="compartment" data-for="${escapeAttribute(node.id)}">`
|
|
473
|
+
];
|
|
474
|
+
for (let index = 0; index < rows.length; index += 1) {
|
|
475
|
+
const row = rows[index];
|
|
476
|
+
if (row === void 0) {
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
const y = node.box.y + 18 + index * lineHeight;
|
|
480
|
+
if (index > 1) {
|
|
481
|
+
lines.push(
|
|
482
|
+
` <line class="compartment-separator" x1="${formatNumber(node.box.x)}" y1="${formatNumber(y - 12)}" x2="${formatNumber(node.box.x + node.box.width)}" y2="${formatNumber(y - 12)}" stroke="${STROKE}"/>`
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
lines.push(
|
|
486
|
+
` <text class="compartment-${row.className}" x="${formatNumber(node.box.x + node.box.width / 2)}" y="${formatNumber(y)}" text-anchor="middle" font-family="${FONT_FAMILY}" font-size="11" fill="#111827">${escapeXml(row.text)}</text>`
|
|
487
|
+
);
|
|
488
|
+
}
|
|
489
|
+
lines.push(" </g>");
|
|
490
|
+
return lines;
|
|
491
|
+
}
|
|
492
|
+
function portLabelX(x, side) {
|
|
493
|
+
if (side === "left") {
|
|
494
|
+
return x - 8;
|
|
495
|
+
}
|
|
496
|
+
if (side === "right") {
|
|
497
|
+
return x + 8;
|
|
498
|
+
}
|
|
499
|
+
return x + 8;
|
|
500
|
+
}
|
|
383
501
|
function renderRect(box, attributes) {
|
|
384
502
|
return `<rect ${attributes} x="${formatNumber(box.x)}" y="${formatNumber(box.y)}" width="${formatNumber(box.width)}" height="${formatNumber(box.height)}"/>`;
|
|
385
503
|
}
|
|
386
504
|
function renderLabel(label, box, item) {
|
|
387
505
|
const labelLayout = item.labelLayout;
|
|
388
506
|
if (labelLayout?.lines !== void 0 && labelLayout.lines.length > 0) {
|
|
507
|
+
const offset = { x: box.x, y: box.y };
|
|
389
508
|
return [
|
|
390
509
|
` <text class="label" data-for="${escapeAttribute(item.id)}" font-family="${FONT_FAMILY}" font-size="${formatNumber(labelLayout.font.fontSize)}" fill="#111827">`,
|
|
391
510
|
...labelLayout.lines.map(
|
|
392
|
-
(line) => ` <tspan x="${formatNumber(line.box.x)}" y="${formatNumber(line.baselineY)}">${escapeXml(line.text)}</tspan>`
|
|
511
|
+
(line) => ` <tspan x="${formatNumber(offset.x + line.box.x)}" y="${formatNumber(offset.y + line.baselineY)}">${escapeXml(line.text)}</tspan>`
|
|
393
512
|
),
|
|
394
513
|
" </text>"
|
|
395
514
|
];
|
|
@@ -401,15 +520,88 @@ function renderLabel(label, box, item) {
|
|
|
401
520
|
` <text class="label" data-for="${escapeAttribute(item.id)}" x="${formatNumber(box.x + box.width / 2)}" y="${formatNumber(box.y + box.height / 2)}" text-anchor="middle" dominant-baseline="middle" font-family="${FONT_FAMILY}" font-size="14" fill="#111827">${escapeXml(label.text)}</text>`
|
|
402
521
|
];
|
|
403
522
|
}
|
|
404
|
-
function renderEdgePath(
|
|
405
|
-
if (points.length < 2) {
|
|
523
|
+
function renderEdgePath(edge) {
|
|
524
|
+
if (edge.points.length < 2) {
|
|
525
|
+
return void 0;
|
|
526
|
+
}
|
|
527
|
+
const dash = edge.style === "dashed" ? ' stroke-dasharray="6 4"' : "";
|
|
528
|
+
return `<path class="edge" data-id="${escapeAttribute(edge.id)}" d="${formatPath(pathPointsBeforeArrowhead(edge.points))}" fill="none" stroke="${EDGE_STROKE}" stroke-width="1.5"${dash}/>`;
|
|
529
|
+
}
|
|
530
|
+
function renderEdgeLabel(edge) {
|
|
531
|
+
if (edge.label?.text === void 0 || edge.points.length < 2) {
|
|
532
|
+
return [];
|
|
533
|
+
}
|
|
534
|
+
const placement = labelPlacementOnPolyline(edge.points);
|
|
535
|
+
if (placement === void 0) {
|
|
536
|
+
return [];
|
|
537
|
+
}
|
|
538
|
+
return [
|
|
539
|
+
` <text class="edge-label" data-for="${escapeAttribute(edge.id)}" x="${formatNumber(placement.x)}" y="${formatNumber(placement.y)}" text-anchor="middle" dominant-baseline="middle" font-family="${FONT_FAMILY}" font-size="12" fill="#111827">${escapeXml(edge.label.text)}</text>`
|
|
540
|
+
];
|
|
541
|
+
}
|
|
542
|
+
function renderArrowhead(edge) {
|
|
543
|
+
const arrowhead = computeArrowhead(edge.points);
|
|
544
|
+
const fill = edge.arrowhead === "hollowTriangle" ? "none" : EDGE_STROKE;
|
|
545
|
+
return `<polygon class="edge-arrowhead" data-edge="${escapeAttribute(edge.id)}" points="${formatPoints([arrowhead.tip, arrowhead.left, arrowhead.right])}" fill="${fill}" stroke="${EDGE_STROKE}"/>`;
|
|
546
|
+
}
|
|
547
|
+
function labelPlacementOnPolyline(points) {
|
|
548
|
+
const segments = nonZeroSegments(points);
|
|
549
|
+
const totalLength = segments.reduce(
|
|
550
|
+
(sum, segment) => sum + segment.length,
|
|
551
|
+
0
|
|
552
|
+
);
|
|
553
|
+
if (totalLength <= 0) {
|
|
406
554
|
return void 0;
|
|
407
555
|
}
|
|
408
|
-
|
|
556
|
+
let remaining = totalLength / 2;
|
|
557
|
+
for (const segment of segments) {
|
|
558
|
+
if (remaining <= segment.length) {
|
|
559
|
+
const ratio = remaining / segment.length;
|
|
560
|
+
const x = segment.start.x + (segment.end.x - segment.start.x) * ratio;
|
|
561
|
+
const y = segment.start.y + (segment.end.y - segment.start.y) * ratio;
|
|
562
|
+
const offset2 = labelOffset(segment);
|
|
563
|
+
return { x: x + offset2.x, y: y + offset2.y };
|
|
564
|
+
}
|
|
565
|
+
remaining -= segment.length;
|
|
566
|
+
}
|
|
567
|
+
const last = segments.at(-1);
|
|
568
|
+
if (last === void 0) {
|
|
569
|
+
return void 0;
|
|
570
|
+
}
|
|
571
|
+
const offset = labelOffset(last);
|
|
572
|
+
return { x: last.end.x + offset.x, y: last.end.y + offset.y };
|
|
573
|
+
}
|
|
574
|
+
function nonZeroSegments(points) {
|
|
575
|
+
const segments = [];
|
|
576
|
+
for (let index = 0; index < points.length - 1; index += 1) {
|
|
577
|
+
const start = points[index];
|
|
578
|
+
const end = points[index + 1];
|
|
579
|
+
if (start === void 0 || end === void 0) {
|
|
580
|
+
continue;
|
|
581
|
+
}
|
|
582
|
+
const length = Math.hypot(end.x - start.x, end.y - start.y);
|
|
583
|
+
if (length > 0) {
|
|
584
|
+
segments.push({ start, end, length });
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
return segments;
|
|
409
588
|
}
|
|
410
|
-
function
|
|
589
|
+
function labelOffset(segment) {
|
|
590
|
+
const offset = 10;
|
|
591
|
+
const dx = segment.end.x - segment.start.x;
|
|
592
|
+
const dy = segment.end.y - segment.start.y;
|
|
593
|
+
return {
|
|
594
|
+
x: -dy / segment.length * offset,
|
|
595
|
+
y: dx / segment.length * offset
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
function pathPointsBeforeArrowhead(points) {
|
|
411
599
|
const arrowhead = computeArrowhead(points);
|
|
412
|
-
|
|
600
|
+
const base = {
|
|
601
|
+
x: (arrowhead.left.x + arrowhead.right.x) / 2,
|
|
602
|
+
y: (arrowhead.left.y + arrowhead.right.y) / 2
|
|
603
|
+
};
|
|
604
|
+
return [...points.slice(0, -1), base];
|
|
413
605
|
}
|
|
414
606
|
function shapePoints(shape, box) {
|
|
415
607
|
const left = box.x;
|
|
@@ -1294,20 +1486,33 @@ function isValidDimension(value) {
|
|
|
1294
1486
|
// src/routing/routes.ts
|
|
1295
1487
|
function routeEdge(input) {
|
|
1296
1488
|
const diagnostics = [];
|
|
1489
|
+
const defaultAnchors = defaultAnchorsForGeometry(
|
|
1490
|
+
input.source.box,
|
|
1491
|
+
input.target.box,
|
|
1492
|
+
input.direction
|
|
1493
|
+
);
|
|
1297
1494
|
const source = getEdgePort(
|
|
1298
1495
|
input.source,
|
|
1299
1496
|
input.target.center,
|
|
1300
|
-
input.sourceAnchor
|
|
1497
|
+
input.sourceAnchor ?? defaultAnchors.sourceAnchor
|
|
1301
1498
|
);
|
|
1302
1499
|
const target = getEdgePort(
|
|
1303
1500
|
input.target,
|
|
1304
1501
|
input.source.center,
|
|
1305
|
-
input.targetAnchor
|
|
1502
|
+
input.targetAnchor ?? defaultAnchors.targetAnchor
|
|
1306
1503
|
);
|
|
1307
1504
|
if ((input.kind ?? "orthogonal") === "straight") {
|
|
1308
1505
|
return { points: simplifyRoute([source, target]), diagnostics };
|
|
1309
1506
|
}
|
|
1310
1507
|
const candidates = orthogonalCandidates(source, target, input.direction);
|
|
1508
|
+
candidates.push(
|
|
1509
|
+
...expandedObstacleCandidates(
|
|
1510
|
+
source,
|
|
1511
|
+
target,
|
|
1512
|
+
input.direction,
|
|
1513
|
+
input.obstacles ?? []
|
|
1514
|
+
)
|
|
1515
|
+
);
|
|
1311
1516
|
for (const candidate of candidates) {
|
|
1312
1517
|
if (!routeIntersectsObstacles(candidate, input.obstacles ?? [])) {
|
|
1313
1518
|
return { points: simplifyRoute(candidate), diagnostics };
|
|
@@ -1346,27 +1551,113 @@ function simplifyRoute(points) {
|
|
|
1346
1551
|
function orthogonalCandidates(source, target, direction) {
|
|
1347
1552
|
const midpointX = (source.x + target.x) / 2;
|
|
1348
1553
|
const midpointY = (source.y + target.y) / 2;
|
|
1349
|
-
const candidates = [
|
|
1350
|
-
[source, { x: target.x, y: source.y }, target],
|
|
1351
|
-
[source, { x: source.x, y: target.y }, target]
|
|
1352
|
-
];
|
|
1554
|
+
const candidates = [];
|
|
1353
1555
|
if (direction === "TB" || direction === "BT") {
|
|
1354
1556
|
candidates.push([
|
|
1355
1557
|
source,
|
|
1356
|
-
{ x:
|
|
1357
|
-
{ x:
|
|
1558
|
+
{ x: source.x, y: midpointY },
|
|
1559
|
+
{ x: target.x, y: midpointY },
|
|
1358
1560
|
target
|
|
1359
1561
|
]);
|
|
1360
1562
|
} else {
|
|
1361
1563
|
candidates.push([
|
|
1362
1564
|
source,
|
|
1363
|
-
{ x:
|
|
1364
|
-
{ x:
|
|
1565
|
+
{ x: midpointX, y: source.y },
|
|
1566
|
+
{ x: midpointX, y: target.y },
|
|
1365
1567
|
target
|
|
1366
1568
|
]);
|
|
1367
1569
|
}
|
|
1570
|
+
candidates.push(
|
|
1571
|
+
[source, { x: target.x, y: source.y }, target],
|
|
1572
|
+
[source, { x: source.x, y: target.y }, target]
|
|
1573
|
+
);
|
|
1574
|
+
return candidates;
|
|
1575
|
+
}
|
|
1576
|
+
function defaultSourceAnchor(direction) {
|
|
1577
|
+
switch (direction) {
|
|
1578
|
+
case "LR":
|
|
1579
|
+
return "right";
|
|
1580
|
+
case "RL":
|
|
1581
|
+
return "left";
|
|
1582
|
+
case "TB":
|
|
1583
|
+
return "bottom";
|
|
1584
|
+
case "BT":
|
|
1585
|
+
return "top";
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
function defaultAnchorsForGeometry(source, target, direction) {
|
|
1589
|
+
const dx = target.x + target.width / 2 - (source.x + source.width / 2);
|
|
1590
|
+
const dy = target.y + target.height / 2 - (source.y + source.height / 2);
|
|
1591
|
+
if (Math.abs(dy) > Math.abs(dx)) {
|
|
1592
|
+
return dy >= 0 ? { sourceAnchor: "bottom", targetAnchor: "top" } : { sourceAnchor: "top", targetAnchor: "bottom" };
|
|
1593
|
+
}
|
|
1594
|
+
if (Math.abs(dx) > 0) {
|
|
1595
|
+
return dx >= 0 ? { sourceAnchor: "right", targetAnchor: "left" } : { sourceAnchor: "left", targetAnchor: "right" };
|
|
1596
|
+
}
|
|
1597
|
+
return {
|
|
1598
|
+
sourceAnchor: defaultSourceAnchor(direction),
|
|
1599
|
+
targetAnchor: defaultTargetAnchor(direction)
|
|
1600
|
+
};
|
|
1601
|
+
}
|
|
1602
|
+
function defaultTargetAnchor(direction) {
|
|
1603
|
+
switch (direction) {
|
|
1604
|
+
case "LR":
|
|
1605
|
+
return "left";
|
|
1606
|
+
case "RL":
|
|
1607
|
+
return "right";
|
|
1608
|
+
case "TB":
|
|
1609
|
+
return "top";
|
|
1610
|
+
case "BT":
|
|
1611
|
+
return "bottom";
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
function expandedObstacleCandidates(source, target, direction, obstacles) {
|
|
1615
|
+
if (obstacles.length === 0) {
|
|
1616
|
+
return [];
|
|
1617
|
+
}
|
|
1618
|
+
const margin = 16;
|
|
1619
|
+
const candidates = [];
|
|
1620
|
+
if (direction === "TB" || direction === "BT") {
|
|
1621
|
+
const lanes = sortedUniqueLanes(
|
|
1622
|
+
obstacles.flatMap((obstacle) => [
|
|
1623
|
+
obstacle.x - margin,
|
|
1624
|
+
obstacle.x + obstacle.width + margin
|
|
1625
|
+
]),
|
|
1626
|
+
(source.x + target.x) / 2
|
|
1627
|
+
);
|
|
1628
|
+
for (const laneX of lanes) {
|
|
1629
|
+
candidates.push([
|
|
1630
|
+
source,
|
|
1631
|
+
{ x: laneX, y: source.y },
|
|
1632
|
+
{ x: laneX, y: target.y },
|
|
1633
|
+
target
|
|
1634
|
+
]);
|
|
1635
|
+
}
|
|
1636
|
+
} else {
|
|
1637
|
+
const lanes = sortedUniqueLanes(
|
|
1638
|
+
obstacles.flatMap((obstacle) => [
|
|
1639
|
+
obstacle.y - margin,
|
|
1640
|
+
obstacle.y + obstacle.height + margin
|
|
1641
|
+
]),
|
|
1642
|
+
(source.y + target.y) / 2
|
|
1643
|
+
);
|
|
1644
|
+
for (const laneY of lanes) {
|
|
1645
|
+
candidates.push([
|
|
1646
|
+
source,
|
|
1647
|
+
{ x: source.x, y: laneY },
|
|
1648
|
+
{ x: target.x, y: laneY },
|
|
1649
|
+
target
|
|
1650
|
+
]);
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1368
1653
|
return candidates;
|
|
1369
1654
|
}
|
|
1655
|
+
function sortedUniqueLanes(lanes, midpoint) {
|
|
1656
|
+
return [...new Set(lanes)].filter((lane) => Number.isFinite(lane)).sort((left, right) => {
|
|
1657
|
+
const distance = Math.abs(left - midpoint) - Math.abs(right - midpoint);
|
|
1658
|
+
return distance === 0 ? left - right : distance;
|
|
1659
|
+
});
|
|
1660
|
+
}
|
|
1370
1661
|
function routeIntersectsObstacles(points, obstacles) {
|
|
1371
1662
|
for (let index = 0; index < points.length - 1; index += 1) {
|
|
1372
1663
|
const a = points[index];
|
|
@@ -1445,12 +1736,17 @@ function solveDiagram(diagram, options = {}) {
|
|
|
1445
1736
|
options,
|
|
1446
1737
|
diagnostics
|
|
1447
1738
|
);
|
|
1739
|
+
const coordinatedSwimlanes = coordinateSwimlanes(
|
|
1740
|
+
diagram.swimlanes ?? [],
|
|
1741
|
+
constrained.boxes
|
|
1742
|
+
);
|
|
1448
1743
|
const groupBoxes = new Map(
|
|
1449
1744
|
coordinatedGroups.map((group) => [group.id, group.box])
|
|
1450
1745
|
);
|
|
1451
1746
|
const coordinatedEdges = coordinateEdges(
|
|
1452
1747
|
edges,
|
|
1453
1748
|
nodeGeometryById,
|
|
1749
|
+
coordinatedNodes,
|
|
1454
1750
|
[...nodeGeometryById.values()].map((geometry) => geometry.obstacleBox),
|
|
1455
1751
|
diagram.direction,
|
|
1456
1752
|
options,
|
|
@@ -1458,8 +1754,18 @@ function solveDiagram(diagram, options = {}) {
|
|
|
1458
1754
|
);
|
|
1459
1755
|
const allBoxes = [
|
|
1460
1756
|
...coordinatedNodes.map((node) => node.box),
|
|
1461
|
-
...
|
|
1757
|
+
...coordinatedNodes.flatMap(
|
|
1758
|
+
(node) => (node.ports ?? []).flatMap(
|
|
1759
|
+
(port) => port.label === void 0 ? [port.box] : [port.box, portLabelBox(port)]
|
|
1760
|
+
)
|
|
1761
|
+
),
|
|
1762
|
+
...groupBoxes.values(),
|
|
1763
|
+
...coordinatedSwimlanes.flatMap(
|
|
1764
|
+
(swimlane) => swimlane.box === void 0 ? [] : [swimlane.box]
|
|
1765
|
+
)
|
|
1462
1766
|
];
|
|
1767
|
+
const contentBounds = allBoxes.length === 0 ? { x: 0, y: 0, width: 0, height: 0 } : unionBoxes(allBoxes);
|
|
1768
|
+
const frame = diagram.frame === void 0 ? void 0 : coordinateFrame(diagram.frame, contentBounds);
|
|
1463
1769
|
return {
|
|
1464
1770
|
id: diagram.id,
|
|
1465
1771
|
...diagram.title === void 0 ? {} : { title: diagram.title },
|
|
@@ -1467,8 +1773,10 @@ function solveDiagram(diagram, options = {}) {
|
|
|
1467
1773
|
nodes: coordinatedNodes,
|
|
1468
1774
|
edges: coordinatedEdges,
|
|
1469
1775
|
groups: coordinatedGroups,
|
|
1776
|
+
...coordinatedSwimlanes.length === 0 ? {} : { swimlanes: coordinatedSwimlanes },
|
|
1470
1777
|
diagnostics,
|
|
1471
|
-
bounds:
|
|
1778
|
+
bounds: frame === void 0 ? contentBounds : unionBoxes([contentBounds, frame.box, frame.titleBox]),
|
|
1779
|
+
...frame === void 0 ? {} : { frame },
|
|
1472
1780
|
...diagram.metadata === void 0 ? {} : { metadata: diagram.metadata }
|
|
1473
1781
|
};
|
|
1474
1782
|
}
|
|
@@ -1494,6 +1802,9 @@ function coordinateNodes(nodes, boxes, options, diagnostics) {
|
|
|
1494
1802
|
coordinated.push({
|
|
1495
1803
|
id: node.id,
|
|
1496
1804
|
...node.label === void 0 ? {} : { label: node.label },
|
|
1805
|
+
...node.style === void 0 ? {} : { style: node.style },
|
|
1806
|
+
...node.ports === void 0 ? {} : { ports: coordinatePorts(node, box, options.portShifting) },
|
|
1807
|
+
...node.compartments === void 0 ? {} : { compartments: node.compartments },
|
|
1497
1808
|
...node.labelLayout === void 0 ? {} : { labelLayout: node.labelLayout },
|
|
1498
1809
|
shape: node.shape,
|
|
1499
1810
|
...node.metadata === void 0 ? {} : { metadata: node.metadata },
|
|
@@ -1504,6 +1815,142 @@ function coordinateNodes(nodes, boxes, options, diagnostics) {
|
|
|
1504
1815
|
}
|
|
1505
1816
|
return coordinated;
|
|
1506
1817
|
}
|
|
1818
|
+
function coordinatePorts(node, nodeBox, portShifting) {
|
|
1819
|
+
const portsBySide = /* @__PURE__ */ new Map();
|
|
1820
|
+
for (const port of node.ports ?? []) {
|
|
1821
|
+
const ports = portsBySide.get(port.side) ?? [];
|
|
1822
|
+
ports.push(port);
|
|
1823
|
+
portsBySide.set(port.side, ports);
|
|
1824
|
+
}
|
|
1825
|
+
const coordinated = [];
|
|
1826
|
+
for (const [side, ports] of portsBySide) {
|
|
1827
|
+
const sorted = [...ports ?? []].sort((a, b) => {
|
|
1828
|
+
const order = (a.order ?? 0) - (b.order ?? 0);
|
|
1829
|
+
return order === 0 ? a.id.localeCompare(b.id) : order;
|
|
1830
|
+
});
|
|
1831
|
+
for (let index = 0; index < sorted.length; index += 1) {
|
|
1832
|
+
const port = sorted[index];
|
|
1833
|
+
if (port === void 0) {
|
|
1834
|
+
continue;
|
|
1835
|
+
}
|
|
1836
|
+
const anchor = portAnchor(
|
|
1837
|
+
nodeBox,
|
|
1838
|
+
side,
|
|
1839
|
+
index,
|
|
1840
|
+
sorted.length,
|
|
1841
|
+
portShifting
|
|
1842
|
+
);
|
|
1843
|
+
const box = portBox(anchor);
|
|
1844
|
+
coordinated.push({ ...port, box, anchor });
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
return coordinated.sort((a, b) => a.id.localeCompare(b.id));
|
|
1848
|
+
}
|
|
1849
|
+
function portAnchor(nodeBox, side, index, count, portShifting) {
|
|
1850
|
+
const shiftingEnabled = portShifting?.enabled ?? true;
|
|
1851
|
+
const spacing = portShifting?.spacing ?? 24;
|
|
1852
|
+
const centeredOffset = shiftingEnabled ? (index - (count - 1) / 2) * spacing : 0;
|
|
1853
|
+
switch (side) {
|
|
1854
|
+
case "left":
|
|
1855
|
+
return {
|
|
1856
|
+
x: nodeBox.x,
|
|
1857
|
+
y: nodeBox.y + nodeBox.height / 2 + centeredOffset
|
|
1858
|
+
};
|
|
1859
|
+
case "right":
|
|
1860
|
+
return {
|
|
1861
|
+
x: nodeBox.x + nodeBox.width,
|
|
1862
|
+
y: nodeBox.y + nodeBox.height / 2 + centeredOffset
|
|
1863
|
+
};
|
|
1864
|
+
case "top":
|
|
1865
|
+
return {
|
|
1866
|
+
x: nodeBox.x + nodeBox.width / 2 + centeredOffset,
|
|
1867
|
+
y: nodeBox.y
|
|
1868
|
+
};
|
|
1869
|
+
case "bottom":
|
|
1870
|
+
return {
|
|
1871
|
+
x: nodeBox.x + nodeBox.width / 2 + centeredOffset,
|
|
1872
|
+
y: nodeBox.y + nodeBox.height
|
|
1873
|
+
};
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
function portBox(anchor) {
|
|
1877
|
+
const size = 10;
|
|
1878
|
+
return {
|
|
1879
|
+
x: anchor.x - size / 2,
|
|
1880
|
+
y: anchor.y - size / 2,
|
|
1881
|
+
width: size,
|
|
1882
|
+
height: size
|
|
1883
|
+
};
|
|
1884
|
+
}
|
|
1885
|
+
function portLabelBox(port) {
|
|
1886
|
+
const textWidth = Math.max(0, (port.label?.text.length ?? 0) * 6);
|
|
1887
|
+
const height = 12;
|
|
1888
|
+
const gap = 8;
|
|
1889
|
+
const x = port.side === "left" ? port.anchor.x - gap - textWidth : port.anchor.x + gap;
|
|
1890
|
+
return {
|
|
1891
|
+
x,
|
|
1892
|
+
y: port.anchor.y - 8 - height,
|
|
1893
|
+
width: textWidth,
|
|
1894
|
+
height
|
|
1895
|
+
};
|
|
1896
|
+
}
|
|
1897
|
+
function coordinateSwimlanes(swimlanes, nodeBoxes) {
|
|
1898
|
+
const titleSize = 28;
|
|
1899
|
+
const padding = 16;
|
|
1900
|
+
return swimlanes.map((swimlane) => {
|
|
1901
|
+
const laneBoxes = swimlane.lanes.flatMap((lane) => {
|
|
1902
|
+
const childBoxes = lane.children.map((child) => nodeBoxes.get(child)).filter((box) => box !== void 0);
|
|
1903
|
+
return childBoxes.length === 0 ? [] : [unionBoxes(childBoxes)];
|
|
1904
|
+
});
|
|
1905
|
+
const laneUnion = laneBoxes.length === 0 ? { x: 0, y: 0, width: 120, height: 80 } : unionBoxes(laneBoxes);
|
|
1906
|
+
const outer = expand(laneUnion, padding, titleSize);
|
|
1907
|
+
const laneCount = Math.max(1, swimlane.lanes.length);
|
|
1908
|
+
const lanes = swimlane.lanes.map((lane, index) => {
|
|
1909
|
+
const box = swimlane.orientation === "vertical" ? {
|
|
1910
|
+
x: outer.x + outer.width / laneCount * index,
|
|
1911
|
+
y: outer.y,
|
|
1912
|
+
width: outer.width / laneCount,
|
|
1913
|
+
height: outer.height
|
|
1914
|
+
} : {
|
|
1915
|
+
x: outer.x,
|
|
1916
|
+
y: outer.y + outer.height / laneCount * index,
|
|
1917
|
+
width: outer.width,
|
|
1918
|
+
height: outer.height / laneCount
|
|
1919
|
+
};
|
|
1920
|
+
return { ...lane, box };
|
|
1921
|
+
});
|
|
1922
|
+
return { ...swimlane, lanes, box: outer };
|
|
1923
|
+
});
|
|
1924
|
+
}
|
|
1925
|
+
function coordinateFrame(frame, contentBounds) {
|
|
1926
|
+
const padding = 32;
|
|
1927
|
+
const titleHeight = 28;
|
|
1928
|
+
const titleWidth = Math.max(180, frame.titleTab.length * 7);
|
|
1929
|
+
const box = {
|
|
1930
|
+
x: contentBounds.x - padding,
|
|
1931
|
+
y: contentBounds.y - padding - titleHeight,
|
|
1932
|
+
width: contentBounds.width + padding * 2,
|
|
1933
|
+
height: contentBounds.height + padding * 2 + titleHeight
|
|
1934
|
+
};
|
|
1935
|
+
return {
|
|
1936
|
+
...frame,
|
|
1937
|
+
box,
|
|
1938
|
+
titleBox: {
|
|
1939
|
+
x: box.x,
|
|
1940
|
+
y: box.y,
|
|
1941
|
+
width: Math.min(titleWidth, box.width * 0.8),
|
|
1942
|
+
height: titleHeight
|
|
1943
|
+
}
|
|
1944
|
+
};
|
|
1945
|
+
}
|
|
1946
|
+
function expand(box, padding, titleSize) {
|
|
1947
|
+
return {
|
|
1948
|
+
x: box.x - padding,
|
|
1949
|
+
y: box.y - padding - titleSize,
|
|
1950
|
+
width: box.width + padding * 2,
|
|
1951
|
+
height: box.height + padding * 2 + titleSize
|
|
1952
|
+
};
|
|
1953
|
+
}
|
|
1507
1954
|
function coordinateGroups(groups, nodeBoxes, options, diagnostics) {
|
|
1508
1955
|
const coordinated = [];
|
|
1509
1956
|
const groupBoxes = /* @__PURE__ */ new Map();
|
|
@@ -1552,8 +1999,11 @@ function coordinateGroups(groups, nodeBoxes, options, diagnostics) {
|
|
|
1552
1999
|
}
|
|
1553
2000
|
return coordinated;
|
|
1554
2001
|
}
|
|
1555
|
-
function coordinateEdges(edges, nodes, obstacles, direction, options, diagnostics) {
|
|
2002
|
+
function coordinateEdges(edges, nodes, coordinatedNodes, obstacles, direction, options, diagnostics) {
|
|
1556
2003
|
const coordinated = [];
|
|
2004
|
+
const coordinatedNodeById = new Map(
|
|
2005
|
+
coordinatedNodes.map((node) => [node.id, node])
|
|
2006
|
+
);
|
|
1557
2007
|
for (const edge of edges) {
|
|
1558
2008
|
const source = nodes.get(edge.source.nodeId);
|
|
1559
2009
|
const target = nodes.get(edge.target.nodeId);
|
|
@@ -1571,11 +2021,13 @@ function coordinateEdges(edges, nodes, obstacles, direction, options, diagnostic
|
|
|
1571
2021
|
});
|
|
1572
2022
|
continue;
|
|
1573
2023
|
}
|
|
2024
|
+
const sourcePort = coordinatedNodeById.get(edge.source.nodeId)?.ports?.find((port) => port.id === edge.source.portId);
|
|
2025
|
+
const targetPort = coordinatedNodeById.get(edge.target.nodeId)?.ports?.find((port) => port.id === edge.target.portId);
|
|
1574
2026
|
const route = routeEdge({
|
|
1575
2027
|
kind: options.routeKind ?? "orthogonal",
|
|
1576
2028
|
direction,
|
|
1577
|
-
source,
|
|
1578
|
-
target,
|
|
2029
|
+
source: portGeometry(source, sourcePort),
|
|
2030
|
+
target: portGeometry(target, targetPort),
|
|
1579
2031
|
...edge.source.anchor === void 0 ? {} : { sourceAnchor: edge.source.anchor },
|
|
1580
2032
|
...edge.target.anchor === void 0 ? {} : { targetAnchor: edge.target.anchor },
|
|
1581
2033
|
obstacles: obstacles.filter(
|
|
@@ -1595,6 +2047,21 @@ function coordinateEdges(edges, nodes, obstacles, direction, options, diagnostic
|
|
|
1595
2047
|
}
|
|
1596
2048
|
return coordinated;
|
|
1597
2049
|
}
|
|
2050
|
+
function portGeometry(nodeGeometry, port) {
|
|
2051
|
+
if (port === void 0) {
|
|
2052
|
+
return nodeGeometry;
|
|
2053
|
+
}
|
|
2054
|
+
return {
|
|
2055
|
+
...nodeGeometry,
|
|
2056
|
+
box: port.box,
|
|
2057
|
+
center: port.anchor,
|
|
2058
|
+
anchors: nodeGeometry.anchors.map((anchor) => ({
|
|
2059
|
+
name: anchor.name,
|
|
2060
|
+
point: port.anchor
|
|
2061
|
+
})),
|
|
2062
|
+
obstacleBox: port.box
|
|
2063
|
+
};
|
|
2064
|
+
}
|
|
1598
2065
|
function stableById(items) {
|
|
1599
2066
|
return [...items].sort((a, b) => a.id.localeCompare(b.id));
|
|
1600
2067
|
}
|
|
@@ -1624,34 +2091,34 @@ function assertFiniteNonNegative(value, label) {
|
|
|
1624
2091
|
throw new TypeError(`${label} must be a finite non-negative width`);
|
|
1625
2092
|
}
|
|
1626
2093
|
}
|
|
1627
|
-
function validateTextStyle(
|
|
1628
|
-
assertFinitePositive(
|
|
1629
|
-
if (
|
|
1630
|
-
assertFinitePositive(
|
|
2094
|
+
function validateTextStyle(style2) {
|
|
2095
|
+
assertFinitePositive(style2.fontSize, "fontSize");
|
|
2096
|
+
if (style2.lineHeight !== void 0) {
|
|
2097
|
+
assertFinitePositive(style2.lineHeight, "lineHeight");
|
|
1631
2098
|
}
|
|
1632
|
-
if (
|
|
2099
|
+
if (style2.letterSpacing !== void 0 && !Number.isFinite(style2.letterSpacing)) {
|
|
1633
2100
|
throw new TypeError("letterSpacing must be finite");
|
|
1634
2101
|
}
|
|
1635
2102
|
}
|
|
1636
|
-
function resolveLineHeight(
|
|
1637
|
-
validateTextStyle(
|
|
1638
|
-
return
|
|
2103
|
+
function resolveLineHeight(style2) {
|
|
2104
|
+
validateTextStyle(style2);
|
|
2105
|
+
return style2.lineHeight ?? style2.fontSize * 1.2;
|
|
1639
2106
|
}
|
|
1640
|
-
function toCanvasFont(
|
|
1641
|
-
validateTextStyle(
|
|
1642
|
-
const fontStyle =
|
|
1643
|
-
const fontWeight =
|
|
1644
|
-
return `${fontStyle}${fontWeight} ${
|
|
2107
|
+
function toCanvasFont(style2) {
|
|
2108
|
+
validateTextStyle(style2);
|
|
2109
|
+
const fontStyle = style2.fontStyle === "italic" ? "italic " : "";
|
|
2110
|
+
const fontWeight = style2.fontWeight ?? 400;
|
|
2111
|
+
return `${fontStyle}${fontWeight} ${style2.fontSize}px ${style2.fontFamily}`;
|
|
1645
2112
|
}
|
|
1646
2113
|
|
|
1647
2114
|
// src/text/fallback.ts
|
|
1648
2115
|
var DeterministicTextMeasurer = class {
|
|
1649
|
-
prepare(text,
|
|
1650
|
-
validateTextStyle(
|
|
2116
|
+
prepare(text, style2) {
|
|
2117
|
+
validateTextStyle(style2);
|
|
1651
2118
|
return {
|
|
1652
2119
|
text,
|
|
1653
|
-
font: toCanvasFont(
|
|
1654
|
-
style: { ...
|
|
2120
|
+
font: toCanvasFont(style2),
|
|
2121
|
+
style: { ...style2 },
|
|
1655
2122
|
backend: "deterministic"
|
|
1656
2123
|
};
|
|
1657
2124
|
}
|
|
@@ -1710,9 +2177,9 @@ var DeterministicTextMeasurer = class {
|
|
|
1710
2177
|
return output;
|
|
1711
2178
|
}
|
|
1712
2179
|
};
|
|
1713
|
-
function getCharacterWidth(
|
|
1714
|
-
const letterSpacing =
|
|
1715
|
-
return Math.max(0,
|
|
2180
|
+
function getCharacterWidth(style2) {
|
|
2181
|
+
const letterSpacing = style2.letterSpacing ?? 0;
|
|
2182
|
+
return Math.max(0, style2.fontSize * 0.6 + letterSpacing);
|
|
1716
2183
|
}
|
|
1717
2184
|
function createLine(text, width, segmentIndex, start, end) {
|
|
1718
2185
|
return {
|
|
@@ -1733,6 +2200,108 @@ function assertFinitePositiveLineHeight(lineHeight) {
|
|
|
1733
2200
|
throw new TypeError("lineHeight must be finite and positive");
|
|
1734
2201
|
}
|
|
1735
2202
|
}
|
|
2203
|
+
var require2 = createRequire(import.meta.url);
|
|
2204
|
+
function installNodeCanvasRuntime(loadNodeCanvasModule = loadDefaultNodeCanvasModule) {
|
|
2205
|
+
if (typeof globalThis.OffscreenCanvas === "function") {
|
|
2206
|
+
return true;
|
|
2207
|
+
}
|
|
2208
|
+
try {
|
|
2209
|
+
const canvasModule = loadNodeCanvasModule();
|
|
2210
|
+
const { createCanvas } = canvasModule;
|
|
2211
|
+
const NodeOffscreenCanvas = class {
|
|
2212
|
+
canvas;
|
|
2213
|
+
constructor(width, height) {
|
|
2214
|
+
this.canvas = createCanvas(width, height);
|
|
2215
|
+
}
|
|
2216
|
+
getContext(contextId) {
|
|
2217
|
+
return contextId === "2d" ? this.canvas.getContext("2d") : null;
|
|
2218
|
+
}
|
|
2219
|
+
};
|
|
2220
|
+
globalThis.OffscreenCanvas = NodeOffscreenCanvas;
|
|
2221
|
+
return true;
|
|
2222
|
+
} catch {
|
|
2223
|
+
return false;
|
|
2224
|
+
}
|
|
2225
|
+
}
|
|
2226
|
+
function loadDefaultNodeCanvasModule() {
|
|
2227
|
+
return require2("@napi-rs/canvas");
|
|
2228
|
+
}
|
|
2229
|
+
var RUNTIME_UNAVAILABLE = "text.pretext.runtime-unavailable";
|
|
2230
|
+
function isPretextRuntimeAvailable() {
|
|
2231
|
+
return typeof Intl.Segmenter === "function" && typeof globalThis.OffscreenCanvas === "function";
|
|
2232
|
+
}
|
|
2233
|
+
var PretextTextMeasurer = class {
|
|
2234
|
+
prepare(text, style2) {
|
|
2235
|
+
if (!isPretextRuntimeAvailable()) {
|
|
2236
|
+
throw new TypeError(RUNTIME_UNAVAILABLE);
|
|
2237
|
+
}
|
|
2238
|
+
validateTextStyle(style2);
|
|
2239
|
+
const font = toCanvasFont(style2);
|
|
2240
|
+
const options = {
|
|
2241
|
+
...style2.whiteSpace === void 0 ? {} : { whiteSpace: style2.whiteSpace },
|
|
2242
|
+
...style2.wordBreak === void 0 ? {} : { wordBreak: style2.wordBreak },
|
|
2243
|
+
...style2.letterSpacing === void 0 ? {} : { letterSpacing: style2.letterSpacing }
|
|
2244
|
+
};
|
|
2245
|
+
const prepared = prepareWithSegments(text, font, options);
|
|
2246
|
+
return {
|
|
2247
|
+
text,
|
|
2248
|
+
font,
|
|
2249
|
+
style: { ...style2 },
|
|
2250
|
+
backend: "pretext",
|
|
2251
|
+
pretextPrepared: prepared
|
|
2252
|
+
};
|
|
2253
|
+
}
|
|
2254
|
+
layout(prepared, maxWidth, lineHeight = resolveLineHeight(prepared.style)) {
|
|
2255
|
+
assertFiniteNonNegative(maxWidth, "maxWidth");
|
|
2256
|
+
if (!Number.isFinite(lineHeight) || lineHeight <= 0) {
|
|
2257
|
+
throw new TypeError("lineHeight must be finite and positive");
|
|
2258
|
+
}
|
|
2259
|
+
const result = layoutWithLines(
|
|
2260
|
+
toInternalPrepared(prepared),
|
|
2261
|
+
maxWidth,
|
|
2262
|
+
lineHeight
|
|
2263
|
+
);
|
|
2264
|
+
const width = result.lines.reduce(
|
|
2265
|
+
(current, line) => Math.max(current, line.width),
|
|
2266
|
+
0
|
|
2267
|
+
);
|
|
2268
|
+
return {
|
|
2269
|
+
width,
|
|
2270
|
+
height: result.height,
|
|
2271
|
+
lineHeight,
|
|
2272
|
+
lineCount: result.lineCount,
|
|
2273
|
+
lines: result.lines.map((line) => ({
|
|
2274
|
+
text: line.text,
|
|
2275
|
+
width: line.width,
|
|
2276
|
+
start: {
|
|
2277
|
+
segmentIndex: line.start.segmentIndex,
|
|
2278
|
+
graphemeIndex: line.start.graphemeIndex
|
|
2279
|
+
},
|
|
2280
|
+
end: {
|
|
2281
|
+
segmentIndex: line.end.segmentIndex,
|
|
2282
|
+
graphemeIndex: line.end.graphemeIndex
|
|
2283
|
+
}
|
|
2284
|
+
})),
|
|
2285
|
+
diagnostics: []
|
|
2286
|
+
};
|
|
2287
|
+
}
|
|
2288
|
+
naturalWidth(prepared) {
|
|
2289
|
+
return measureNaturalWidth(toInternalPrepared(prepared));
|
|
2290
|
+
}
|
|
2291
|
+
};
|
|
2292
|
+
function toInternalPrepared(prepared) {
|
|
2293
|
+
if (prepared.backend !== "pretext" || !("pretextPrepared" in prepared)) {
|
|
2294
|
+
throw new TypeError("prepared text was not created by PretextTextMeasurer");
|
|
2295
|
+
}
|
|
2296
|
+
return prepared.pretextPrepared;
|
|
2297
|
+
}
|
|
2298
|
+
|
|
2299
|
+
// src/text/default.ts
|
|
2300
|
+
function createDefaultTextMeasurer(options = {}) {
|
|
2301
|
+
const installRuntime = options.installNodeCanvasRuntime ?? installNodeCanvasRuntime;
|
|
2302
|
+
installRuntime();
|
|
2303
|
+
return isPretextRuntimeAvailable() ? new PretextTextMeasurer() : new DeterministicTextMeasurer();
|
|
2304
|
+
}
|
|
1736
2305
|
|
|
1737
2306
|
// src/labels/fit.ts
|
|
1738
2307
|
function fitLabel(text, options, measurer) {
|
|
@@ -1791,6 +2360,7 @@ function computeLabelLayout(text, options, measurer) {
|
|
|
1791
2360
|
fittedSize,
|
|
1792
2361
|
padding,
|
|
1793
2362
|
font: { ...options.font },
|
|
2363
|
+
textBackend: prepared.backend,
|
|
1794
2364
|
lineHeight,
|
|
1795
2365
|
lines: buildLines(textLayout, contentBox2, lineHeight),
|
|
1796
2366
|
overflow,
|
|
@@ -1885,8 +2455,9 @@ function normalizeDiagramDsl(dslValue, options = {}) {
|
|
|
1885
2455
|
...outputResult(dsl)
|
|
1886
2456
|
};
|
|
1887
2457
|
}
|
|
1888
|
-
const measurer = options.textMeasurer ??
|
|
2458
|
+
const measurer = options.textMeasurer ?? createDefaultTextMeasurer();
|
|
1889
2459
|
const routeKind = dsl.routing?.kind ?? "orthogonal";
|
|
2460
|
+
const portShifting = normalizePortShifting(dsl.routing?.portShifting);
|
|
1890
2461
|
const diagram = {
|
|
1891
2462
|
id: options.id ?? dsl.id ?? "diagram",
|
|
1892
2463
|
...dsl.title === void 0 ? {} : { title: dsl.title },
|
|
@@ -1894,9 +2465,14 @@ function normalizeDiagramDsl(dslValue, options = {}) {
|
|
|
1894
2465
|
nodes: normalizeNodes(dsl, measurer),
|
|
1895
2466
|
edges: normalizeEdges(dsl),
|
|
1896
2467
|
groups: normalizeGroups(dsl, measurer),
|
|
2468
|
+
swimlanes: normalizeSwimlanes(dsl),
|
|
1897
2469
|
constraints: normalizeConstraints(dsl),
|
|
1898
2470
|
diagnostics: [],
|
|
1899
|
-
|
|
2471
|
+
...dsl.frame === void 0 ? {} : { frame: normalizeFrame(dsl.frame) },
|
|
2472
|
+
metadata: {
|
|
2473
|
+
routeKind,
|
|
2474
|
+
...portShifting === void 0 ? {} : { portShifting }
|
|
2475
|
+
}
|
|
1900
2476
|
};
|
|
1901
2477
|
return {
|
|
1902
2478
|
diagram,
|
|
@@ -1904,6 +2480,15 @@ function normalizeDiagramDsl(dslValue, options = {}) {
|
|
|
1904
2480
|
...outputResult(dsl)
|
|
1905
2481
|
};
|
|
1906
2482
|
}
|
|
2483
|
+
function normalizePortShifting(portShifting) {
|
|
2484
|
+
if (portShifting === void 0) {
|
|
2485
|
+
return void 0;
|
|
2486
|
+
}
|
|
2487
|
+
return {
|
|
2488
|
+
...portShifting.enabled === void 0 ? {} : { enabled: portShifting.enabled },
|
|
2489
|
+
...portShifting.spacing === void 0 ? {} : { spacing: portShifting.spacing }
|
|
2490
|
+
};
|
|
2491
|
+
}
|
|
1907
2492
|
function outputResult(dsl) {
|
|
1908
2493
|
return dsl.output?.format === void 0 ? {} : { output: { format: dsl.output.format } };
|
|
1909
2494
|
}
|
|
@@ -1913,15 +2498,24 @@ function normalizeNodes(dsl, measurer) {
|
|
|
1913
2498
|
const label = toLabel(node?.label);
|
|
1914
2499
|
const labelLayout = label === void 0 ? void 0 : fitDslLabel(label, measurer);
|
|
1915
2500
|
const fittedSize = labelLayout?.fittedSize;
|
|
2501
|
+
const nodeCompartments = node?.compartments === void 0 ? void 0 : compartments(node.compartments);
|
|
2502
|
+
const compartmentWidth = nodeCompartments === void 0 ? 0 : compartmentNaturalWidth(id, label, nodeCompartments, measurer);
|
|
1916
2503
|
return {
|
|
1917
2504
|
id,
|
|
1918
2505
|
...label === void 0 ? {} : { label },
|
|
1919
2506
|
shape: node?.shape ?? "rectangle",
|
|
1920
2507
|
...node?.position === void 0 ? {} : { position: point(node.position) },
|
|
2508
|
+
...node?.style === void 0 ? {} : { style: style(node.style) },
|
|
2509
|
+
...node?.ports === void 0 ? {} : { ports: normalizePorts(node.ports) },
|
|
2510
|
+
...nodeCompartments === void 0 ? {} : { compartments: nodeCompartments },
|
|
1921
2511
|
size: {
|
|
1922
|
-
width: Math.max(
|
|
2512
|
+
width: Math.max(
|
|
2513
|
+
DEFAULT_NODE_MIN_SIZE.width,
|
|
2514
|
+
fittedSize?.width ?? 0,
|
|
2515
|
+
compartmentWidth
|
|
2516
|
+
),
|
|
1923
2517
|
height: Math.max(
|
|
1924
|
-
DEFAULT_NODE_MIN_SIZE.height,
|
|
2518
|
+
nodeCompartments === void 0 ? DEFAULT_NODE_MIN_SIZE.height : compartmentHeight(nodeCompartments),
|
|
1925
2519
|
fittedSize?.height ?? 0
|
|
1926
2520
|
)
|
|
1927
2521
|
},
|
|
@@ -1930,11 +2524,42 @@ function normalizeNodes(dsl, measurer) {
|
|
|
1930
2524
|
};
|
|
1931
2525
|
});
|
|
1932
2526
|
}
|
|
2527
|
+
function compartmentHeight(value) {
|
|
2528
|
+
const rowCount = (value.stereotype === void 0 ? 0 : 1) + 1 + (value.properties?.length ?? 0) + (value.constraints?.length ?? 0);
|
|
2529
|
+
const rowHeight = 16;
|
|
2530
|
+
const verticalPadding = 20;
|
|
2531
|
+
return Math.max(
|
|
2532
|
+
DEFAULT_NODE_MIN_SIZE.height,
|
|
2533
|
+
rowCount * rowHeight + verticalPadding
|
|
2534
|
+
);
|
|
2535
|
+
}
|
|
2536
|
+
function compartmentNaturalWidth(id, label, value, measurer) {
|
|
2537
|
+
const rows = compartmentRows(id, label, value);
|
|
2538
|
+
const maxRowWidth = rows.reduce((width, row) => {
|
|
2539
|
+
const prepared = measurer.prepare(row, DEFAULT_FONT);
|
|
2540
|
+
return Math.max(width, measurer.naturalWidth(prepared));
|
|
2541
|
+
}, 0);
|
|
2542
|
+
return Math.ceil(
|
|
2543
|
+
maxRowWidth + DEFAULT_NODE_PADDING.left + DEFAULT_NODE_PADDING.right
|
|
2544
|
+
);
|
|
2545
|
+
}
|
|
2546
|
+
function compartmentRows(id, label, value) {
|
|
2547
|
+
return [
|
|
2548
|
+
...value.stereotype === void 0 ? [] : [value.stereotype],
|
|
2549
|
+
value.name ?? label?.text ?? id,
|
|
2550
|
+
...value.properties ?? [],
|
|
2551
|
+
...value.constraints ?? []
|
|
2552
|
+
];
|
|
2553
|
+
}
|
|
1933
2554
|
function normalizeEdges(dsl) {
|
|
1934
2555
|
const counts = /* @__PURE__ */ new Map();
|
|
1935
2556
|
return (dsl.edges ?? []).map((edge) => {
|
|
1936
|
-
const
|
|
1937
|
-
const
|
|
2557
|
+
const source = typeof edge === "string" ? void 0 : edge.source;
|
|
2558
|
+
const target = typeof edge === "string" ? void 0 : edge.target;
|
|
2559
|
+
const sourceId = typeof edge === "string" ? "" : edge.sourceId ?? endpointNodeId(source) ?? "";
|
|
2560
|
+
const targetId = typeof edge === "string" ? "" : edge.targetId ?? endpointNodeId(target) ?? "";
|
|
2561
|
+
const sourceEndpoint = typeof edge === "string" ? { nodeId: sourceId } : endpoint(source, edge.sourceId);
|
|
2562
|
+
const targetEndpoint = typeof edge === "string" ? { nodeId: targetId } : endpoint(target, edge.targetId);
|
|
1938
2563
|
const baseId = `${sourceId}-${targetId}`;
|
|
1939
2564
|
const count = counts.get(baseId) ?? 0;
|
|
1940
2565
|
counts.set(baseId, count + 1);
|
|
@@ -1942,9 +2567,96 @@ function normalizeEdges(dsl) {
|
|
|
1942
2567
|
const label = typeof edge === "string" ? void 0 : toLabel(edge.label);
|
|
1943
2568
|
return {
|
|
1944
2569
|
id,
|
|
1945
|
-
source:
|
|
1946
|
-
target:
|
|
1947
|
-
...label === void 0 ? {} : { label }
|
|
2570
|
+
source: sourceEndpoint,
|
|
2571
|
+
target: targetEndpoint,
|
|
2572
|
+
...label === void 0 ? {} : { label },
|
|
2573
|
+
...typeof edge === "string" || edge.style === void 0 ? {} : { style: edge.style },
|
|
2574
|
+
...typeof edge === "string" || edge.arrowhead === void 0 ? {} : { arrowhead: edge.arrowhead }
|
|
2575
|
+
};
|
|
2576
|
+
});
|
|
2577
|
+
}
|
|
2578
|
+
function normalizePorts(ports) {
|
|
2579
|
+
return Object.keys(ports ?? {}).sort().map((id) => {
|
|
2580
|
+
const port = ports?.[id];
|
|
2581
|
+
const label = toLabel(port?.label);
|
|
2582
|
+
return {
|
|
2583
|
+
id,
|
|
2584
|
+
...label === void 0 ? {} : { label },
|
|
2585
|
+
side: port?.side ?? "right",
|
|
2586
|
+
kind: port?.kind ?? "proxy",
|
|
2587
|
+
...port?.order === void 0 ? {} : { order: port.order },
|
|
2588
|
+
...port?.style === void 0 ? {} : { style: style(port.style) }
|
|
2589
|
+
};
|
|
2590
|
+
});
|
|
2591
|
+
}
|
|
2592
|
+
function endpoint(value, nodeIdOverride) {
|
|
2593
|
+
if (nodeIdOverride !== void 0) {
|
|
2594
|
+
return {
|
|
2595
|
+
nodeId: nodeIdOverride,
|
|
2596
|
+
...typeof value === "object" && value.node === nodeIdOverride && value.port !== void 0 ? { portId: value.port } : {}
|
|
2597
|
+
};
|
|
2598
|
+
}
|
|
2599
|
+
if (value === void 0) {
|
|
2600
|
+
return { nodeId: "" };
|
|
2601
|
+
}
|
|
2602
|
+
if (typeof value === "string") {
|
|
2603
|
+
return { nodeId: value };
|
|
2604
|
+
}
|
|
2605
|
+
return {
|
|
2606
|
+
nodeId: value.node,
|
|
2607
|
+
...value.port === void 0 ? {} : { portId: value.port }
|
|
2608
|
+
};
|
|
2609
|
+
}
|
|
2610
|
+
function style(value) {
|
|
2611
|
+
return {
|
|
2612
|
+
...value.fill === void 0 ? {} : { fill: value.fill },
|
|
2613
|
+
...value.stroke === void 0 ? {} : { stroke: value.stroke }
|
|
2614
|
+
};
|
|
2615
|
+
}
|
|
2616
|
+
function compartments(value) {
|
|
2617
|
+
return {
|
|
2618
|
+
...value.stereotype === void 0 ? {} : { stereotype: value.stereotype },
|
|
2619
|
+
...value.name === void 0 ? {} : { name: value.name },
|
|
2620
|
+
...value.properties === void 0 ? {} : { properties: value.properties.map(formatCompartmentEntry) },
|
|
2621
|
+
...value.constraints === void 0 ? {} : { constraints: [...value.constraints] }
|
|
2622
|
+
};
|
|
2623
|
+
}
|
|
2624
|
+
function normalizeFrame(frame) {
|
|
2625
|
+
return {
|
|
2626
|
+
kind: frame.kind,
|
|
2627
|
+
...frame.context === void 0 ? {} : { context: frame.context },
|
|
2628
|
+
...frame.name === void 0 ? {} : { name: frame.name },
|
|
2629
|
+
titleTab: frame.titleTab,
|
|
2630
|
+
...frame.style === void 0 ? {} : { style: style(frame.style) }
|
|
2631
|
+
};
|
|
2632
|
+
}
|
|
2633
|
+
function formatCompartmentEntry(value) {
|
|
2634
|
+
if (typeof value === "string") {
|
|
2635
|
+
return value;
|
|
2636
|
+
}
|
|
2637
|
+
const [entry] = Object.entries(value);
|
|
2638
|
+
if (entry === void 0) {
|
|
2639
|
+
return "";
|
|
2640
|
+
}
|
|
2641
|
+
return `${entry[0]}: ${entry[1]}`;
|
|
2642
|
+
}
|
|
2643
|
+
function normalizeSwimlanes(dsl) {
|
|
2644
|
+
return Object.keys(dsl.swimlanes ?? {}).sort().map((id) => {
|
|
2645
|
+
const swimlane = dsl.swimlanes?.[id];
|
|
2646
|
+
const label = toLabel(swimlane?.label);
|
|
2647
|
+
return {
|
|
2648
|
+
id,
|
|
2649
|
+
...label === void 0 ? {} : { label },
|
|
2650
|
+
orientation: swimlane?.orientation ?? "vertical",
|
|
2651
|
+
lanes: Object.keys(swimlane?.lanes ?? {}).sort().map((laneId) => {
|
|
2652
|
+
const lane = swimlane?.lanes[laneId];
|
|
2653
|
+
const laneLabel = toLabel(lane?.label);
|
|
2654
|
+
return {
|
|
2655
|
+
id: laneId,
|
|
2656
|
+
...laneLabel === void 0 ? {} : { label: laneLabel },
|
|
2657
|
+
children: [...lane?.children ?? []]
|
|
2658
|
+
};
|
|
2659
|
+
})
|
|
1948
2660
|
};
|
|
1949
2661
|
});
|
|
1950
2662
|
}
|
|
@@ -2018,14 +2730,28 @@ function validateReferences(dsl) {
|
|
|
2018
2730
|
if (typeof edge === "string") {
|
|
2019
2731
|
return;
|
|
2020
2732
|
}
|
|
2021
|
-
const sourceId = edge.sourceId ?? edge.source;
|
|
2022
|
-
const targetId = edge.targetId ?? edge.target;
|
|
2733
|
+
const sourceId = edge.sourceId ?? endpointNodeId(edge.source);
|
|
2734
|
+
const targetId = edge.targetId ?? endpointNodeId(edge.target);
|
|
2735
|
+
const sourceEndpoint = endpoint(edge.source, edge.sourceId);
|
|
2736
|
+
const targetEndpoint = endpoint(edge.target, edge.targetId);
|
|
2023
2737
|
if (sourceId !== void 0 && !nodeIds.has(sourceId)) {
|
|
2024
2738
|
diagnostics.push(referenceMissing(["edges", index, "source"], sourceId));
|
|
2025
2739
|
}
|
|
2026
2740
|
if (targetId !== void 0 && !nodeIds.has(targetId)) {
|
|
2027
2741
|
diagnostics.push(referenceMissing(["edges", index, "target"], targetId));
|
|
2028
2742
|
}
|
|
2743
|
+
validateEndpointPort(
|
|
2744
|
+
dsl,
|
|
2745
|
+
sourceEndpoint,
|
|
2746
|
+
["edges", index, "source"],
|
|
2747
|
+
diagnostics
|
|
2748
|
+
);
|
|
2749
|
+
validateEndpointPort(
|
|
2750
|
+
dsl,
|
|
2751
|
+
targetEndpoint,
|
|
2752
|
+
["edges", index, "target"],
|
|
2753
|
+
diagnostics
|
|
2754
|
+
);
|
|
2029
2755
|
});
|
|
2030
2756
|
for (const [groupId, group] of Object.entries(dsl.groups ?? {})) {
|
|
2031
2757
|
(group.nodes ?? []).forEach((nodeId, index) => {
|
|
@@ -2043,6 +2769,27 @@ function validateReferences(dsl) {
|
|
|
2043
2769
|
}
|
|
2044
2770
|
});
|
|
2045
2771
|
}
|
|
2772
|
+
for (const [swimlaneId, swimlane] of Object.entries(dsl.swimlanes ?? {})) {
|
|
2773
|
+
for (const [laneId, lane] of Object.entries(swimlane.lanes)) {
|
|
2774
|
+
(lane.children ?? []).forEach((child, childIndex) => {
|
|
2775
|
+
if (!nodeIds.has(child)) {
|
|
2776
|
+
diagnostics.push(
|
|
2777
|
+
referenceMissing(
|
|
2778
|
+
[
|
|
2779
|
+
"swimlanes",
|
|
2780
|
+
swimlaneId,
|
|
2781
|
+
"lanes",
|
|
2782
|
+
laneId,
|
|
2783
|
+
"children",
|
|
2784
|
+
childIndex
|
|
2785
|
+
],
|
|
2786
|
+
child
|
|
2787
|
+
)
|
|
2788
|
+
);
|
|
2789
|
+
}
|
|
2790
|
+
});
|
|
2791
|
+
}
|
|
2792
|
+
}
|
|
2046
2793
|
(dsl.constraints ?? []).forEach((constraint, index) => {
|
|
2047
2794
|
switch (constraint.kind) {
|
|
2048
2795
|
case "exact-position": {
|
|
@@ -2086,10 +2833,12 @@ function validateReferences(dsl) {
|
|
|
2086
2833
|
break;
|
|
2087
2834
|
case "containment": {
|
|
2088
2835
|
const container = constraint.containerId ?? constraint.container;
|
|
2089
|
-
if (container !== void 0
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2836
|
+
if (container !== void 0) {
|
|
2837
|
+
if (!nodeIds.has(container)) {
|
|
2838
|
+
diagnostics.push(
|
|
2839
|
+
referenceMissing(["constraints", index, "container"], container)
|
|
2840
|
+
);
|
|
2841
|
+
}
|
|
2093
2842
|
}
|
|
2094
2843
|
(constraint.childIds ?? constraint.children ?? []).forEach(
|
|
2095
2844
|
(child, childIndex) => {
|
|
@@ -2119,8 +2868,23 @@ function referenceMissing(path, id) {
|
|
|
2119
2868
|
hint: "Define the referenced node or group id, or update this reference."
|
|
2120
2869
|
};
|
|
2121
2870
|
}
|
|
2122
|
-
function hasNodeOrGroup(id, nodeIds, groupIds) {
|
|
2123
|
-
return nodeIds.has(id) || groupIds.has(id);
|
|
2871
|
+
function hasNodeOrGroup(id, nodeIds, groupIds, swimlaneLaneIds = /* @__PURE__ */ new Set()) {
|
|
2872
|
+
return nodeIds.has(id) || groupIds.has(id) || swimlaneLaneIds.has(id);
|
|
2873
|
+
}
|
|
2874
|
+
function endpointNodeId(endpointValue) {
|
|
2875
|
+
if (typeof endpointValue === "string" || endpointValue === void 0) {
|
|
2876
|
+
return endpointValue;
|
|
2877
|
+
}
|
|
2878
|
+
return endpointValue.node;
|
|
2879
|
+
}
|
|
2880
|
+
function validateEndpointPort(dsl, endpointValue, path, diagnostics) {
|
|
2881
|
+
if (endpointValue.portId === void 0) {
|
|
2882
|
+
return;
|
|
2883
|
+
}
|
|
2884
|
+
const node = dsl.nodes[endpointValue.nodeId];
|
|
2885
|
+
if (node !== void 0 && node.ports?.[endpointValue.portId] === void 0) {
|
|
2886
|
+
diagnostics.push(referenceMissing([...path, "port"], endpointValue.portId));
|
|
2887
|
+
}
|
|
2124
2888
|
}
|
|
2125
2889
|
function toLabel(value) {
|
|
2126
2890
|
if (value === void 0) {
|
|
@@ -2190,6 +2954,8 @@ function isValidEdgeId(value) {
|
|
|
2190
2954
|
var directionSchema = z.enum(["TB", "LR", "BT", "RL"]);
|
|
2191
2955
|
var routeKindSchema = z.enum(["orthogonal", "straight"]);
|
|
2192
2956
|
var outputFormatSchema = z.enum(["svg", "excalidraw"]);
|
|
2957
|
+
var edgeStrokeStyleSchema = z.enum(["solid", "dashed"]);
|
|
2958
|
+
var edgeArrowheadSchema = z.enum(["triangle", "hollowTriangle"]);
|
|
2193
2959
|
var nodeShapeSchema = z.enum([
|
|
2194
2960
|
"rectangle",
|
|
2195
2961
|
"rounded-rectangle",
|
|
@@ -2217,18 +2983,49 @@ var labelSchema = z.union([
|
|
|
2217
2983
|
maxWidth: finiteNumberSchema.optional()
|
|
2218
2984
|
})
|
|
2219
2985
|
]);
|
|
2986
|
+
var styleSchema = z.object({
|
|
2987
|
+
fill: z.string().optional(),
|
|
2988
|
+
stroke: z.string().optional()
|
|
2989
|
+
});
|
|
2990
|
+
var portSideSchema = z.enum(["top", "right", "bottom", "left"]);
|
|
2991
|
+
var portKindSchema = z.enum(["proxy", "flow"]);
|
|
2992
|
+
var portSchema = z.object({
|
|
2993
|
+
label: labelSchema.optional(),
|
|
2994
|
+
side: portSideSchema,
|
|
2995
|
+
kind: portKindSchema.optional(),
|
|
2996
|
+
order: finiteNumberSchema.optional(),
|
|
2997
|
+
style: styleSchema.optional()
|
|
2998
|
+
});
|
|
2999
|
+
var compartmentsSchema = z.object({
|
|
3000
|
+
stereotype: z.string().optional(),
|
|
3001
|
+
name: z.string().optional(),
|
|
3002
|
+
properties: z.array(z.record(z.string(), z.string()).or(z.string())).optional(),
|
|
3003
|
+
constraints: z.array(z.string()).optional()
|
|
3004
|
+
});
|
|
2220
3005
|
var nodeSchema = z.object({
|
|
2221
3006
|
label: labelSchema.optional(),
|
|
2222
3007
|
shape: nodeShapeSchema.optional(),
|
|
2223
|
-
position: pointSchema.optional()
|
|
3008
|
+
position: pointSchema.optional(),
|
|
3009
|
+
style: styleSchema.optional(),
|
|
3010
|
+
ports: z.record(z.string(), portSchema).optional(),
|
|
3011
|
+
compartments: compartmentsSchema.optional()
|
|
2224
3012
|
});
|
|
3013
|
+
var endpointSchema = z.union([
|
|
3014
|
+
z.string(),
|
|
3015
|
+
z.object({
|
|
3016
|
+
node: z.string(),
|
|
3017
|
+
port: z.string().optional()
|
|
3018
|
+
})
|
|
3019
|
+
]);
|
|
2225
3020
|
var structuredEdgeSchema = z.object({
|
|
2226
3021
|
id: z.string().optional(),
|
|
2227
|
-
source:
|
|
2228
|
-
target:
|
|
3022
|
+
source: endpointSchema.optional(),
|
|
3023
|
+
target: endpointSchema.optional(),
|
|
2229
3024
|
sourceId: z.string().optional(),
|
|
2230
3025
|
targetId: z.string().optional(),
|
|
2231
|
-
label: labelSchema.optional()
|
|
3026
|
+
label: labelSchema.optional(),
|
|
3027
|
+
style: edgeStrokeStyleSchema.optional(),
|
|
3028
|
+
arrowhead: edgeArrowheadSchema.optional()
|
|
2232
3029
|
}).superRefine((edge, context) => {
|
|
2233
3030
|
if (edge.source === void 0 && edge.sourceId === void 0) {
|
|
2234
3031
|
context.addIssue({
|
|
@@ -2252,6 +3049,17 @@ var groupSchema = z.object({
|
|
|
2252
3049
|
groups: z.array(z.string()).optional(),
|
|
2253
3050
|
padding: insetsSchema.optional()
|
|
2254
3051
|
});
|
|
3052
|
+
var swimlaneSchema = z.object({
|
|
3053
|
+
label: labelSchema.optional(),
|
|
3054
|
+
orientation: z.enum(["vertical", "horizontal"]).optional(),
|
|
3055
|
+
lanes: z.record(
|
|
3056
|
+
z.string(),
|
|
3057
|
+
z.object({
|
|
3058
|
+
label: labelSchema.optional(),
|
|
3059
|
+
children: z.array(z.string()).optional()
|
|
3060
|
+
})
|
|
3061
|
+
)
|
|
3062
|
+
});
|
|
2255
3063
|
var exactPositionConstraintSchema = z.object({
|
|
2256
3064
|
kind: z.literal("exact-position"),
|
|
2257
3065
|
target: z.string().optional(),
|
|
@@ -2312,12 +3120,24 @@ var diagramDslSchema = z.object({
|
|
|
2312
3120
|
direction: directionSchema.optional()
|
|
2313
3121
|
}).optional(),
|
|
2314
3122
|
routing: z.object({
|
|
2315
|
-
kind: routeKindSchema.optional()
|
|
3123
|
+
kind: routeKindSchema.optional(),
|
|
3124
|
+
portShifting: z.object({
|
|
3125
|
+
enabled: z.boolean().optional(),
|
|
3126
|
+
spacing: finiteNumberSchema.optional()
|
|
3127
|
+
}).optional()
|
|
2316
3128
|
}).optional(),
|
|
2317
3129
|
nodes: z.record(z.string(), nodeSchema),
|
|
2318
3130
|
edges: z.array(edgeSchema).optional(),
|
|
2319
3131
|
groups: z.record(z.string(), groupSchema).optional(),
|
|
3132
|
+
swimlanes: z.record(z.string(), swimlaneSchema).optional(),
|
|
2320
3133
|
constraints: z.array(constraintSchema).optional(),
|
|
3134
|
+
frame: z.object({
|
|
3135
|
+
kind: z.string(),
|
|
3136
|
+
context: z.string().optional(),
|
|
3137
|
+
name: z.string().optional(),
|
|
3138
|
+
titleTab: z.string(),
|
|
3139
|
+
style: styleSchema.optional()
|
|
3140
|
+
}).optional(),
|
|
2321
3141
|
output: z.object({
|
|
2322
3142
|
format: outputFormatSchema.optional()
|
|
2323
3143
|
}).optional()
|
|
@@ -2514,7 +3334,8 @@ function renderDiagramDsl(source, options = {}) {
|
|
|
2514
3334
|
return { diagnostics };
|
|
2515
3335
|
}
|
|
2516
3336
|
const solved = solveDiagram(normalized.diagram, {
|
|
2517
|
-
routeKind: normalized.diagram.metadata?.routeKind === "straight" ? "straight" : "orthogonal"
|
|
3337
|
+
routeKind: normalized.diagram.metadata?.routeKind === "straight" ? "straight" : "orthogonal",
|
|
3338
|
+
...solvePortShiftingOption(normalized.diagram.metadata?.portShifting)
|
|
2518
3339
|
});
|
|
2519
3340
|
const solveDiagnostics = solved.diagnostics.map(toSolveDiagnostic);
|
|
2520
3341
|
if (hasErrorDiagnostics2(solveDiagnostics)) {
|
|
@@ -2553,6 +3374,22 @@ function renderDiagramDsl(source, options = {}) {
|
|
|
2553
3374
|
function toSolveDiagnostic(diagnostic) {
|
|
2554
3375
|
return { ...diagnostic, layer: "solve" };
|
|
2555
3376
|
}
|
|
3377
|
+
function solvePortShiftingOption(value) {
|
|
3378
|
+
if (!isJsonObject(value)) {
|
|
3379
|
+
return {};
|
|
3380
|
+
}
|
|
3381
|
+
const portShifting = {};
|
|
3382
|
+
if (value.enabled === false) {
|
|
3383
|
+
portShifting.enabled = false;
|
|
3384
|
+
}
|
|
3385
|
+
if (typeof value.spacing === "number") {
|
|
3386
|
+
portShifting.spacing = value.spacing;
|
|
3387
|
+
}
|
|
3388
|
+
return { portShifting };
|
|
3389
|
+
}
|
|
3390
|
+
function isJsonObject(value) {
|
|
3391
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3392
|
+
}
|
|
2556
3393
|
function toExportDiagnostic(diagnostic) {
|
|
2557
3394
|
return { ...diagnostic, layer: "export" };
|
|
2558
3395
|
}
|