@crazyhappyone/auto-graph 0.1.0 → 0.1.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/dist/cli/index.js CHANGED
@@ -3144,6 +3144,15 @@ function fitDslLabel(label, measurer) {
3144
3144
  function point(value) {
3145
3145
  return { x: value.x, y: value.y };
3146
3146
  }
3147
+
3148
+ // src/ir/diagnostics.ts
3149
+ var DELIVERABILITY_DIAGNOSTIC_CODES = /* @__PURE__ */ new Set([
3150
+ "constraints.locked-target-not-moved",
3151
+ "routing.evidence.crossing_forbidden",
3152
+ "routing.obstacle.unavoidable",
3153
+ "route_obstacle_fallback",
3154
+ "routing.text-clearance.unresolved"
3155
+ ]);
3147
3156
  var DEFAULT_OPTIONS = {
3148
3157
  nodesep: 80,
3149
3158
  ranksep: 100,
@@ -3342,6 +3351,51 @@ function routeEdge(input) {
3342
3351
  )
3343
3352
  );
3344
3353
  if (hardClearCandidate !== void 0) {
3354
+ let bestPoints2 = hardClearCandidate.points;
3355
+ if (input.kind === "obstacle-avoiding") {
3356
+ const allObstacles = [...softObstacles, ...hardObstacles];
3357
+ for (const candidate of candidateRoutes) {
3358
+ if (routeCrossesBoxes(candidate.points, hardObstacles) || routeIntersectsEndpointInteriors(
3359
+ candidate.points,
3360
+ candidate.endpointObstacles
3361
+ )) {
3362
+ continue;
3363
+ }
3364
+ const rerouted2 = greedyRerouteAroundObstacles(
3365
+ candidate.points,
3366
+ allObstacles,
3367
+ 3
3368
+ );
3369
+ if (!routeCrossesBoxes(rerouted2, allObstacles) && !routeIntersectsEndpointInteriors(
3370
+ rerouted2,
3371
+ candidate.endpointObstacles
3372
+ )) {
3373
+ return {
3374
+ points: finalizeRoute(
3375
+ rerouted2,
3376
+ softObstacles,
3377
+ hardObstacles,
3378
+ diagnostics
3379
+ ),
3380
+ diagnostics
3381
+ };
3382
+ }
3383
+ }
3384
+ const rerouted = greedyRerouteAroundObstacles(
3385
+ bestPoints2,
3386
+ allObstacles,
3387
+ 3
3388
+ );
3389
+ const reroutedAvoidsEndpointInteriors = !routeIntersectsEndpointInteriors(
3390
+ rerouted,
3391
+ hardClearCandidate.endpointObstacles
3392
+ );
3393
+ if (reroutedAvoidsEndpointInteriors) {
3394
+ if (routeCrossesBoxes(rerouted, hardObstacles) && !routeCrossesBoxes(bestPoints2, hardObstacles)) ; else {
3395
+ bestPoints2 = rerouted;
3396
+ }
3397
+ }
3398
+ }
3345
3399
  diagnostics.push({
3346
3400
  severity: "warning",
3347
3401
  code: "routing.obstacle.unavoidable",
@@ -3349,7 +3403,7 @@ function routeEdge(input) {
3349
3403
  });
3350
3404
  return {
3351
3405
  points: finalizeRoute(
3352
- hardClearCandidate.points,
3406
+ bestPoints2,
3353
3407
  softObstacles,
3354
3408
  hardObstacles,
3355
3409
  diagnostics
@@ -3358,6 +3412,33 @@ function routeEdge(input) {
3358
3412
  };
3359
3413
  }
3360
3414
  if (hardObstacles.length > 0) {
3415
+ let bestPoints2 = candidateRoutes[0]?.points ?? fallbackRoute(input, defaultAnchors);
3416
+ if (input.kind === "obstacle-avoiding") {
3417
+ const allObstacles = [...softObstacles, ...hardObstacles];
3418
+ for (const candidate of candidateRoutes) {
3419
+ const rerouted = greedyRerouteAroundObstacles(
3420
+ candidate.points,
3421
+ allObstacles,
3422
+ 5
3423
+ );
3424
+ if (!routeCrossesBoxes(rerouted, allObstacles)) {
3425
+ return {
3426
+ points: finalizeRoute(
3427
+ rerouted,
3428
+ softObstacles,
3429
+ hardObstacles,
3430
+ diagnostics
3431
+ ),
3432
+ diagnostics
3433
+ };
3434
+ }
3435
+ }
3436
+ bestPoints2 = greedyRerouteAroundObstacles(
3437
+ candidateRoutes[0]?.points ?? fallbackRoute(input, defaultAnchors),
3438
+ allObstacles,
3439
+ 5
3440
+ );
3441
+ }
3361
3442
  diagnostics.push({
3362
3443
  severity: "error",
3363
3444
  code: "routing.evidence.crossing_forbidden",
@@ -3365,7 +3446,7 @@ function routeEdge(input) {
3365
3446
  });
3366
3447
  return {
3367
3448
  points: finalizeRoute(
3368
- candidateRoutes[0]?.points ?? fallbackRoute(input, defaultAnchors),
3449
+ bestPoints2,
3369
3450
  softObstacles,
3370
3451
  hardObstacles,
3371
3452
  diagnostics
@@ -3373,6 +3454,33 @@ function routeEdge(input) {
3373
3454
  diagnostics
3374
3455
  };
3375
3456
  }
3457
+ let bestPoints = candidateRoutes[0]?.points ?? fallbackRoute(input, defaultAnchors);
3458
+ if (input.kind === "obstacle-avoiding") {
3459
+ const allObstacles = [...softObstacles, ...hardObstacles];
3460
+ for (const candidate of candidateRoutes) {
3461
+ const rerouted = greedyRerouteAroundObstacles(
3462
+ candidate.points,
3463
+ allObstacles,
3464
+ 5
3465
+ );
3466
+ if (!routeCrossesBoxes(rerouted, allObstacles)) {
3467
+ return {
3468
+ points: finalizeRoute(
3469
+ rerouted,
3470
+ softObstacles,
3471
+ hardObstacles,
3472
+ diagnostics
3473
+ ),
3474
+ diagnostics
3475
+ };
3476
+ }
3477
+ }
3478
+ bestPoints = greedyRerouteAroundObstacles(
3479
+ candidateRoutes[0]?.points ?? fallbackRoute(input, defaultAnchors),
3480
+ allObstacles,
3481
+ 5
3482
+ );
3483
+ }
3376
3484
  diagnostics.push({
3377
3485
  severity: "warning",
3378
3486
  code: "routing.obstacle.unavoidable",
@@ -3380,7 +3488,7 @@ function routeEdge(input) {
3380
3488
  });
3381
3489
  return {
3382
3490
  points: finalizeRoute(
3383
- candidateRoutes[0]?.points ?? fallbackRoute(input, defaultAnchors),
3491
+ bestPoints,
3384
3492
  softObstacles,
3385
3493
  hardObstacles,
3386
3494
  diagnostics
@@ -3390,21 +3498,29 @@ function routeEdge(input) {
3390
3498
  }
3391
3499
  function finalizeRoute(points, softObstacles, hardObstacles, diagnostics) {
3392
3500
  const simplified = simplifyRoute(points);
3501
+ if (simplified.length >= 3) {
3502
+ return simplified;
3503
+ }
3393
3504
  const crossesHardObstacles = routeCrossesBoxes(simplified, hardObstacles);
3394
3505
  const crossesSoftObstacles = routeCrossesBoxes(simplified, softObstacles);
3395
- if (simplified.length < 3 && (crossesHardObstacles || crossesSoftObstacles)) {
3506
+ if (!crossesHardObstacles && !crossesSoftObstacles) {
3507
+ return simplified;
3508
+ }
3509
+ const expanded = expandFallbackRoute(simplified, [
3510
+ ...softObstacles,
3511
+ ...hardObstacles
3512
+ ]);
3513
+ const expandedCrossesHard = routeCrossesBoxes(expanded, hardObstacles);
3514
+ const expandedCrossesSoft = routeCrossesBoxes(expanded, softObstacles);
3515
+ if (expandedCrossesHard || expandedCrossesSoft) {
3396
3516
  diagnostics.push({
3397
- severity: crossesHardObstacles ? "error" : "warning",
3517
+ severity: expandedCrossesHard ? "error" : "warning",
3398
3518
  code: "route_obstacle_fallback",
3399
3519
  message: "Obstacle-aware routing fell back to fewer than three route points.",
3400
3520
  detail: { pointCount: simplified.length }
3401
3521
  });
3402
- return expandFallbackRoute(simplified, [
3403
- ...softObstacles,
3404
- ...hardObstacles
3405
- ]);
3406
3522
  }
3407
- return simplified;
3523
+ return expanded;
3408
3524
  }
3409
3525
  function expandFallbackRoute(points, obstacles) {
3410
3526
  if (points.length !== 2) {
@@ -3435,12 +3551,12 @@ function expandFallbackRoute(points, obstacles) {
3435
3551
  const hv = diagonalDetourHV(source, target, obstacles);
3436
3552
  const vh = diagonalDetourVH(source, target, obstacles);
3437
3553
  const viable = [hv, vh].filter((c) => !routeCrossesBoxes(c, obstacles));
3438
- if (viable.length > 0) {
3554
+ const [firstViable, ...remainingViable] = viable;
3555
+ if (firstViable !== void 0) {
3439
3556
  const directLen = Math.hypot(target.x - source.x, target.y - source.y);
3440
- let best = viable[0];
3441
- for (let i = 1; i < viable.length; i += 1) {
3442
- const cand = viable[i];
3443
- if (cand !== void 0 && pathLength(cand) - directLen < pathLength(best) - directLen) {
3557
+ let best = firstViable;
3558
+ for (const cand of remainingViable) {
3559
+ if (pathLength(cand) - directLen < pathLength(best) - directLen) {
3444
3560
  best = cand;
3445
3561
  }
3446
3562
  }
@@ -3530,6 +3646,70 @@ function insetBox(box, margin) {
3530
3646
  height: box.height - margin * 2
3531
3647
  };
3532
3648
  }
3649
+ function greedyRerouteAroundObstacles(points, obstacles, maxIterations) {
3650
+ let current = [...points];
3651
+ for (let iter = 0; iter < maxIterations; iter++) {
3652
+ const improved = pushRouteAwayFromObstacles(current, obstacles);
3653
+ if (improved === null) {
3654
+ break;
3655
+ }
3656
+ current = improved;
3657
+ if (!routeCrossesBoxes(current, obstacles)) {
3658
+ break;
3659
+ }
3660
+ }
3661
+ return current;
3662
+ }
3663
+ function pushRouteAwayFromObstacles(points, obstacles) {
3664
+ const result = [];
3665
+ let improved = false;
3666
+ for (let i = 0; i < points.length - 1; i++) {
3667
+ const a = points[i];
3668
+ const b = points[i + 1];
3669
+ if (a === void 0 || b === void 0) {
3670
+ result.push(a ?? b ?? { x: 0, y: 0 });
3671
+ continue;
3672
+ }
3673
+ result.push(a);
3674
+ const intersectors = obstacles.filter(
3675
+ (obs) => segmentIntersectsBox(a, b, obs)
3676
+ );
3677
+ if (intersectors.length === 0) {
3678
+ continue;
3679
+ }
3680
+ const mx = (a.x + b.x) / 2;
3681
+ const my = (a.y + b.y) / 2;
3682
+ const isHorizontal = a.y === b.y;
3683
+ const margin = 12;
3684
+ let bestWaypoint = null;
3685
+ let bestDist = Infinity;
3686
+ for (const obs of intersectors) {
3687
+ const candidates = isHorizontal ? [
3688
+ { x: mx, y: obs.y - margin },
3689
+ { x: mx, y: obs.y + obs.height + margin }
3690
+ ] : [
3691
+ { x: obs.x - margin, y: my },
3692
+ { x: obs.x + obs.width + margin, y: my }
3693
+ ];
3694
+ for (const wp of candidates) {
3695
+ const dist = Math.hypot(wp.x - mx, wp.y - my);
3696
+ if (dist < bestDist) {
3697
+ bestDist = dist;
3698
+ bestWaypoint = wp;
3699
+ }
3700
+ }
3701
+ }
3702
+ if (bestWaypoint !== null) {
3703
+ result.push(bestWaypoint);
3704
+ improved = true;
3705
+ }
3706
+ }
3707
+ const last = points[points.length - 1];
3708
+ if (last !== void 0) {
3709
+ result.push(last);
3710
+ }
3711
+ return improved ? result : null;
3712
+ }
3533
3713
  function fallbackRoute(input, defaultAnchors) {
3534
3714
  return [
3535
3715
  getEdgePort(
@@ -4026,6 +4206,7 @@ function solveDiagram(diagram, options = {}) {
4026
4206
  ];
4027
4207
  const initialContentBounds = layoutBoxes.length === 0 ? { x: 0, y: 0, width: 0} : unionBoxes(layoutBoxes);
4028
4208
  placeEvidenceBlocks(
4209
+ options.obstacleMargin ?? 0,
4029
4210
  [
4030
4211
  ...coordinatedMatrices,
4031
4212
  ...coordinatedTables,
@@ -4092,17 +4273,35 @@ function solveDiagram(diagram, options = {}) {
4092
4273
  ...baseTextAnnotations.filter(isPreRouteTextObstacle),
4093
4274
  ...frameTextAnnotation.filter(isPreRouteTextObstacle)
4094
4275
  ];
4276
+ const margin = options.obstacleMargin ?? 0;
4277
+ const softObstacles = [
4278
+ ...coordinatedTables.map((table) => expandBox(table.box, margin)),
4279
+ ...coordinatedEvidencePanels.map((panel) => expandBox(panel.box, margin))
4280
+ ];
4281
+ const hardObstacles = coordinatedMatrices.map(
4282
+ (matrix) => expandBox(matrix.box, margin)
4283
+ );
4284
+ const titleBarObstacles = [];
4285
+ if (frame !== void 0) {
4286
+ titleBarObstacles.push(expandBox(frame.titleBox, margin));
4287
+ }
4288
+ for (const swimlane of coordinatedSwimlanes) {
4289
+ for (const lane of swimlane.lanes) {
4290
+ if (lane.headerBox !== void 0 && lane.headerBox.width > 0 && lane.headerBox.height > 0) {
4291
+ titleBarObstacles.push(expandBox(lane.headerBox, margin));
4292
+ }
4293
+ }
4294
+ }
4095
4295
  const coordinatedEdges = coordinateEdges(
4096
4296
  styledEdges,
4097
4297
  nodeGeometryById,
4098
4298
  coordinatedNodes,
4099
- [...nodeGeometryById.values()].map((geometry) => geometry.obstacleBox),
4100
- [
4101
- ...coordinatedTables.map((table) => table.box),
4102
- ...coordinatedEvidencePanels.map((panel) => panel.box)
4103
- ],
4299
+ [...nodeGeometryById.values()].map(
4300
+ (geometry) => options.routingGutter === void 0 ? geometry.obstacleBox : expandBox(geometry.obstacleBox, options.routingGutter)
4301
+ ),
4302
+ [...softObstacles, ...titleBarObstacles],
4104
4303
  routingTextObstacles,
4105
- coordinatedMatrices.map((matrix) => matrix.box),
4304
+ hardObstacles,
4106
4305
  diagram.direction,
4107
4306
  options,
4108
4307
  diagnostics
@@ -4137,6 +4336,16 @@ function solveDiagram(diagram, options = {}) {
4137
4336
  options.pageBounds
4138
4337
  )
4139
4338
  );
4339
+ let degraded = false;
4340
+ const resultDiagnostics = diagnostics.map((diagnostic) => {
4341
+ if (DELIVERABILITY_DIAGNOSTIC_CODES.has(diagnostic.code)) {
4342
+ degraded = true;
4343
+ if (options.strict) {
4344
+ return { ...diagnostic, severity: "error" };
4345
+ }
4346
+ }
4347
+ return diagnostic;
4348
+ });
4140
4349
  return {
4141
4350
  id: diagram.id,
4142
4351
  ...diagram.title === void 0 ? {} : { title: diagram.title },
@@ -4148,7 +4357,8 @@ function solveDiagram(diagram, options = {}) {
4148
4357
  ...coordinatedMatrices.length === 0 ? {} : { matrices: coordinatedMatrices },
4149
4358
  ...coordinatedTables.length === 0 ? {} : { tables: coordinatedTables },
4150
4359
  ...coordinatedEvidencePanels.length === 0 ? {} : { evidencePanels: coordinatedEvidencePanels },
4151
- diagnostics,
4360
+ diagnostics: resultDiagnostics,
4361
+ degraded,
4152
4362
  bounds: frame === void 0 ? unionBoxes(boundsBase) : unionBoxes([...boundsBase, frame.box, frame.titleBox]),
4153
4363
  ...frame === void 0 ? {} : { frame },
4154
4364
  ...textAnnotations.length === 0 ? {} : { textAnnotations },
@@ -5534,16 +5744,25 @@ function blockBox(block, defaultSize) {
5534
5744
  height: block.size?.height ?? defaultSize.height
5535
5745
  };
5536
5746
  }
5537
- function placeEvidenceBlocks(blocks, contentBounds) {
5747
+ function placeEvidenceBlocks(obstacleMargin, blocks, contentBounds) {
5748
+ const margin = normalizeInsets(obstacleMargin);
5749
+ const horizontalGap = Math.max(
5750
+ DEFAULT_EVIDENCE_BLOCK_GAP,
5751
+ margin.right + margin.left
5752
+ );
5753
+ const verticalGap = Math.max(
5754
+ DEFAULT_EVIDENCE_BLOCK_GAP,
5755
+ margin.bottom + margin.top
5756
+ );
5538
5757
  let nextY = contentBounds.y;
5539
- const x = contentBounds.x + contentBounds.width + DEFAULT_EVIDENCE_BLOCK_GAP;
5758
+ const x = contentBounds.x + contentBounds.width + horizontalGap;
5540
5759
  for (const block of blocks) {
5541
5760
  if (block.position !== void 0) {
5542
5761
  continue;
5543
5762
  }
5544
5763
  block.box.x = x;
5545
5764
  block.box.y = nextY;
5546
- nextY += block.box.height + DEFAULT_EVIDENCE_BLOCK_GAP;
5765
+ nextY += block.box.height + verticalGap;
5547
5766
  }
5548
5767
  }
5549
5768
  function columnXOffsets(table, box) {
@@ -6399,9 +6618,7 @@ function edgeLabelAnchorCandidates(points, placement, layout2) {
6399
6618
  { x: placement.x, y: placement.y + offset }
6400
6619
  );
6401
6620
  }
6402
- return candidates;
6403
- }
6404
- if (segment.start.x === segment.end.x) {
6621
+ } else if (segment.start.x === segment.end.x) {
6405
6622
  const needed = layout2.box.width / 2 + EDGE_LABEL_CLEARANCE;
6406
6623
  const maxSteps = Math.max(12, Math.ceil(needed / EDGE_LABEL_CLEARANCE));
6407
6624
  for (let step = 1; step <= maxSteps; step += 1) {
@@ -6411,7 +6628,83 @@ function edgeLabelAnchorCandidates(points, placement, layout2) {
6411
6628
  { x: placement.x - offset, y: placement.y }
6412
6629
  );
6413
6630
  }
6414
- return candidates;
6631
+ } else {
6632
+ const dx = segment.end.x - segment.start.x;
6633
+ const dy = segment.end.y - segment.start.y;
6634
+ const segLen = Math.hypot(dx, dy);
6635
+ if (segLen > 0) {
6636
+ const nx = -dy / segLen;
6637
+ const ny = dx / segLen;
6638
+ const needed = (Math.abs(nx) * layout2.box.width + Math.abs(ny) * layout2.box.height) / 2 + EDGE_LABEL_CLEARANCE;
6639
+ const maxSteps = Math.max(12, Math.ceil(needed / EDGE_LABEL_CLEARANCE));
6640
+ for (let step = 1; step <= maxSteps; step += 1) {
6641
+ const offset = EDGE_LABEL_CLEARANCE * step;
6642
+ candidates.push(
6643
+ { x: placement.x + nx * offset, y: placement.y + ny * offset },
6644
+ { x: placement.x - nx * offset, y: placement.y - ny * offset }
6645
+ );
6646
+ }
6647
+ }
6648
+ }
6649
+ const totalLen = points.reduce((sum, p, idx) => {
6650
+ if (idx === 0) return 0;
6651
+ const prev = points[idx - 1];
6652
+ return sum + Math.hypot((p?.x ?? 0) - (prev?.x ?? 0), (p?.y ?? 0) - (prev?.y ?? 0));
6653
+ }, 0);
6654
+ if (totalLen > 200) {
6655
+ for (const ratio of [0.25, 0.75]) {
6656
+ const qp = labelPlacementAtRatio(points, ratio, totalLen);
6657
+ if (qp !== void 0) {
6658
+ candidates.push(qp);
6659
+ const qTargetDist = totalLen * ratio;
6660
+ let qTravelled = 0;
6661
+ let seg;
6662
+ for (let si = 1; si < points.length; si++) {
6663
+ const sp = points[si - 1];
6664
+ const sc = points[si];
6665
+ if (sp === void 0 || sc === void 0) continue;
6666
+ const sl = Math.hypot(sc.x - sp.x, sc.y - sp.y);
6667
+ if (sl <= 0) continue;
6668
+ if (qTravelled + sl >= qTargetDist) {
6669
+ seg = { start: sp, end: sc, length: sl };
6670
+ break;
6671
+ }
6672
+ qTravelled += sl;
6673
+ }
6674
+ if (seg !== void 0) {
6675
+ const segLen = Math.hypot(
6676
+ seg.end.x - seg.start.x,
6677
+ seg.end.y - seg.start.y
6678
+ );
6679
+ const qpNeeded = seg.start.y === seg.end.y ? layout2.box.height / 2 + EDGE_LABEL_CLEARANCE : seg.start.x === seg.end.x ? layout2.box.width / 2 + EDGE_LABEL_CLEARANCE : (Math.abs(seg.start.y - seg.end.y) * layout2.box.width + Math.abs(seg.end.x - seg.start.x) * layout2.box.height) / (2 * segLen) + EDGE_LABEL_CLEARANCE;
6680
+ const qpMaxSteps = Math.max(
6681
+ 12,
6682
+ Math.ceil(qpNeeded / EDGE_LABEL_CLEARANCE)
6683
+ );
6684
+ for (let step = 1; step <= qpMaxSteps; step += 1) {
6685
+ const offset = EDGE_LABEL_CLEARANCE * step;
6686
+ if (seg.start.y === seg.end.y) {
6687
+ candidates.push(
6688
+ { x: qp.x, y: qp.y - offset },
6689
+ { x: qp.x, y: qp.y + offset }
6690
+ );
6691
+ } else if (seg.start.x === seg.end.x) {
6692
+ candidates.push(
6693
+ { x: qp.x - offset, y: qp.y },
6694
+ { x: qp.x + offset, y: qp.y }
6695
+ );
6696
+ } else {
6697
+ const nx = -(seg.end.y - seg.start.y) / segLen;
6698
+ const ny = (seg.end.x - seg.start.x) / segLen;
6699
+ candidates.push(
6700
+ { x: qp.x + nx * offset, y: qp.y + ny * offset },
6701
+ { x: qp.x - nx * offset, y: qp.y - ny * offset }
6702
+ );
6703
+ }
6704
+ }
6705
+ }
6706
+ }
6707
+ }
6415
6708
  }
6416
6709
  return candidates;
6417
6710
  }
@@ -6468,6 +6761,34 @@ function nonZeroSegments2(points) {
6468
6761
  }
6469
6762
  return segments;
6470
6763
  }
6764
+ function labelPlacementAtRatio(points, ratio, totalLength) {
6765
+ if (points.length < 2 || ratio < 0 || ratio > 1) {
6766
+ return void 0;
6767
+ }
6768
+ const targetDist = totalLength * ratio;
6769
+ let travelled = 0;
6770
+ for (let idx = 1; idx < points.length; idx++) {
6771
+ const prev = points[idx - 1];
6772
+ const curr = points[idx];
6773
+ if (prev === void 0 || curr === void 0) {
6774
+ continue;
6775
+ }
6776
+ const segLen = Math.hypot(curr.x - prev.x, curr.y - prev.y);
6777
+ if (segLen <= 0) {
6778
+ continue;
6779
+ }
6780
+ if (travelled + segLen >= targetDist) {
6781
+ const t = (targetDist - travelled) / segLen;
6782
+ const offset = labelOffset2({ start: prev, end: curr, length: segLen });
6783
+ return {
6784
+ x: prev.x + (curr.x - prev.x) * t + offset.x,
6785
+ y: prev.y + (curr.y - prev.y) * t + offset.y
6786
+ };
6787
+ }
6788
+ travelled += segLen;
6789
+ }
6790
+ return void 0;
6791
+ }
6471
6792
  function labelOffset2(segment) {
6472
6793
  const offset = 10;
6473
6794
  const dx = segment.end.x - segment.start.x;
@@ -6581,7 +6902,7 @@ function isValidEdgeId(value) {
6581
6902
  return value.length > 0 && EDGE_ID_PATTERN.test(value);
6582
6903
  }
6583
6904
  var directionSchema = z.enum(["TB", "LR", "BT", "RL"]);
6584
- var routeKindSchema = z.enum(["orthogonal", "straight"]);
6905
+ var routeKindSchema = z.enum(["orthogonal", "straight", "obstacle-avoiding"]);
6585
6906
  var outputFormatSchema = z.enum(["svg", "excalidraw"]);
6586
6907
  var edgeStrokeStyleSchema = z.enum(["solid", "dashed"]);
6587
6908
  var edgeArrowheadSchema = z.enum(["triangle", "hollowTriangle"]);
@@ -7180,7 +7501,7 @@ function renderDiagramDsl(source, options = {}) {
7180
7501
  return { diagnostics };
7181
7502
  }
7182
7503
  const solved = solveDiagram(normalized.diagram, {
7183
- routeKind: normalized.diagram.metadata?.routeKind === "straight" ? "straight" : "orthogonal",
7504
+ routeKind: normalized.diagram.metadata?.routeKind === "straight" ? "straight" : normalized.diagram.metadata?.routeKind === "obstacle-avoiding" ? "obstacle-avoiding" : "orthogonal",
7184
7505
  ...solvePortShiftingOption(normalized.diagram.metadata?.portShifting),
7185
7506
  ...options.textMeasurer === void 0 ? {} : { textMeasurer: options.textMeasurer }
7186
7507
  });