@crazyhappyone/auto-graph 0.0.1 → 0.0.2
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 +910 -66
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +909 -66
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +849 -73
- 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 +847 -74
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/cli/index.cjs
CHANGED
|
@@ -3,12 +3,15 @@
|
|
|
3
3
|
|
|
4
4
|
var commander = require('commander');
|
|
5
5
|
var dagre = require('@dagrejs/dagre');
|
|
6
|
+
var module$1 = require('module');
|
|
7
|
+
var pretext = require('@chenglou/pretext');
|
|
6
8
|
var buffer = require('buffer');
|
|
7
9
|
var yaml = require('yaml');
|
|
8
10
|
var zod = require('zod');
|
|
9
11
|
var promises = require('fs/promises');
|
|
10
12
|
var path = require('path');
|
|
11
13
|
|
|
14
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
12
15
|
// src/dsl/diagnostics.ts
|
|
13
16
|
var SEVERITY_RANK = /* @__PURE__ */ new Map([
|
|
14
17
|
["error", 0],
|
|
@@ -196,11 +199,12 @@ function renderArrow(edge) {
|
|
|
196
199
|
height: box.height
|
|
197
200
|
}),
|
|
198
201
|
backgroundColor: "transparent",
|
|
202
|
+
strokeStyle: edge.style ?? "solid",
|
|
199
203
|
points: relativePoints,
|
|
200
204
|
startBinding: { elementId: `node:${edge.source.nodeId}`, focus: 0, gap: 0 },
|
|
201
205
|
endBinding: { elementId: `node:${edge.target.nodeId}`, focus: 0, gap: 0 },
|
|
202
206
|
startArrowhead: null,
|
|
203
|
-
endArrowhead:
|
|
207
|
+
endArrowhead: mapArrowhead(edge.arrowhead)
|
|
204
208
|
};
|
|
205
209
|
}
|
|
206
210
|
function renderText(id, label, box, containerId, groupIds) {
|
|
@@ -278,6 +282,16 @@ function mapShape(shape) {
|
|
|
278
282
|
return "cylinder";
|
|
279
283
|
}
|
|
280
284
|
}
|
|
285
|
+
function mapArrowhead(arrowhead) {
|
|
286
|
+
switch (arrowhead) {
|
|
287
|
+
case void 0:
|
|
288
|
+
return "arrow";
|
|
289
|
+
case "triangle":
|
|
290
|
+
return "triangle";
|
|
291
|
+
case "hollowTriangle":
|
|
292
|
+
return "triangle_outline";
|
|
293
|
+
}
|
|
294
|
+
}
|
|
281
295
|
function createGroupMembership(groups) {
|
|
282
296
|
const membership = /* @__PURE__ */ new Map();
|
|
283
297
|
for (const group of groups) {
|
|
@@ -344,19 +358,28 @@ function exportSvg(diagram, options = {}) {
|
|
|
344
358
|
`<svg xmlns="http://www.w3.org/2000/svg" role="img" viewBox="${formatBoxViewBox(diagram.bounds)}">`,
|
|
345
359
|
...title === void 0 ? [] : [` <title>${escapeXml(title)}</title>`],
|
|
346
360
|
` <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"/>`,
|
|
361
|
+
...diagram.frame === void 0 ? [] : [indent(renderFrame(diagram.frame))],
|
|
362
|
+
...(diagram.swimlanes ?? []).flatMap(
|
|
363
|
+
(swimlane) => renderSwimlane(swimlane)
|
|
364
|
+
),
|
|
347
365
|
...diagram.groups.map((group) => indent(renderGroup2(group))),
|
|
348
366
|
...diagram.edges.flatMap((edge) => {
|
|
349
|
-
const path = renderEdgePath(edge
|
|
367
|
+
const path = renderEdgePath(edge);
|
|
350
368
|
if (path === void 0) {
|
|
351
369
|
return [];
|
|
352
370
|
}
|
|
353
|
-
return [indent(path), indent(renderArrowhead(edge
|
|
371
|
+
return [indent(path), indent(renderArrowhead(edge))];
|
|
354
372
|
}),
|
|
355
373
|
...diagram.nodes.map((node) => indent(renderNode2(node))),
|
|
374
|
+
...diagram.nodes.flatMap((node) => renderCompartments(node)),
|
|
375
|
+
...diagram.nodes.flatMap((node) => renderPorts(node)),
|
|
356
376
|
...diagram.groups.flatMap(
|
|
357
377
|
(group) => renderLabel(group.label, group.box, group)
|
|
358
378
|
),
|
|
359
|
-
...diagram.nodes.flatMap(
|
|
379
|
+
...diagram.nodes.flatMap(
|
|
380
|
+
(node) => node.compartments === void 0 ? renderLabel(node.label, node.box, node) : []
|
|
381
|
+
),
|
|
382
|
+
...diagram.edges.flatMap((edge) => renderEdgeLabel(edge)),
|
|
360
383
|
"</svg>"
|
|
361
384
|
];
|
|
362
385
|
return `${lines.join("\n")}
|
|
@@ -366,7 +389,9 @@ function renderGroup2(group) {
|
|
|
366
389
|
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"/>`;
|
|
367
390
|
}
|
|
368
391
|
function renderNode2(node) {
|
|
369
|
-
const
|
|
392
|
+
const fill = node.style?.fill ?? NODE_FILL;
|
|
393
|
+
const stroke = node.style?.stroke ?? STROKE;
|
|
394
|
+
const common = `class="node node-${node.shape}" data-id="${escapeAttribute(node.id)}" fill="${escapeAttribute(fill)}" stroke="${escapeAttribute(stroke)}"`;
|
|
370
395
|
switch (node.shape) {
|
|
371
396
|
case "rectangle":
|
|
372
397
|
return renderRect(node.box, common);
|
|
@@ -382,16 +407,111 @@ function renderNode2(node) {
|
|
|
382
407
|
return `<path ${common} d="${formatCylinderPath(node.box)}"/>`;
|
|
383
408
|
}
|
|
384
409
|
}
|
|
410
|
+
function renderFrame(frame) {
|
|
411
|
+
const stroke = frame.style?.stroke ?? "#6b7280";
|
|
412
|
+
const fill = frame.style?.fill ?? "transparent";
|
|
413
|
+
return [
|
|
414
|
+
`<g class="sysml-frame" data-kind="${escapeAttribute(frame.kind)}">`,
|
|
415
|
+
` <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)}"/>`,
|
|
416
|
+
` <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)}"/>`,
|
|
417
|
+
` <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>`,
|
|
418
|
+
"</g>"
|
|
419
|
+
].join("\n");
|
|
420
|
+
}
|
|
421
|
+
function renderSwimlane(swimlane) {
|
|
422
|
+
if (swimlane.box === void 0) {
|
|
423
|
+
return [];
|
|
424
|
+
}
|
|
425
|
+
const lines = [
|
|
426
|
+
` <g class="swimlane" data-id="${escapeAttribute(swimlane.id)}">`,
|
|
427
|
+
` <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}"/>`
|
|
428
|
+
];
|
|
429
|
+
for (const lane of swimlane.lanes) {
|
|
430
|
+
if (lane.box === void 0) {
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
lines.push(
|
|
434
|
+
` <rect class="swimlane-lane" data-lane="${escapeAttribute(`${swimlane.id}.${lane.id}`)}" x="${formatNumber(lane.box.x)}" y="${formatNumber(lane.box.y)}" width="${formatNumber(lane.box.width)}" height="${formatNumber(lane.box.height)}" fill="none" stroke="${STROKE}"/>`
|
|
435
|
+
);
|
|
436
|
+
if (lane.label?.text !== void 0) {
|
|
437
|
+
lines.push(
|
|
438
|
+
` <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>`
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
lines.push(" </g>");
|
|
443
|
+
return lines;
|
|
444
|
+
}
|
|
445
|
+
function renderPorts(node) {
|
|
446
|
+
return (node.ports ?? []).flatMap((port) => [
|
|
447
|
+
` <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)}"/>`,
|
|
448
|
+
...port.label?.text === void 0 ? [] : [
|
|
449
|
+
` <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>`
|
|
450
|
+
]
|
|
451
|
+
]);
|
|
452
|
+
}
|
|
453
|
+
function renderCompartments(node) {
|
|
454
|
+
const compartments2 = node.compartments;
|
|
455
|
+
if (compartments2 === void 0) {
|
|
456
|
+
return [];
|
|
457
|
+
}
|
|
458
|
+
const rows = [
|
|
459
|
+
...compartments2.stereotype === void 0 ? [] : [{ className: "stereotype", text: compartments2.stereotype }],
|
|
460
|
+
{
|
|
461
|
+
className: "name",
|
|
462
|
+
text: compartments2.name ?? node.label?.text ?? node.id
|
|
463
|
+
},
|
|
464
|
+
...(compartments2.properties ?? []).map((text) => ({
|
|
465
|
+
className: "properties",
|
|
466
|
+
text
|
|
467
|
+
})),
|
|
468
|
+
...(compartments2.constraints ?? []).map((text) => ({
|
|
469
|
+
className: "constraints",
|
|
470
|
+
text
|
|
471
|
+
}))
|
|
472
|
+
];
|
|
473
|
+
const lineHeight = 16;
|
|
474
|
+
const lines = [
|
|
475
|
+
` <g class="compartment" data-for="${escapeAttribute(node.id)}">`
|
|
476
|
+
];
|
|
477
|
+
for (let index = 0; index < rows.length; index += 1) {
|
|
478
|
+
const row = rows[index];
|
|
479
|
+
if (row === void 0) {
|
|
480
|
+
continue;
|
|
481
|
+
}
|
|
482
|
+
const y = node.box.y + 18 + index * lineHeight;
|
|
483
|
+
if (index > 1) {
|
|
484
|
+
lines.push(
|
|
485
|
+
` <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}"/>`
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
lines.push(
|
|
489
|
+
` <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>`
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
lines.push(" </g>");
|
|
493
|
+
return lines;
|
|
494
|
+
}
|
|
495
|
+
function portLabelX(x, side) {
|
|
496
|
+
if (side === "left") {
|
|
497
|
+
return x - 8;
|
|
498
|
+
}
|
|
499
|
+
if (side === "right") {
|
|
500
|
+
return x + 8;
|
|
501
|
+
}
|
|
502
|
+
return x + 8;
|
|
503
|
+
}
|
|
385
504
|
function renderRect(box, attributes) {
|
|
386
505
|
return `<rect ${attributes} x="${formatNumber(box.x)}" y="${formatNumber(box.y)}" width="${formatNumber(box.width)}" height="${formatNumber(box.height)}"/>`;
|
|
387
506
|
}
|
|
388
507
|
function renderLabel(label, box, item) {
|
|
389
508
|
const labelLayout = item.labelLayout;
|
|
390
509
|
if (labelLayout?.lines !== void 0 && labelLayout.lines.length > 0) {
|
|
510
|
+
const offset = isAbsoluteLabelLayout(labelLayout.box, box) ? { x: 0, y: 0 } : { x: box.x, y: box.y };
|
|
391
511
|
return [
|
|
392
512
|
` <text class="label" data-for="${escapeAttribute(item.id)}" font-family="${FONT_FAMILY}" font-size="${formatNumber(labelLayout.font.fontSize)}" fill="#111827">`,
|
|
393
513
|
...labelLayout.lines.map(
|
|
394
|
-
(line) => ` <tspan x="${formatNumber(line.box.x)}" y="${formatNumber(line.baselineY)}">${escapeXml(line.text)}</tspan>`
|
|
514
|
+
(line) => ` <tspan x="${formatNumber(offset.x + line.box.x)}" y="${formatNumber(offset.y + line.baselineY)}">${escapeXml(line.text)}</tspan>`
|
|
395
515
|
),
|
|
396
516
|
" </text>"
|
|
397
517
|
];
|
|
@@ -403,15 +523,91 @@ function renderLabel(label, box, item) {
|
|
|
403
523
|
` <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>`
|
|
404
524
|
];
|
|
405
525
|
}
|
|
406
|
-
function renderEdgePath(
|
|
407
|
-
if (points.length < 2) {
|
|
526
|
+
function renderEdgePath(edge) {
|
|
527
|
+
if (edge.points.length < 2) {
|
|
528
|
+
return void 0;
|
|
529
|
+
}
|
|
530
|
+
const dash = edge.style === "dashed" ? ' stroke-dasharray="6 4"' : "";
|
|
531
|
+
return `<path class="edge" data-id="${escapeAttribute(edge.id)}" d="${formatPath(pathPointsBeforeArrowhead(edge.points))}" fill="none" stroke="${EDGE_STROKE}" stroke-width="1.5"${dash}/>`;
|
|
532
|
+
}
|
|
533
|
+
function renderEdgeLabel(edge) {
|
|
534
|
+
if (edge.label?.text === void 0 || edge.points.length < 2) {
|
|
535
|
+
return [];
|
|
536
|
+
}
|
|
537
|
+
const placement = labelPlacementOnPolyline(edge.points);
|
|
538
|
+
if (placement === void 0) {
|
|
539
|
+
return [];
|
|
540
|
+
}
|
|
541
|
+
return [
|
|
542
|
+
` <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>`
|
|
543
|
+
];
|
|
544
|
+
}
|
|
545
|
+
function renderArrowhead(edge) {
|
|
546
|
+
const arrowhead = computeArrowhead(edge.points);
|
|
547
|
+
const fill = edge.arrowhead === "hollowTriangle" ? "none" : EDGE_STROKE;
|
|
548
|
+
return `<polygon class="edge-arrowhead" data-edge="${escapeAttribute(edge.id)}" points="${formatPoints([arrowhead.tip, arrowhead.left, arrowhead.right])}" fill="${fill}" stroke="${EDGE_STROKE}"/>`;
|
|
549
|
+
}
|
|
550
|
+
function labelPlacementOnPolyline(points) {
|
|
551
|
+
const segments = nonZeroSegments(points);
|
|
552
|
+
const totalLength = segments.reduce(
|
|
553
|
+
(sum, segment) => sum + segment.length,
|
|
554
|
+
0
|
|
555
|
+
);
|
|
556
|
+
if (totalLength <= 0) {
|
|
408
557
|
return void 0;
|
|
409
558
|
}
|
|
410
|
-
|
|
559
|
+
let remaining = totalLength / 2;
|
|
560
|
+
for (const segment of segments) {
|
|
561
|
+
if (remaining <= segment.length) {
|
|
562
|
+
const ratio = remaining / segment.length;
|
|
563
|
+
const x = segment.start.x + (segment.end.x - segment.start.x) * ratio;
|
|
564
|
+
const y = segment.start.y + (segment.end.y - segment.start.y) * ratio;
|
|
565
|
+
const offset2 = labelOffset(segment);
|
|
566
|
+
return { x: x + offset2.x, y: y + offset2.y };
|
|
567
|
+
}
|
|
568
|
+
remaining -= segment.length;
|
|
569
|
+
}
|
|
570
|
+
const last = segments.at(-1);
|
|
571
|
+
if (last === void 0) {
|
|
572
|
+
return void 0;
|
|
573
|
+
}
|
|
574
|
+
const offset = labelOffset(last);
|
|
575
|
+
return { x: last.end.x + offset.x, y: last.end.y + offset.y };
|
|
576
|
+
}
|
|
577
|
+
function nonZeroSegments(points) {
|
|
578
|
+
const segments = [];
|
|
579
|
+
for (let index = 0; index < points.length - 1; index += 1) {
|
|
580
|
+
const start = points[index];
|
|
581
|
+
const end = points[index + 1];
|
|
582
|
+
if (start === void 0 || end === void 0) {
|
|
583
|
+
continue;
|
|
584
|
+
}
|
|
585
|
+
const length = Math.hypot(end.x - start.x, end.y - start.y);
|
|
586
|
+
if (length > 0) {
|
|
587
|
+
segments.push({ start, end, length });
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
return segments;
|
|
411
591
|
}
|
|
412
|
-
function
|
|
592
|
+
function labelOffset(segment) {
|
|
593
|
+
const offset = 10;
|
|
594
|
+
const dx = segment.end.x - segment.start.x;
|
|
595
|
+
const dy = segment.end.y - segment.start.y;
|
|
596
|
+
return {
|
|
597
|
+
x: -dy / segment.length * offset,
|
|
598
|
+
y: dx / segment.length * offset
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
function pathPointsBeforeArrowhead(points) {
|
|
413
602
|
const arrowhead = computeArrowhead(points);
|
|
414
|
-
|
|
603
|
+
const base = {
|
|
604
|
+
x: (arrowhead.left.x + arrowhead.right.x) / 2,
|
|
605
|
+
y: (arrowhead.left.y + arrowhead.right.y) / 2
|
|
606
|
+
};
|
|
607
|
+
return [...points.slice(0, -1), base];
|
|
608
|
+
}
|
|
609
|
+
function isAbsoluteLabelLayout(labelBox, itemBox) {
|
|
610
|
+
return labelBox.x >= itemBox.x && labelBox.y >= itemBox.y && labelBox.x + labelBox.width <= itemBox.x + itemBox.width && labelBox.y + labelBox.height <= itemBox.y + itemBox.height;
|
|
415
611
|
}
|
|
416
612
|
function shapePoints(shape, box) {
|
|
417
613
|
const left = box.x;
|
|
@@ -1296,20 +1492,33 @@ function isValidDimension(value) {
|
|
|
1296
1492
|
// src/routing/routes.ts
|
|
1297
1493
|
function routeEdge(input) {
|
|
1298
1494
|
const diagnostics = [];
|
|
1495
|
+
const defaultAnchors = defaultAnchorsForGeometry(
|
|
1496
|
+
input.source.box,
|
|
1497
|
+
input.target.box,
|
|
1498
|
+
input.direction
|
|
1499
|
+
);
|
|
1299
1500
|
const source = getEdgePort(
|
|
1300
1501
|
input.source,
|
|
1301
1502
|
input.target.center,
|
|
1302
|
-
input.sourceAnchor
|
|
1503
|
+
input.sourceAnchor ?? defaultAnchors.sourceAnchor
|
|
1303
1504
|
);
|
|
1304
1505
|
const target = getEdgePort(
|
|
1305
1506
|
input.target,
|
|
1306
1507
|
input.source.center,
|
|
1307
|
-
input.targetAnchor
|
|
1508
|
+
input.targetAnchor ?? defaultAnchors.targetAnchor
|
|
1308
1509
|
);
|
|
1309
1510
|
if ((input.kind ?? "orthogonal") === "straight") {
|
|
1310
1511
|
return { points: simplifyRoute([source, target]), diagnostics };
|
|
1311
1512
|
}
|
|
1312
1513
|
const candidates = orthogonalCandidates(source, target, input.direction);
|
|
1514
|
+
candidates.push(
|
|
1515
|
+
...expandedObstacleCandidates(
|
|
1516
|
+
source,
|
|
1517
|
+
target,
|
|
1518
|
+
input.direction,
|
|
1519
|
+
input.obstacles ?? []
|
|
1520
|
+
)
|
|
1521
|
+
);
|
|
1313
1522
|
for (const candidate of candidates) {
|
|
1314
1523
|
if (!routeIntersectsObstacles(candidate, input.obstacles ?? [])) {
|
|
1315
1524
|
return { points: simplifyRoute(candidate), diagnostics };
|
|
@@ -1348,27 +1557,113 @@ function simplifyRoute(points) {
|
|
|
1348
1557
|
function orthogonalCandidates(source, target, direction) {
|
|
1349
1558
|
const midpointX = (source.x + target.x) / 2;
|
|
1350
1559
|
const midpointY = (source.y + target.y) / 2;
|
|
1351
|
-
const candidates = [
|
|
1352
|
-
[source, { x: target.x, y: source.y }, target],
|
|
1353
|
-
[source, { x: source.x, y: target.y }, target]
|
|
1354
|
-
];
|
|
1560
|
+
const candidates = [];
|
|
1355
1561
|
if (direction === "TB" || direction === "BT") {
|
|
1356
1562
|
candidates.push([
|
|
1357
1563
|
source,
|
|
1358
|
-
{ x:
|
|
1359
|
-
{ x:
|
|
1564
|
+
{ x: source.x, y: midpointY },
|
|
1565
|
+
{ x: target.x, y: midpointY },
|
|
1360
1566
|
target
|
|
1361
1567
|
]);
|
|
1362
1568
|
} else {
|
|
1363
1569
|
candidates.push([
|
|
1364
1570
|
source,
|
|
1365
|
-
{ x:
|
|
1366
|
-
{ x:
|
|
1571
|
+
{ x: midpointX, y: source.y },
|
|
1572
|
+
{ x: midpointX, y: target.y },
|
|
1367
1573
|
target
|
|
1368
1574
|
]);
|
|
1369
1575
|
}
|
|
1576
|
+
candidates.push(
|
|
1577
|
+
[source, { x: target.x, y: source.y }, target],
|
|
1578
|
+
[source, { x: source.x, y: target.y }, target]
|
|
1579
|
+
);
|
|
1580
|
+
return candidates;
|
|
1581
|
+
}
|
|
1582
|
+
function defaultSourceAnchor(direction) {
|
|
1583
|
+
switch (direction) {
|
|
1584
|
+
case "LR":
|
|
1585
|
+
return "right";
|
|
1586
|
+
case "RL":
|
|
1587
|
+
return "left";
|
|
1588
|
+
case "TB":
|
|
1589
|
+
return "bottom";
|
|
1590
|
+
case "BT":
|
|
1591
|
+
return "top";
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
function defaultAnchorsForGeometry(source, target, direction) {
|
|
1595
|
+
const dx = target.x + target.width / 2 - (source.x + source.width / 2);
|
|
1596
|
+
const dy = target.y + target.height / 2 - (source.y + source.height / 2);
|
|
1597
|
+
if (Math.abs(dy) > Math.abs(dx)) {
|
|
1598
|
+
return dy >= 0 ? { sourceAnchor: "bottom", targetAnchor: "top" } : { sourceAnchor: "top", targetAnchor: "bottom" };
|
|
1599
|
+
}
|
|
1600
|
+
if (Math.abs(dx) > 0) {
|
|
1601
|
+
return dx >= 0 ? { sourceAnchor: "right", targetAnchor: "left" } : { sourceAnchor: "left", targetAnchor: "right" };
|
|
1602
|
+
}
|
|
1603
|
+
return {
|
|
1604
|
+
sourceAnchor: defaultSourceAnchor(direction),
|
|
1605
|
+
targetAnchor: defaultTargetAnchor(direction)
|
|
1606
|
+
};
|
|
1607
|
+
}
|
|
1608
|
+
function defaultTargetAnchor(direction) {
|
|
1609
|
+
switch (direction) {
|
|
1610
|
+
case "LR":
|
|
1611
|
+
return "left";
|
|
1612
|
+
case "RL":
|
|
1613
|
+
return "right";
|
|
1614
|
+
case "TB":
|
|
1615
|
+
return "top";
|
|
1616
|
+
case "BT":
|
|
1617
|
+
return "bottom";
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
function expandedObstacleCandidates(source, target, direction, obstacles) {
|
|
1621
|
+
if (obstacles.length === 0) {
|
|
1622
|
+
return [];
|
|
1623
|
+
}
|
|
1624
|
+
const margin = 16;
|
|
1625
|
+
const candidates = [];
|
|
1626
|
+
if (direction === "TB" || direction === "BT") {
|
|
1627
|
+
const lanes = sortedUniqueLanes(
|
|
1628
|
+
obstacles.flatMap((obstacle) => [
|
|
1629
|
+
obstacle.x - margin,
|
|
1630
|
+
obstacle.x + obstacle.width + margin
|
|
1631
|
+
]),
|
|
1632
|
+
(source.x + target.x) / 2
|
|
1633
|
+
);
|
|
1634
|
+
for (const laneX of lanes) {
|
|
1635
|
+
candidates.push([
|
|
1636
|
+
source,
|
|
1637
|
+
{ x: laneX, y: source.y },
|
|
1638
|
+
{ x: laneX, y: target.y },
|
|
1639
|
+
target
|
|
1640
|
+
]);
|
|
1641
|
+
}
|
|
1642
|
+
} else {
|
|
1643
|
+
const lanes = sortedUniqueLanes(
|
|
1644
|
+
obstacles.flatMap((obstacle) => [
|
|
1645
|
+
obstacle.y - margin,
|
|
1646
|
+
obstacle.y + obstacle.height + margin
|
|
1647
|
+
]),
|
|
1648
|
+
(source.y + target.y) / 2
|
|
1649
|
+
);
|
|
1650
|
+
for (const laneY of lanes) {
|
|
1651
|
+
candidates.push([
|
|
1652
|
+
source,
|
|
1653
|
+
{ x: source.x, y: laneY },
|
|
1654
|
+
{ x: target.x, y: laneY },
|
|
1655
|
+
target
|
|
1656
|
+
]);
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1370
1659
|
return candidates;
|
|
1371
1660
|
}
|
|
1661
|
+
function sortedUniqueLanes(lanes, midpoint) {
|
|
1662
|
+
return [...new Set(lanes)].filter((lane) => Number.isFinite(lane)).sort((left, right) => {
|
|
1663
|
+
const distance = Math.abs(left - midpoint) - Math.abs(right - midpoint);
|
|
1664
|
+
return distance === 0 ? left - right : distance;
|
|
1665
|
+
});
|
|
1666
|
+
}
|
|
1372
1667
|
function routeIntersectsObstacles(points, obstacles) {
|
|
1373
1668
|
for (let index = 0; index < points.length - 1; index += 1) {
|
|
1374
1669
|
const a = points[index];
|
|
@@ -1447,12 +1742,17 @@ function solveDiagram(diagram, options = {}) {
|
|
|
1447
1742
|
options,
|
|
1448
1743
|
diagnostics
|
|
1449
1744
|
);
|
|
1745
|
+
const coordinatedSwimlanes = coordinateSwimlanes(
|
|
1746
|
+
diagram.swimlanes ?? [],
|
|
1747
|
+
constrained.boxes
|
|
1748
|
+
);
|
|
1450
1749
|
const groupBoxes = new Map(
|
|
1451
1750
|
coordinatedGroups.map((group) => [group.id, group.box])
|
|
1452
1751
|
);
|
|
1453
1752
|
const coordinatedEdges = coordinateEdges(
|
|
1454
1753
|
edges,
|
|
1455
1754
|
nodeGeometryById,
|
|
1755
|
+
coordinatedNodes,
|
|
1456
1756
|
[...nodeGeometryById.values()].map((geometry) => geometry.obstacleBox),
|
|
1457
1757
|
diagram.direction,
|
|
1458
1758
|
options,
|
|
@@ -1460,8 +1760,18 @@ function solveDiagram(diagram, options = {}) {
|
|
|
1460
1760
|
);
|
|
1461
1761
|
const allBoxes = [
|
|
1462
1762
|
...coordinatedNodes.map((node) => node.box),
|
|
1463
|
-
...
|
|
1763
|
+
...coordinatedNodes.flatMap(
|
|
1764
|
+
(node) => (node.ports ?? []).flatMap(
|
|
1765
|
+
(port) => port.label === void 0 ? [port.box] : [port.box, portLabelBox(port)]
|
|
1766
|
+
)
|
|
1767
|
+
),
|
|
1768
|
+
...groupBoxes.values(),
|
|
1769
|
+
...coordinatedSwimlanes.flatMap(
|
|
1770
|
+
(swimlane) => swimlane.box === void 0 ? [] : [swimlane.box]
|
|
1771
|
+
)
|
|
1464
1772
|
];
|
|
1773
|
+
const contentBounds = allBoxes.length === 0 ? { x: 0, y: 0, width: 0, height: 0 } : unionBoxes(allBoxes);
|
|
1774
|
+
const frame = diagram.frame === void 0 ? void 0 : coordinateFrame(diagram.frame, contentBounds);
|
|
1465
1775
|
return {
|
|
1466
1776
|
id: diagram.id,
|
|
1467
1777
|
...diagram.title === void 0 ? {} : { title: diagram.title },
|
|
@@ -1469,8 +1779,10 @@ function solveDiagram(diagram, options = {}) {
|
|
|
1469
1779
|
nodes: coordinatedNodes,
|
|
1470
1780
|
edges: coordinatedEdges,
|
|
1471
1781
|
groups: coordinatedGroups,
|
|
1782
|
+
...coordinatedSwimlanes.length === 0 ? {} : { swimlanes: coordinatedSwimlanes },
|
|
1472
1783
|
diagnostics,
|
|
1473
|
-
bounds:
|
|
1784
|
+
bounds: frame === void 0 ? contentBounds : unionBoxes([contentBounds, frame.box, frame.titleBox]),
|
|
1785
|
+
...frame === void 0 ? {} : { frame },
|
|
1474
1786
|
...diagram.metadata === void 0 ? {} : { metadata: diagram.metadata }
|
|
1475
1787
|
};
|
|
1476
1788
|
}
|
|
@@ -1496,6 +1808,9 @@ function coordinateNodes(nodes, boxes, options, diagnostics) {
|
|
|
1496
1808
|
coordinated.push({
|
|
1497
1809
|
id: node.id,
|
|
1498
1810
|
...node.label === void 0 ? {} : { label: node.label },
|
|
1811
|
+
...node.style === void 0 ? {} : { style: node.style },
|
|
1812
|
+
...node.ports === void 0 ? {} : { ports: coordinatePorts(node, box, options.portShifting) },
|
|
1813
|
+
...node.compartments === void 0 ? {} : { compartments: node.compartments },
|
|
1499
1814
|
...node.labelLayout === void 0 ? {} : { labelLayout: node.labelLayout },
|
|
1500
1815
|
shape: node.shape,
|
|
1501
1816
|
...node.metadata === void 0 ? {} : { metadata: node.metadata },
|
|
@@ -1506,6 +1821,142 @@ function coordinateNodes(nodes, boxes, options, diagnostics) {
|
|
|
1506
1821
|
}
|
|
1507
1822
|
return coordinated;
|
|
1508
1823
|
}
|
|
1824
|
+
function coordinatePorts(node, nodeBox, portShifting) {
|
|
1825
|
+
const portsBySide = /* @__PURE__ */ new Map();
|
|
1826
|
+
for (const port of node.ports ?? []) {
|
|
1827
|
+
const ports = portsBySide.get(port.side) ?? [];
|
|
1828
|
+
ports.push(port);
|
|
1829
|
+
portsBySide.set(port.side, ports);
|
|
1830
|
+
}
|
|
1831
|
+
const coordinated = [];
|
|
1832
|
+
for (const [side, ports] of portsBySide) {
|
|
1833
|
+
const sorted = [...ports ?? []].sort((a, b) => {
|
|
1834
|
+
const order = (a.order ?? 0) - (b.order ?? 0);
|
|
1835
|
+
return order === 0 ? a.id.localeCompare(b.id) : order;
|
|
1836
|
+
});
|
|
1837
|
+
for (let index = 0; index < sorted.length; index += 1) {
|
|
1838
|
+
const port = sorted[index];
|
|
1839
|
+
if (port === void 0) {
|
|
1840
|
+
continue;
|
|
1841
|
+
}
|
|
1842
|
+
const anchor = portAnchor(
|
|
1843
|
+
nodeBox,
|
|
1844
|
+
side,
|
|
1845
|
+
index,
|
|
1846
|
+
sorted.length,
|
|
1847
|
+
portShifting
|
|
1848
|
+
);
|
|
1849
|
+
const box = portBox(anchor);
|
|
1850
|
+
coordinated.push({ ...port, box, anchor });
|
|
1851
|
+
}
|
|
1852
|
+
}
|
|
1853
|
+
return coordinated.sort((a, b) => a.id.localeCompare(b.id));
|
|
1854
|
+
}
|
|
1855
|
+
function portAnchor(nodeBox, side, index, count, portShifting) {
|
|
1856
|
+
const shiftingEnabled = portShifting?.enabled ?? true;
|
|
1857
|
+
const spacing = portShifting?.spacing ?? 24;
|
|
1858
|
+
const centeredOffset = shiftingEnabled ? (index - (count - 1) / 2) * spacing : 0;
|
|
1859
|
+
switch (side) {
|
|
1860
|
+
case "left":
|
|
1861
|
+
return {
|
|
1862
|
+
x: nodeBox.x,
|
|
1863
|
+
y: nodeBox.y + nodeBox.height / 2 + centeredOffset
|
|
1864
|
+
};
|
|
1865
|
+
case "right":
|
|
1866
|
+
return {
|
|
1867
|
+
x: nodeBox.x + nodeBox.width,
|
|
1868
|
+
y: nodeBox.y + nodeBox.height / 2 + centeredOffset
|
|
1869
|
+
};
|
|
1870
|
+
case "top":
|
|
1871
|
+
return {
|
|
1872
|
+
x: nodeBox.x + nodeBox.width / 2 + centeredOffset,
|
|
1873
|
+
y: nodeBox.y
|
|
1874
|
+
};
|
|
1875
|
+
case "bottom":
|
|
1876
|
+
return {
|
|
1877
|
+
x: nodeBox.x + nodeBox.width / 2 + centeredOffset,
|
|
1878
|
+
y: nodeBox.y + nodeBox.height
|
|
1879
|
+
};
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
function portBox(anchor) {
|
|
1883
|
+
const size = 10;
|
|
1884
|
+
return {
|
|
1885
|
+
x: anchor.x - size / 2,
|
|
1886
|
+
y: anchor.y - size / 2,
|
|
1887
|
+
width: size,
|
|
1888
|
+
height: size
|
|
1889
|
+
};
|
|
1890
|
+
}
|
|
1891
|
+
function portLabelBox(port) {
|
|
1892
|
+
const textWidth = Math.max(0, (port.label?.text.length ?? 0) * 6);
|
|
1893
|
+
const height = 12;
|
|
1894
|
+
const gap = 8;
|
|
1895
|
+
const x = port.side === "left" ? port.anchor.x - gap - textWidth : port.anchor.x + gap;
|
|
1896
|
+
return {
|
|
1897
|
+
x,
|
|
1898
|
+
y: port.anchor.y - 8 - height,
|
|
1899
|
+
width: textWidth,
|
|
1900
|
+
height
|
|
1901
|
+
};
|
|
1902
|
+
}
|
|
1903
|
+
function coordinateSwimlanes(swimlanes, nodeBoxes) {
|
|
1904
|
+
const titleSize = 28;
|
|
1905
|
+
const padding = 16;
|
|
1906
|
+
return swimlanes.map((swimlane) => {
|
|
1907
|
+
const laneBoxes = swimlane.lanes.flatMap((lane) => {
|
|
1908
|
+
const childBoxes = lane.children.map((child) => nodeBoxes.get(child)).filter((box) => box !== void 0);
|
|
1909
|
+
return childBoxes.length === 0 ? [] : [unionBoxes(childBoxes)];
|
|
1910
|
+
});
|
|
1911
|
+
const laneUnion = laneBoxes.length === 0 ? { x: 0, y: 0, width: 120, height: 80 } : unionBoxes(laneBoxes);
|
|
1912
|
+
const outer = expand(laneUnion, padding, titleSize);
|
|
1913
|
+
const laneCount = Math.max(1, swimlane.lanes.length);
|
|
1914
|
+
const lanes = swimlane.lanes.map((lane, index) => {
|
|
1915
|
+
const box = swimlane.orientation === "vertical" ? {
|
|
1916
|
+
x: outer.x + outer.width / laneCount * index,
|
|
1917
|
+
y: outer.y,
|
|
1918
|
+
width: outer.width / laneCount,
|
|
1919
|
+
height: outer.height
|
|
1920
|
+
} : {
|
|
1921
|
+
x: outer.x,
|
|
1922
|
+
y: outer.y + outer.height / laneCount * index,
|
|
1923
|
+
width: outer.width,
|
|
1924
|
+
height: outer.height / laneCount
|
|
1925
|
+
};
|
|
1926
|
+
return { ...lane, box };
|
|
1927
|
+
});
|
|
1928
|
+
return { ...swimlane, lanes, box: outer };
|
|
1929
|
+
});
|
|
1930
|
+
}
|
|
1931
|
+
function coordinateFrame(frame, contentBounds) {
|
|
1932
|
+
const padding = 32;
|
|
1933
|
+
const titleHeight = 28;
|
|
1934
|
+
const titleWidth = Math.max(180, frame.titleTab.length * 7);
|
|
1935
|
+
const box = {
|
|
1936
|
+
x: contentBounds.x - padding,
|
|
1937
|
+
y: contentBounds.y - padding - titleHeight,
|
|
1938
|
+
width: contentBounds.width + padding * 2,
|
|
1939
|
+
height: contentBounds.height + padding * 2 + titleHeight
|
|
1940
|
+
};
|
|
1941
|
+
return {
|
|
1942
|
+
...frame,
|
|
1943
|
+
box,
|
|
1944
|
+
titleBox: {
|
|
1945
|
+
x: box.x,
|
|
1946
|
+
y: box.y,
|
|
1947
|
+
width: Math.min(titleWidth, box.width * 0.8),
|
|
1948
|
+
height: titleHeight
|
|
1949
|
+
}
|
|
1950
|
+
};
|
|
1951
|
+
}
|
|
1952
|
+
function expand(box, padding, titleSize) {
|
|
1953
|
+
return {
|
|
1954
|
+
x: box.x - padding,
|
|
1955
|
+
y: box.y - padding - titleSize,
|
|
1956
|
+
width: box.width + padding * 2,
|
|
1957
|
+
height: box.height + padding * 2 + titleSize
|
|
1958
|
+
};
|
|
1959
|
+
}
|
|
1509
1960
|
function coordinateGroups(groups, nodeBoxes, options, diagnostics) {
|
|
1510
1961
|
const coordinated = [];
|
|
1511
1962
|
const groupBoxes = /* @__PURE__ */ new Map();
|
|
@@ -1554,8 +2005,11 @@ function coordinateGroups(groups, nodeBoxes, options, diagnostics) {
|
|
|
1554
2005
|
}
|
|
1555
2006
|
return coordinated;
|
|
1556
2007
|
}
|
|
1557
|
-
function coordinateEdges(edges, nodes, obstacles, direction, options, diagnostics) {
|
|
2008
|
+
function coordinateEdges(edges, nodes, coordinatedNodes, obstacles, direction, options, diagnostics) {
|
|
1558
2009
|
const coordinated = [];
|
|
2010
|
+
const coordinatedNodeById = new Map(
|
|
2011
|
+
coordinatedNodes.map((node) => [node.id, node])
|
|
2012
|
+
);
|
|
1559
2013
|
for (const edge of edges) {
|
|
1560
2014
|
const source = nodes.get(edge.source.nodeId);
|
|
1561
2015
|
const target = nodes.get(edge.target.nodeId);
|
|
@@ -1573,11 +2027,13 @@ function coordinateEdges(edges, nodes, obstacles, direction, options, diagnostic
|
|
|
1573
2027
|
});
|
|
1574
2028
|
continue;
|
|
1575
2029
|
}
|
|
2030
|
+
const sourcePort = coordinatedNodeById.get(edge.source.nodeId)?.ports?.find((port) => port.id === edge.source.portId);
|
|
2031
|
+
const targetPort = coordinatedNodeById.get(edge.target.nodeId)?.ports?.find((port) => port.id === edge.target.portId);
|
|
1576
2032
|
const route = routeEdge({
|
|
1577
2033
|
kind: options.routeKind ?? "orthogonal",
|
|
1578
2034
|
direction,
|
|
1579
|
-
source,
|
|
1580
|
-
target,
|
|
2035
|
+
source: portGeometry(source, sourcePort),
|
|
2036
|
+
target: portGeometry(target, targetPort),
|
|
1581
2037
|
...edge.source.anchor === void 0 ? {} : { sourceAnchor: edge.source.anchor },
|
|
1582
2038
|
...edge.target.anchor === void 0 ? {} : { targetAnchor: edge.target.anchor },
|
|
1583
2039
|
obstacles: obstacles.filter(
|
|
@@ -1597,6 +2053,21 @@ function coordinateEdges(edges, nodes, obstacles, direction, options, diagnostic
|
|
|
1597
2053
|
}
|
|
1598
2054
|
return coordinated;
|
|
1599
2055
|
}
|
|
2056
|
+
function portGeometry(nodeGeometry, port) {
|
|
2057
|
+
if (port === void 0) {
|
|
2058
|
+
return nodeGeometry;
|
|
2059
|
+
}
|
|
2060
|
+
return {
|
|
2061
|
+
...nodeGeometry,
|
|
2062
|
+
box: port.box,
|
|
2063
|
+
center: port.anchor,
|
|
2064
|
+
anchors: nodeGeometry.anchors.map((anchor) => ({
|
|
2065
|
+
name: anchor.name,
|
|
2066
|
+
point: port.anchor
|
|
2067
|
+
})),
|
|
2068
|
+
obstacleBox: port.box
|
|
2069
|
+
};
|
|
2070
|
+
}
|
|
1600
2071
|
function stableById(items) {
|
|
1601
2072
|
return [...items].sort((a, b) => a.id.localeCompare(b.id));
|
|
1602
2073
|
}
|
|
@@ -1626,34 +2097,34 @@ function assertFiniteNonNegative(value, label) {
|
|
|
1626
2097
|
throw new TypeError(`${label} must be a finite non-negative width`);
|
|
1627
2098
|
}
|
|
1628
2099
|
}
|
|
1629
|
-
function validateTextStyle(
|
|
1630
|
-
assertFinitePositive(
|
|
1631
|
-
if (
|
|
1632
|
-
assertFinitePositive(
|
|
2100
|
+
function validateTextStyle(style2) {
|
|
2101
|
+
assertFinitePositive(style2.fontSize, "fontSize");
|
|
2102
|
+
if (style2.lineHeight !== void 0) {
|
|
2103
|
+
assertFinitePositive(style2.lineHeight, "lineHeight");
|
|
1633
2104
|
}
|
|
1634
|
-
if (
|
|
2105
|
+
if (style2.letterSpacing !== void 0 && !Number.isFinite(style2.letterSpacing)) {
|
|
1635
2106
|
throw new TypeError("letterSpacing must be finite");
|
|
1636
2107
|
}
|
|
1637
2108
|
}
|
|
1638
|
-
function resolveLineHeight(
|
|
1639
|
-
validateTextStyle(
|
|
1640
|
-
return
|
|
2109
|
+
function resolveLineHeight(style2) {
|
|
2110
|
+
validateTextStyle(style2);
|
|
2111
|
+
return style2.lineHeight ?? style2.fontSize * 1.2;
|
|
1641
2112
|
}
|
|
1642
|
-
function toCanvasFont(
|
|
1643
|
-
validateTextStyle(
|
|
1644
|
-
const fontStyle =
|
|
1645
|
-
const fontWeight =
|
|
1646
|
-
return `${fontStyle}${fontWeight} ${
|
|
2113
|
+
function toCanvasFont(style2) {
|
|
2114
|
+
validateTextStyle(style2);
|
|
2115
|
+
const fontStyle = style2.fontStyle === "italic" ? "italic " : "";
|
|
2116
|
+
const fontWeight = style2.fontWeight ?? 400;
|
|
2117
|
+
return `${fontStyle}${fontWeight} ${style2.fontSize}px ${style2.fontFamily}`;
|
|
1647
2118
|
}
|
|
1648
2119
|
|
|
1649
2120
|
// src/text/fallback.ts
|
|
1650
2121
|
var DeterministicTextMeasurer = class {
|
|
1651
|
-
prepare(text,
|
|
1652
|
-
validateTextStyle(
|
|
2122
|
+
prepare(text, style2) {
|
|
2123
|
+
validateTextStyle(style2);
|
|
1653
2124
|
return {
|
|
1654
2125
|
text,
|
|
1655
|
-
font: toCanvasFont(
|
|
1656
|
-
style: { ...
|
|
2126
|
+
font: toCanvasFont(style2),
|
|
2127
|
+
style: { ...style2 },
|
|
1657
2128
|
backend: "deterministic"
|
|
1658
2129
|
};
|
|
1659
2130
|
}
|
|
@@ -1712,9 +2183,9 @@ var DeterministicTextMeasurer = class {
|
|
|
1712
2183
|
return output;
|
|
1713
2184
|
}
|
|
1714
2185
|
};
|
|
1715
|
-
function getCharacterWidth(
|
|
1716
|
-
const letterSpacing =
|
|
1717
|
-
return Math.max(0,
|
|
2186
|
+
function getCharacterWidth(style2) {
|
|
2187
|
+
const letterSpacing = style2.letterSpacing ?? 0;
|
|
2188
|
+
return Math.max(0, style2.fontSize * 0.6 + letterSpacing);
|
|
1718
2189
|
}
|
|
1719
2190
|
function createLine(text, width, segmentIndex, start, end) {
|
|
1720
2191
|
return {
|
|
@@ -1735,6 +2206,108 @@ function assertFinitePositiveLineHeight(lineHeight) {
|
|
|
1735
2206
|
throw new TypeError("lineHeight must be finite and positive");
|
|
1736
2207
|
}
|
|
1737
2208
|
}
|
|
2209
|
+
var require2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
2210
|
+
function installNodeCanvasRuntime(loadNodeCanvasModule = loadDefaultNodeCanvasModule) {
|
|
2211
|
+
if (typeof globalThis.OffscreenCanvas === "function") {
|
|
2212
|
+
return true;
|
|
2213
|
+
}
|
|
2214
|
+
try {
|
|
2215
|
+
const canvasModule = loadNodeCanvasModule();
|
|
2216
|
+
const { createCanvas } = canvasModule;
|
|
2217
|
+
const NodeOffscreenCanvas = class {
|
|
2218
|
+
canvas;
|
|
2219
|
+
constructor(width, height) {
|
|
2220
|
+
this.canvas = createCanvas(width, height);
|
|
2221
|
+
}
|
|
2222
|
+
getContext(contextId) {
|
|
2223
|
+
return contextId === "2d" ? this.canvas.getContext("2d") : null;
|
|
2224
|
+
}
|
|
2225
|
+
};
|
|
2226
|
+
globalThis.OffscreenCanvas = NodeOffscreenCanvas;
|
|
2227
|
+
return true;
|
|
2228
|
+
} catch {
|
|
2229
|
+
return false;
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
function loadDefaultNodeCanvasModule() {
|
|
2233
|
+
return require2("@napi-rs/canvas");
|
|
2234
|
+
}
|
|
2235
|
+
var RUNTIME_UNAVAILABLE = "text.pretext.runtime-unavailable";
|
|
2236
|
+
function isPretextRuntimeAvailable() {
|
|
2237
|
+
return typeof Intl.Segmenter === "function" && typeof globalThis.OffscreenCanvas === "function";
|
|
2238
|
+
}
|
|
2239
|
+
var PretextTextMeasurer = class {
|
|
2240
|
+
prepare(text, style2) {
|
|
2241
|
+
if (!isPretextRuntimeAvailable()) {
|
|
2242
|
+
throw new TypeError(RUNTIME_UNAVAILABLE);
|
|
2243
|
+
}
|
|
2244
|
+
validateTextStyle(style2);
|
|
2245
|
+
const font = toCanvasFont(style2);
|
|
2246
|
+
const options = {
|
|
2247
|
+
...style2.whiteSpace === void 0 ? {} : { whiteSpace: style2.whiteSpace },
|
|
2248
|
+
...style2.wordBreak === void 0 ? {} : { wordBreak: style2.wordBreak },
|
|
2249
|
+
...style2.letterSpacing === void 0 ? {} : { letterSpacing: style2.letterSpacing }
|
|
2250
|
+
};
|
|
2251
|
+
const prepared = pretext.prepareWithSegments(text, font, options);
|
|
2252
|
+
return {
|
|
2253
|
+
text,
|
|
2254
|
+
font,
|
|
2255
|
+
style: { ...style2 },
|
|
2256
|
+
backend: "pretext",
|
|
2257
|
+
pretextPrepared: prepared
|
|
2258
|
+
};
|
|
2259
|
+
}
|
|
2260
|
+
layout(prepared, maxWidth, lineHeight = resolveLineHeight(prepared.style)) {
|
|
2261
|
+
assertFiniteNonNegative(maxWidth, "maxWidth");
|
|
2262
|
+
if (!Number.isFinite(lineHeight) || lineHeight <= 0) {
|
|
2263
|
+
throw new TypeError("lineHeight must be finite and positive");
|
|
2264
|
+
}
|
|
2265
|
+
const result = pretext.layoutWithLines(
|
|
2266
|
+
toInternalPrepared(prepared),
|
|
2267
|
+
maxWidth,
|
|
2268
|
+
lineHeight
|
|
2269
|
+
);
|
|
2270
|
+
const width = result.lines.reduce(
|
|
2271
|
+
(current, line) => Math.max(current, line.width),
|
|
2272
|
+
0
|
|
2273
|
+
);
|
|
2274
|
+
return {
|
|
2275
|
+
width,
|
|
2276
|
+
height: result.height,
|
|
2277
|
+
lineHeight,
|
|
2278
|
+
lineCount: result.lineCount,
|
|
2279
|
+
lines: result.lines.map((line) => ({
|
|
2280
|
+
text: line.text,
|
|
2281
|
+
width: line.width,
|
|
2282
|
+
start: {
|
|
2283
|
+
segmentIndex: line.start.segmentIndex,
|
|
2284
|
+
graphemeIndex: line.start.graphemeIndex
|
|
2285
|
+
},
|
|
2286
|
+
end: {
|
|
2287
|
+
segmentIndex: line.end.segmentIndex,
|
|
2288
|
+
graphemeIndex: line.end.graphemeIndex
|
|
2289
|
+
}
|
|
2290
|
+
})),
|
|
2291
|
+
diagnostics: []
|
|
2292
|
+
};
|
|
2293
|
+
}
|
|
2294
|
+
naturalWidth(prepared) {
|
|
2295
|
+
return pretext.measureNaturalWidth(toInternalPrepared(prepared));
|
|
2296
|
+
}
|
|
2297
|
+
};
|
|
2298
|
+
function toInternalPrepared(prepared) {
|
|
2299
|
+
if (prepared.backend !== "pretext" || !("pretextPrepared" in prepared)) {
|
|
2300
|
+
throw new TypeError("prepared text was not created by PretextTextMeasurer");
|
|
2301
|
+
}
|
|
2302
|
+
return prepared.pretextPrepared;
|
|
2303
|
+
}
|
|
2304
|
+
|
|
2305
|
+
// src/text/default.ts
|
|
2306
|
+
function createDefaultTextMeasurer(options = {}) {
|
|
2307
|
+
const installRuntime = options.installNodeCanvasRuntime ?? installNodeCanvasRuntime;
|
|
2308
|
+
installRuntime();
|
|
2309
|
+
return isPretextRuntimeAvailable() ? new PretextTextMeasurer() : new DeterministicTextMeasurer();
|
|
2310
|
+
}
|
|
1738
2311
|
|
|
1739
2312
|
// src/labels/fit.ts
|
|
1740
2313
|
function fitLabel(text, options, measurer) {
|
|
@@ -1793,6 +2366,7 @@ function computeLabelLayout(text, options, measurer) {
|
|
|
1793
2366
|
fittedSize,
|
|
1794
2367
|
padding,
|
|
1795
2368
|
font: { ...options.font },
|
|
2369
|
+
textBackend: prepared.backend,
|
|
1796
2370
|
lineHeight,
|
|
1797
2371
|
lines: buildLines(textLayout, contentBox2, lineHeight),
|
|
1798
2372
|
overflow,
|
|
@@ -1887,8 +2461,9 @@ function normalizeDiagramDsl(dslValue, options = {}) {
|
|
|
1887
2461
|
...outputResult(dsl)
|
|
1888
2462
|
};
|
|
1889
2463
|
}
|
|
1890
|
-
const measurer = options.textMeasurer ??
|
|
2464
|
+
const measurer = options.textMeasurer ?? createDefaultTextMeasurer();
|
|
1891
2465
|
const routeKind = dsl.routing?.kind ?? "orthogonal";
|
|
2466
|
+
const portShifting = normalizePortShifting(dsl.routing?.portShifting);
|
|
1892
2467
|
const diagram = {
|
|
1893
2468
|
id: options.id ?? dsl.id ?? "diagram",
|
|
1894
2469
|
...dsl.title === void 0 ? {} : { title: dsl.title },
|
|
@@ -1896,9 +2471,14 @@ function normalizeDiagramDsl(dslValue, options = {}) {
|
|
|
1896
2471
|
nodes: normalizeNodes(dsl, measurer),
|
|
1897
2472
|
edges: normalizeEdges(dsl),
|
|
1898
2473
|
groups: normalizeGroups(dsl, measurer),
|
|
2474
|
+
swimlanes: normalizeSwimlanes(dsl),
|
|
1899
2475
|
constraints: normalizeConstraints(dsl),
|
|
1900
2476
|
diagnostics: [],
|
|
1901
|
-
|
|
2477
|
+
...dsl.frame === void 0 ? {} : { frame: normalizeFrame(dsl.frame) },
|
|
2478
|
+
metadata: {
|
|
2479
|
+
routeKind,
|
|
2480
|
+
...portShifting === void 0 ? {} : { portShifting }
|
|
2481
|
+
}
|
|
1902
2482
|
};
|
|
1903
2483
|
return {
|
|
1904
2484
|
diagram,
|
|
@@ -1906,6 +2486,15 @@ function normalizeDiagramDsl(dslValue, options = {}) {
|
|
|
1906
2486
|
...outputResult(dsl)
|
|
1907
2487
|
};
|
|
1908
2488
|
}
|
|
2489
|
+
function normalizePortShifting(portShifting) {
|
|
2490
|
+
if (portShifting === void 0) {
|
|
2491
|
+
return void 0;
|
|
2492
|
+
}
|
|
2493
|
+
return {
|
|
2494
|
+
...portShifting.enabled === void 0 ? {} : { enabled: portShifting.enabled },
|
|
2495
|
+
...portShifting.spacing === void 0 ? {} : { spacing: portShifting.spacing }
|
|
2496
|
+
};
|
|
2497
|
+
}
|
|
1909
2498
|
function outputResult(dsl) {
|
|
1910
2499
|
return dsl.output?.format === void 0 ? {} : { output: { format: dsl.output.format } };
|
|
1911
2500
|
}
|
|
@@ -1915,15 +2504,24 @@ function normalizeNodes(dsl, measurer) {
|
|
|
1915
2504
|
const label = toLabel(node?.label);
|
|
1916
2505
|
const labelLayout = label === void 0 ? void 0 : fitDslLabel(label, measurer);
|
|
1917
2506
|
const fittedSize = labelLayout?.fittedSize;
|
|
2507
|
+
const nodeCompartments = node?.compartments === void 0 ? void 0 : compartments(node.compartments);
|
|
2508
|
+
const compartmentWidth = nodeCompartments === void 0 ? 0 : compartmentNaturalWidth(id, label, nodeCompartments, measurer);
|
|
1918
2509
|
return {
|
|
1919
2510
|
id,
|
|
1920
2511
|
...label === void 0 ? {} : { label },
|
|
1921
2512
|
shape: node?.shape ?? "rectangle",
|
|
1922
2513
|
...node?.position === void 0 ? {} : { position: point(node.position) },
|
|
2514
|
+
...node?.style === void 0 ? {} : { style: style(node.style) },
|
|
2515
|
+
...node?.ports === void 0 ? {} : { ports: normalizePorts(node.ports) },
|
|
2516
|
+
...nodeCompartments === void 0 ? {} : { compartments: nodeCompartments },
|
|
1923
2517
|
size: {
|
|
1924
|
-
width: Math.max(
|
|
2518
|
+
width: Math.max(
|
|
2519
|
+
DEFAULT_NODE_MIN_SIZE.width,
|
|
2520
|
+
fittedSize?.width ?? 0,
|
|
2521
|
+
compartmentWidth
|
|
2522
|
+
),
|
|
1925
2523
|
height: Math.max(
|
|
1926
|
-
DEFAULT_NODE_MIN_SIZE.height,
|
|
2524
|
+
nodeCompartments === void 0 ? DEFAULT_NODE_MIN_SIZE.height : compartmentHeight(nodeCompartments),
|
|
1927
2525
|
fittedSize?.height ?? 0
|
|
1928
2526
|
)
|
|
1929
2527
|
},
|
|
@@ -1932,11 +2530,42 @@ function normalizeNodes(dsl, measurer) {
|
|
|
1932
2530
|
};
|
|
1933
2531
|
});
|
|
1934
2532
|
}
|
|
2533
|
+
function compartmentHeight(value) {
|
|
2534
|
+
const rowCount = (value.stereotype === void 0 ? 0 : 1) + 1 + (value.properties?.length ?? 0) + (value.constraints?.length ?? 0);
|
|
2535
|
+
const rowHeight = 16;
|
|
2536
|
+
const verticalPadding = 20;
|
|
2537
|
+
return Math.max(
|
|
2538
|
+
DEFAULT_NODE_MIN_SIZE.height,
|
|
2539
|
+
rowCount * rowHeight + verticalPadding
|
|
2540
|
+
);
|
|
2541
|
+
}
|
|
2542
|
+
function compartmentNaturalWidth(id, label, value, measurer) {
|
|
2543
|
+
const rows = compartmentRows(id, label, value);
|
|
2544
|
+
const maxRowWidth = rows.reduce((width, row) => {
|
|
2545
|
+
const prepared = measurer.prepare(row, DEFAULT_FONT);
|
|
2546
|
+
return Math.max(width, measurer.naturalWidth(prepared));
|
|
2547
|
+
}, 0);
|
|
2548
|
+
return Math.ceil(
|
|
2549
|
+
maxRowWidth + DEFAULT_NODE_PADDING.left + DEFAULT_NODE_PADDING.right
|
|
2550
|
+
);
|
|
2551
|
+
}
|
|
2552
|
+
function compartmentRows(id, label, value) {
|
|
2553
|
+
return [
|
|
2554
|
+
...value.stereotype === void 0 ? [] : [value.stereotype],
|
|
2555
|
+
value.name ?? label?.text ?? id,
|
|
2556
|
+
...value.properties ?? [],
|
|
2557
|
+
...value.constraints ?? []
|
|
2558
|
+
];
|
|
2559
|
+
}
|
|
1935
2560
|
function normalizeEdges(dsl) {
|
|
1936
2561
|
const counts = /* @__PURE__ */ new Map();
|
|
1937
2562
|
return (dsl.edges ?? []).map((edge) => {
|
|
1938
|
-
const
|
|
1939
|
-
const
|
|
2563
|
+
const source = typeof edge === "string" ? void 0 : edge.source;
|
|
2564
|
+
const target = typeof edge === "string" ? void 0 : edge.target;
|
|
2565
|
+
const sourceId = typeof edge === "string" ? "" : edge.sourceId ?? endpointNodeId(source) ?? "";
|
|
2566
|
+
const targetId = typeof edge === "string" ? "" : edge.targetId ?? endpointNodeId(target) ?? "";
|
|
2567
|
+
const sourceEndpoint = typeof edge === "string" ? { nodeId: sourceId } : endpoint(source, edge.sourceId);
|
|
2568
|
+
const targetEndpoint = typeof edge === "string" ? { nodeId: targetId } : endpoint(target, edge.targetId);
|
|
1940
2569
|
const baseId = `${sourceId}-${targetId}`;
|
|
1941
2570
|
const count = counts.get(baseId) ?? 0;
|
|
1942
2571
|
counts.set(baseId, count + 1);
|
|
@@ -1944,9 +2573,96 @@ function normalizeEdges(dsl) {
|
|
|
1944
2573
|
const label = typeof edge === "string" ? void 0 : toLabel(edge.label);
|
|
1945
2574
|
return {
|
|
1946
2575
|
id,
|
|
1947
|
-
source:
|
|
1948
|
-
target:
|
|
1949
|
-
...label === void 0 ? {} : { label }
|
|
2576
|
+
source: sourceEndpoint,
|
|
2577
|
+
target: targetEndpoint,
|
|
2578
|
+
...label === void 0 ? {} : { label },
|
|
2579
|
+
...typeof edge === "string" || edge.style === void 0 ? {} : { style: edge.style },
|
|
2580
|
+
...typeof edge === "string" || edge.arrowhead === void 0 ? {} : { arrowhead: edge.arrowhead }
|
|
2581
|
+
};
|
|
2582
|
+
});
|
|
2583
|
+
}
|
|
2584
|
+
function normalizePorts(ports) {
|
|
2585
|
+
return Object.keys(ports ?? {}).sort().map((id) => {
|
|
2586
|
+
const port = ports?.[id];
|
|
2587
|
+
const label = toLabel(port?.label);
|
|
2588
|
+
return {
|
|
2589
|
+
id,
|
|
2590
|
+
...label === void 0 ? {} : { label },
|
|
2591
|
+
side: port?.side ?? "right",
|
|
2592
|
+
kind: port?.kind ?? "proxy",
|
|
2593
|
+
...port?.order === void 0 ? {} : { order: port.order },
|
|
2594
|
+
...port?.style === void 0 ? {} : { style: style(port.style) }
|
|
2595
|
+
};
|
|
2596
|
+
});
|
|
2597
|
+
}
|
|
2598
|
+
function endpoint(value, nodeIdOverride) {
|
|
2599
|
+
if (nodeIdOverride !== void 0) {
|
|
2600
|
+
return {
|
|
2601
|
+
nodeId: nodeIdOverride,
|
|
2602
|
+
...typeof value === "object" && value.node === nodeIdOverride && value.port !== void 0 ? { portId: value.port } : {}
|
|
2603
|
+
};
|
|
2604
|
+
}
|
|
2605
|
+
if (value === void 0) {
|
|
2606
|
+
return { nodeId: "" };
|
|
2607
|
+
}
|
|
2608
|
+
if (typeof value === "string") {
|
|
2609
|
+
return { nodeId: value };
|
|
2610
|
+
}
|
|
2611
|
+
return {
|
|
2612
|
+
nodeId: value.node,
|
|
2613
|
+
...value.port === void 0 ? {} : { portId: value.port }
|
|
2614
|
+
};
|
|
2615
|
+
}
|
|
2616
|
+
function style(value) {
|
|
2617
|
+
return {
|
|
2618
|
+
...value.fill === void 0 ? {} : { fill: value.fill },
|
|
2619
|
+
...value.stroke === void 0 ? {} : { stroke: value.stroke }
|
|
2620
|
+
};
|
|
2621
|
+
}
|
|
2622
|
+
function compartments(value) {
|
|
2623
|
+
return {
|
|
2624
|
+
...value.stereotype === void 0 ? {} : { stereotype: value.stereotype },
|
|
2625
|
+
...value.name === void 0 ? {} : { name: value.name },
|
|
2626
|
+
...value.properties === void 0 ? {} : { properties: value.properties.map(formatCompartmentEntry) },
|
|
2627
|
+
...value.constraints === void 0 ? {} : { constraints: [...value.constraints] }
|
|
2628
|
+
};
|
|
2629
|
+
}
|
|
2630
|
+
function normalizeFrame(frame) {
|
|
2631
|
+
return {
|
|
2632
|
+
kind: frame.kind,
|
|
2633
|
+
...frame.context === void 0 ? {} : { context: frame.context },
|
|
2634
|
+
...frame.name === void 0 ? {} : { name: frame.name },
|
|
2635
|
+
titleTab: frame.titleTab,
|
|
2636
|
+
...frame.style === void 0 ? {} : { style: style(frame.style) }
|
|
2637
|
+
};
|
|
2638
|
+
}
|
|
2639
|
+
function formatCompartmentEntry(value) {
|
|
2640
|
+
if (typeof value === "string") {
|
|
2641
|
+
return value;
|
|
2642
|
+
}
|
|
2643
|
+
const [entry] = Object.entries(value);
|
|
2644
|
+
if (entry === void 0) {
|
|
2645
|
+
return "";
|
|
2646
|
+
}
|
|
2647
|
+
return `${entry[0]}: ${entry[1]}`;
|
|
2648
|
+
}
|
|
2649
|
+
function normalizeSwimlanes(dsl) {
|
|
2650
|
+
return Object.keys(dsl.swimlanes ?? {}).sort().map((id) => {
|
|
2651
|
+
const swimlane = dsl.swimlanes?.[id];
|
|
2652
|
+
const label = toLabel(swimlane?.label);
|
|
2653
|
+
return {
|
|
2654
|
+
id,
|
|
2655
|
+
...label === void 0 ? {} : { label },
|
|
2656
|
+
orientation: swimlane?.orientation ?? "vertical",
|
|
2657
|
+
lanes: Object.keys(swimlane?.lanes ?? {}).sort().map((laneId) => {
|
|
2658
|
+
const lane = swimlane?.lanes[laneId];
|
|
2659
|
+
const laneLabel = toLabel(lane?.label);
|
|
2660
|
+
return {
|
|
2661
|
+
id: laneId,
|
|
2662
|
+
...laneLabel === void 0 ? {} : { label: laneLabel },
|
|
2663
|
+
children: [...lane?.children ?? []]
|
|
2664
|
+
};
|
|
2665
|
+
})
|
|
1950
2666
|
};
|
|
1951
2667
|
});
|
|
1952
2668
|
}
|
|
@@ -2016,18 +2732,37 @@ function validateReferences(dsl) {
|
|
|
2016
2732
|
const diagnostics = [];
|
|
2017
2733
|
const nodeIds = new Set(Object.keys(dsl.nodes));
|
|
2018
2734
|
const groupIds = new Set(Object.keys(dsl.groups ?? {}));
|
|
2735
|
+
const swimlaneLaneIds = new Set(
|
|
2736
|
+
Object.entries(dsl.swimlanes ?? {}).flatMap(
|
|
2737
|
+
([swimlaneId, swimlane]) => Object.keys(swimlane.lanes).map((laneId) => `${swimlaneId}.${laneId}`)
|
|
2738
|
+
)
|
|
2739
|
+
);
|
|
2019
2740
|
(dsl.edges ?? []).forEach((edge, index) => {
|
|
2020
2741
|
if (typeof edge === "string") {
|
|
2021
2742
|
return;
|
|
2022
2743
|
}
|
|
2023
|
-
const sourceId = edge.sourceId ?? edge.source;
|
|
2024
|
-
const targetId = edge.targetId ?? edge.target;
|
|
2744
|
+
const sourceId = edge.sourceId ?? endpointNodeId(edge.source);
|
|
2745
|
+
const targetId = edge.targetId ?? endpointNodeId(edge.target);
|
|
2746
|
+
const sourceEndpoint = endpoint(edge.source, edge.sourceId);
|
|
2747
|
+
const targetEndpoint = endpoint(edge.target, edge.targetId);
|
|
2025
2748
|
if (sourceId !== void 0 && !nodeIds.has(sourceId)) {
|
|
2026
2749
|
diagnostics.push(referenceMissing(["edges", index, "source"], sourceId));
|
|
2027
2750
|
}
|
|
2028
2751
|
if (targetId !== void 0 && !nodeIds.has(targetId)) {
|
|
2029
2752
|
diagnostics.push(referenceMissing(["edges", index, "target"], targetId));
|
|
2030
2753
|
}
|
|
2754
|
+
validateEndpointPort(
|
|
2755
|
+
dsl,
|
|
2756
|
+
sourceEndpoint,
|
|
2757
|
+
["edges", index, "source"],
|
|
2758
|
+
diagnostics
|
|
2759
|
+
);
|
|
2760
|
+
validateEndpointPort(
|
|
2761
|
+
dsl,
|
|
2762
|
+
targetEndpoint,
|
|
2763
|
+
["edges", index, "target"],
|
|
2764
|
+
diagnostics
|
|
2765
|
+
);
|
|
2031
2766
|
});
|
|
2032
2767
|
for (const [groupId, group] of Object.entries(dsl.groups ?? {})) {
|
|
2033
2768
|
(group.nodes ?? []).forEach((nodeId, index) => {
|
|
@@ -2045,6 +2780,27 @@ function validateReferences(dsl) {
|
|
|
2045
2780
|
}
|
|
2046
2781
|
});
|
|
2047
2782
|
}
|
|
2783
|
+
for (const [swimlaneId, swimlane] of Object.entries(dsl.swimlanes ?? {})) {
|
|
2784
|
+
for (const [laneId, lane] of Object.entries(swimlane.lanes)) {
|
|
2785
|
+
(lane.children ?? []).forEach((child, childIndex) => {
|
|
2786
|
+
if (!nodeIds.has(child)) {
|
|
2787
|
+
diagnostics.push(
|
|
2788
|
+
referenceMissing(
|
|
2789
|
+
[
|
|
2790
|
+
"swimlanes",
|
|
2791
|
+
swimlaneId,
|
|
2792
|
+
"lanes",
|
|
2793
|
+
laneId,
|
|
2794
|
+
"children",
|
|
2795
|
+
childIndex
|
|
2796
|
+
],
|
|
2797
|
+
child
|
|
2798
|
+
)
|
|
2799
|
+
);
|
|
2800
|
+
}
|
|
2801
|
+
});
|
|
2802
|
+
}
|
|
2803
|
+
}
|
|
2048
2804
|
(dsl.constraints ?? []).forEach((constraint, index) => {
|
|
2049
2805
|
switch (constraint.kind) {
|
|
2050
2806
|
case "exact-position": {
|
|
@@ -2088,7 +2844,7 @@ function validateReferences(dsl) {
|
|
|
2088
2844
|
break;
|
|
2089
2845
|
case "containment": {
|
|
2090
2846
|
const container = constraint.containerId ?? constraint.container;
|
|
2091
|
-
if (container !== void 0 && !hasNodeOrGroup(container, nodeIds, groupIds)) {
|
|
2847
|
+
if (container !== void 0 && !hasNodeOrGroup(container, nodeIds, groupIds, swimlaneLaneIds)) {
|
|
2092
2848
|
diagnostics.push(
|
|
2093
2849
|
referenceMissing(["constraints", index, "container"], container)
|
|
2094
2850
|
);
|
|
@@ -2121,8 +2877,23 @@ function referenceMissing(path, id) {
|
|
|
2121
2877
|
hint: "Define the referenced node or group id, or update this reference."
|
|
2122
2878
|
};
|
|
2123
2879
|
}
|
|
2124
|
-
function hasNodeOrGroup(id, nodeIds, groupIds) {
|
|
2125
|
-
return nodeIds.has(id) || groupIds.has(id);
|
|
2880
|
+
function hasNodeOrGroup(id, nodeIds, groupIds, swimlaneLaneIds = /* @__PURE__ */ new Set()) {
|
|
2881
|
+
return nodeIds.has(id) || groupIds.has(id) || swimlaneLaneIds.has(id);
|
|
2882
|
+
}
|
|
2883
|
+
function endpointNodeId(endpointValue) {
|
|
2884
|
+
if (typeof endpointValue === "string" || endpointValue === void 0) {
|
|
2885
|
+
return endpointValue;
|
|
2886
|
+
}
|
|
2887
|
+
return endpointValue.node;
|
|
2888
|
+
}
|
|
2889
|
+
function validateEndpointPort(dsl, endpointValue, path, diagnostics) {
|
|
2890
|
+
if (endpointValue.portId === void 0) {
|
|
2891
|
+
return;
|
|
2892
|
+
}
|
|
2893
|
+
const node = dsl.nodes[endpointValue.nodeId];
|
|
2894
|
+
if (node !== void 0 && node.ports?.[endpointValue.portId] === void 0) {
|
|
2895
|
+
diagnostics.push(referenceMissing([...path, "port"], endpointValue.portId));
|
|
2896
|
+
}
|
|
2126
2897
|
}
|
|
2127
2898
|
function toLabel(value) {
|
|
2128
2899
|
if (value === void 0) {
|
|
@@ -2192,6 +2963,8 @@ function isValidEdgeId(value) {
|
|
|
2192
2963
|
var directionSchema = zod.z.enum(["TB", "LR", "BT", "RL"]);
|
|
2193
2964
|
var routeKindSchema = zod.z.enum(["orthogonal", "straight"]);
|
|
2194
2965
|
var outputFormatSchema = zod.z.enum(["svg", "excalidraw"]);
|
|
2966
|
+
var edgeStrokeStyleSchema = zod.z.enum(["solid", "dashed"]);
|
|
2967
|
+
var edgeArrowheadSchema = zod.z.enum(["triangle", "hollowTriangle"]);
|
|
2195
2968
|
var nodeShapeSchema = zod.z.enum([
|
|
2196
2969
|
"rectangle",
|
|
2197
2970
|
"rounded-rectangle",
|
|
@@ -2219,18 +2992,49 @@ var labelSchema = zod.z.union([
|
|
|
2219
2992
|
maxWidth: finiteNumberSchema.optional()
|
|
2220
2993
|
})
|
|
2221
2994
|
]);
|
|
2995
|
+
var styleSchema = zod.z.object({
|
|
2996
|
+
fill: zod.z.string().optional(),
|
|
2997
|
+
stroke: zod.z.string().optional()
|
|
2998
|
+
});
|
|
2999
|
+
var portSideSchema = zod.z.enum(["top", "right", "bottom", "left"]);
|
|
3000
|
+
var portKindSchema = zod.z.enum(["proxy", "flow"]);
|
|
3001
|
+
var portSchema = zod.z.object({
|
|
3002
|
+
label: labelSchema.optional(),
|
|
3003
|
+
side: portSideSchema,
|
|
3004
|
+
kind: portKindSchema.optional(),
|
|
3005
|
+
order: finiteNumberSchema.optional(),
|
|
3006
|
+
style: styleSchema.optional()
|
|
3007
|
+
});
|
|
3008
|
+
var compartmentsSchema = zod.z.object({
|
|
3009
|
+
stereotype: zod.z.string().optional(),
|
|
3010
|
+
name: zod.z.string().optional(),
|
|
3011
|
+
properties: zod.z.array(zod.z.record(zod.z.string(), zod.z.string()).or(zod.z.string())).optional(),
|
|
3012
|
+
constraints: zod.z.array(zod.z.string()).optional()
|
|
3013
|
+
});
|
|
2222
3014
|
var nodeSchema = zod.z.object({
|
|
2223
3015
|
label: labelSchema.optional(),
|
|
2224
3016
|
shape: nodeShapeSchema.optional(),
|
|
2225
|
-
position: pointSchema.optional()
|
|
3017
|
+
position: pointSchema.optional(),
|
|
3018
|
+
style: styleSchema.optional(),
|
|
3019
|
+
ports: zod.z.record(zod.z.string(), portSchema).optional(),
|
|
3020
|
+
compartments: compartmentsSchema.optional()
|
|
2226
3021
|
});
|
|
3022
|
+
var endpointSchema = zod.z.union([
|
|
3023
|
+
zod.z.string(),
|
|
3024
|
+
zod.z.object({
|
|
3025
|
+
node: zod.z.string(),
|
|
3026
|
+
port: zod.z.string().optional()
|
|
3027
|
+
})
|
|
3028
|
+
]);
|
|
2227
3029
|
var structuredEdgeSchema = zod.z.object({
|
|
2228
3030
|
id: zod.z.string().optional(),
|
|
2229
|
-
source:
|
|
2230
|
-
target:
|
|
3031
|
+
source: endpointSchema.optional(),
|
|
3032
|
+
target: endpointSchema.optional(),
|
|
2231
3033
|
sourceId: zod.z.string().optional(),
|
|
2232
3034
|
targetId: zod.z.string().optional(),
|
|
2233
|
-
label: labelSchema.optional()
|
|
3035
|
+
label: labelSchema.optional(),
|
|
3036
|
+
style: edgeStrokeStyleSchema.optional(),
|
|
3037
|
+
arrowhead: edgeArrowheadSchema.optional()
|
|
2234
3038
|
}).superRefine((edge, context) => {
|
|
2235
3039
|
if (edge.source === void 0 && edge.sourceId === void 0) {
|
|
2236
3040
|
context.addIssue({
|
|
@@ -2254,6 +3058,17 @@ var groupSchema = zod.z.object({
|
|
|
2254
3058
|
groups: zod.z.array(zod.z.string()).optional(),
|
|
2255
3059
|
padding: insetsSchema.optional()
|
|
2256
3060
|
});
|
|
3061
|
+
var swimlaneSchema = zod.z.object({
|
|
3062
|
+
label: labelSchema.optional(),
|
|
3063
|
+
orientation: zod.z.enum(["vertical", "horizontal"]).optional(),
|
|
3064
|
+
lanes: zod.z.record(
|
|
3065
|
+
zod.z.string(),
|
|
3066
|
+
zod.z.object({
|
|
3067
|
+
label: labelSchema.optional(),
|
|
3068
|
+
children: zod.z.array(zod.z.string()).optional()
|
|
3069
|
+
})
|
|
3070
|
+
)
|
|
3071
|
+
});
|
|
2257
3072
|
var exactPositionConstraintSchema = zod.z.object({
|
|
2258
3073
|
kind: zod.z.literal("exact-position"),
|
|
2259
3074
|
target: zod.z.string().optional(),
|
|
@@ -2314,12 +3129,24 @@ var diagramDslSchema = zod.z.object({
|
|
|
2314
3129
|
direction: directionSchema.optional()
|
|
2315
3130
|
}).optional(),
|
|
2316
3131
|
routing: zod.z.object({
|
|
2317
|
-
kind: routeKindSchema.optional()
|
|
3132
|
+
kind: routeKindSchema.optional(),
|
|
3133
|
+
portShifting: zod.z.object({
|
|
3134
|
+
enabled: zod.z.boolean().optional(),
|
|
3135
|
+
spacing: finiteNumberSchema.optional()
|
|
3136
|
+
}).optional()
|
|
2318
3137
|
}).optional(),
|
|
2319
3138
|
nodes: zod.z.record(zod.z.string(), nodeSchema),
|
|
2320
3139
|
edges: zod.z.array(edgeSchema).optional(),
|
|
2321
3140
|
groups: zod.z.record(zod.z.string(), groupSchema).optional(),
|
|
3141
|
+
swimlanes: zod.z.record(zod.z.string(), swimlaneSchema).optional(),
|
|
2322
3142
|
constraints: zod.z.array(constraintSchema).optional(),
|
|
3143
|
+
frame: zod.z.object({
|
|
3144
|
+
kind: zod.z.string(),
|
|
3145
|
+
context: zod.z.string().optional(),
|
|
3146
|
+
name: zod.z.string().optional(),
|
|
3147
|
+
titleTab: zod.z.string(),
|
|
3148
|
+
style: styleSchema.optional()
|
|
3149
|
+
}).optional(),
|
|
2323
3150
|
output: zod.z.object({
|
|
2324
3151
|
format: outputFormatSchema.optional()
|
|
2325
3152
|
}).optional()
|
|
@@ -2516,7 +3343,8 @@ function renderDiagramDsl(source, options = {}) {
|
|
|
2516
3343
|
return { diagnostics };
|
|
2517
3344
|
}
|
|
2518
3345
|
const solved = solveDiagram(normalized.diagram, {
|
|
2519
|
-
routeKind: normalized.diagram.metadata?.routeKind === "straight" ? "straight" : "orthogonal"
|
|
3346
|
+
routeKind: normalized.diagram.metadata?.routeKind === "straight" ? "straight" : "orthogonal",
|
|
3347
|
+
...solvePortShiftingOption(normalized.diagram.metadata?.portShifting)
|
|
2520
3348
|
});
|
|
2521
3349
|
const solveDiagnostics = solved.diagnostics.map(toSolveDiagnostic);
|
|
2522
3350
|
if (hasErrorDiagnostics2(solveDiagnostics)) {
|
|
@@ -2555,6 +3383,22 @@ function renderDiagramDsl(source, options = {}) {
|
|
|
2555
3383
|
function toSolveDiagnostic(diagnostic) {
|
|
2556
3384
|
return { ...diagnostic, layer: "solve" };
|
|
2557
3385
|
}
|
|
3386
|
+
function solvePortShiftingOption(value) {
|
|
3387
|
+
if (!isJsonObject(value)) {
|
|
3388
|
+
return {};
|
|
3389
|
+
}
|
|
3390
|
+
const portShifting = {};
|
|
3391
|
+
if (value.enabled === false) {
|
|
3392
|
+
portShifting.enabled = false;
|
|
3393
|
+
}
|
|
3394
|
+
if (typeof value.spacing === "number") {
|
|
3395
|
+
portShifting.spacing = value.spacing;
|
|
3396
|
+
}
|
|
3397
|
+
return { portShifting };
|
|
3398
|
+
}
|
|
3399
|
+
function isJsonObject(value) {
|
|
3400
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3401
|
+
}
|
|
2558
3402
|
function toExportDiagnostic(diagnostic) {
|
|
2559
3403
|
return { ...diagnostic, layer: "export" };
|
|
2560
3404
|
}
|