@weasel-js/diagram-formats 1.13.0-rc.0 → 1.14.0

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/index.js CHANGED
@@ -1,5 +1,5 @@
1
+ import { placedPagesOf, scenePoseAdapter, layoutPages, PAGES_DOC_KEY, documentOf, isAnnotationLayer, boundsOfPath, layoutTextPose, warmRender, renderSceneToPixels, planPixelRender, viewToMat3, createRasterSession, pageHolding, effectivePose, derivedDepOf, IDENTITY_POSE_COMPOSITION, pageName, composeWorldPose, derivedPartsOf, INHERIT, resolvePartPaint, createScene, mat3 } from '@weasel-js/core';
1
2
  import { diagramThemeFrom, DIAGRAM_THEME_KEY, diagramLabelOf, offPageSplits, diagramScene, themeDocValue, diagramShape, markShape, documentBoundsOf, dataNodeStyle, dataEdgeStyle, diagramEdgeOf, diagramContainerOf, NODE_STROKE_WIDTH, dataRegionStyle, poolAxisOf, titleIdOf, layoutOwnsRoute, EDGE_STROKE_WIDTH, diagramThemeOf, edgeIdOf, layoutOwnsPort, DEFAULT_PORTS, LANE_STROKE_WIDTH } from '@weasel-js/diagram';
2
- import { placedPagesOf, layoutPages, PAGES_DOC_KEY, documentOf, isAnnotationLayer, boundsOfPath, layoutTextPose, warmRender, renderSceneToPixels, planPixelRender, viewToMat3, createRasterSession, pageHolding, effectivePose, derivedDepOf, pageName, derivedPartsOf, INHERIT, resolvePartPaint, createScene, mat3 } from '@weasel-js/core';
3
3
  import { svgNodesFromKit, svgLeafFromKit, warmSvg, serializeSvg, escapeAttr, svgPaintFromKit, svgStrokeFromKit } from '@weasel-js/svg';
4
4
  import { writePdf, registryFontSource } from '@weasel-js/pdf';
5
5
 
@@ -65,6 +65,7 @@ function laidOutPage(page, opts) {
65
65
  const specs = diagramScene(pinned, {
66
66
  layout: "layered",
67
67
  theme: opts.theme,
68
+ composition: IDENTITY_POSE_COMPOSITION,
68
69
  ...opts.measure ? { measure: opts.measure } : {},
69
70
  ...page.direction ? { layoutOptions: { direction: page.direction } } : {}
70
71
  });
@@ -479,23 +480,47 @@ var OUTLINES = {
479
480
  ellipse: "ellipse",
480
481
  oval: "ellipse",
481
482
  circle: "ellipse",
482
- doublecircle: "ellipse",
483
+ doublecircle: "doubleEllipse",
483
484
  point: "ellipse",
484
485
  diamond: "diamond",
485
486
  hexagon: "hexagon",
486
487
  parallelogram: "parallelogram",
487
- trapezium: "trapezoid"
488
+ trapezium: "trapezoid",
489
+ cylinder: "cylinder",
490
+ note: "note",
491
+ folder: "folder",
492
+ tab: "folder",
493
+ octagon: "octagon",
494
+ triangle: "triangle",
495
+ box3d: "cube"
488
496
  };
497
+ var OUTLINE_ATTR = "weasel_outline";
498
+ var SHAPE_NAMES = {
499
+ stadium: { shape: "box", rounded: true, marked: true },
500
+ roundRect: { shape: "box", rounded: true },
501
+ trapezoid: { shape: "trapezium" },
502
+ cube: { shape: "box3d" },
503
+ doubleEllipse: { shape: "doublecircle" }
504
+ };
505
+ var SAME_NAMES = /* @__PURE__ */ new Set([
506
+ "diamond",
507
+ "ellipse",
508
+ "hexagon",
509
+ "parallelogram",
510
+ "cylinder",
511
+ "note",
512
+ "folder",
513
+ "octagon",
514
+ "triangle"
515
+ ]);
489
516
  function outlineOf(shape, styles) {
490
517
  const outline = OUTLINES[shape.toLowerCase()];
491
518
  if (outline === void 0) return null;
492
- return outline === "rect" && styles.includes("rounded") ? "stadium" : outline;
519
+ return outline === "rect" && styles.includes("rounded") ? "roundRect" : outline;
493
520
  }
494
521
  function shapeOf(outline) {
495
522
  if (outline === void 0 || typeof outline !== "string" || outline === "rect") return { shape: "box" };
496
- if (outline === "stadium") return { shape: "box", rounded: true };
497
- if (outline === "trapezoid") return { shape: "trapezium" };
498
- return { shape: outline };
523
+ return SHAPE_NAMES[outline] ?? (SAME_NAMES.has(outline) ? { shape: outline } : { shape: "box", missing: true, marked: true });
499
524
  }
500
525
  var ARROWS = {
501
526
  normal: "arrow",
@@ -509,8 +534,13 @@ var ARROWS = {
509
534
  obox: "square",
510
535
  tee: "bar",
511
536
  empty: "arrow-open",
512
- onormal: "arrow-open",
513
- vee: "arrow-concave"
537
+ onormal: "triangle-hollow",
538
+ vee: "arrow-concave",
539
+ crow: "crow-many",
540
+ teetee: "crow-one",
541
+ teeodot: "crow-zero-one",
542
+ crowtee: "crow-one-many",
543
+ crowodot: "crow-zero-many"
514
544
  };
515
545
  var ARROW_NAMES = {
516
546
  arrow: "normal",
@@ -520,7 +550,13 @@ var ARROW_NAMES = {
520
550
  "diamond-hollow": "odiamond",
521
551
  circle: "dot",
522
552
  square: "box",
523
- bar: "tee"
553
+ bar: "tee",
554
+ "triangle-hollow": "onormal",
555
+ "crow-many": "crow",
556
+ "crow-one": "teetee",
557
+ "crow-zero-one": "teeodot",
558
+ "crow-one-many": "crowtee",
559
+ "crow-zero-many": "crowodot"
524
560
  };
525
561
  var markerOf = (name) => ARROWS[name.toLowerCase()];
526
562
  function arrowName(marker2) {
@@ -538,7 +574,7 @@ var READ = {
538
574
  root: /* @__PURE__ */ new Set(["rankdir", "label", "bb"]),
539
575
  cluster: /* @__PURE__ */ new Set(["label", "style", "color", "fillcolor", "bgcolor", "pencolor", "fontcolor"]),
540
576
  plain: /* @__PURE__ */ new Set(),
541
- node: /* @__PURE__ */ new Set(["label", "shape", "style", "color", "fillcolor", "fontcolor", "penwidth", "width", "height", "pos"]),
577
+ node: /* @__PURE__ */ new Set([OUTLINE_ATTR, "label", "shape", "style", "color", "fillcolor", "fontcolor", "penwidth", "width", "height", "pos"]),
542
578
  edge: /* @__PURE__ */ new Set(["label", "color", "fontcolor", "penwidth", "style", "dir", "arrowhead", "arrowtail", "tailport", "headport"])
543
579
  };
544
580
  var DIRECTIONS = { TB: "down", BT: "up", LR: "right", RL: "left" };
@@ -632,7 +668,7 @@ function nodeColors(attrs2, styles) {
632
668
  function readNode(r, id, attrs2) {
633
669
  const styles = stylesOf(str(attrs2, "style"));
634
670
  const shape = str(attrs2, "shape") ?? "ellipse";
635
- let outline = outlineOf(shape, styles);
671
+ let outline = str(attrs2, OUTLINE_ATTR) ?? outlineOf(shape, styles);
636
672
  if (outline === null) {
637
673
  r.warnings.list("DOT shapes read as rectangles", shape);
638
674
  outline = "rect";
@@ -770,16 +806,23 @@ function readDot(text) {
770
806
  });
771
807
  return { document: { pages: [page] }, warnings: r.warnings.all() };
772
808
  }
773
- function nodeLines(node, warnings, format) {
809
+
810
+ // src/rowLines.ts
811
+ function rowLines(node, dropped) {
774
812
  if (node.rows === void 0) return [...node.lines ?? []];
775
813
  const lines = [];
776
814
  for (const row of node.rows) {
777
815
  if (row.kind === "label") lines.push(row.text);
778
816
  else if (row.kind === "field") lines.push(`${row.label}: ${row.value}`);
779
- else warnings.add(`${format} holds only text in a shape; its port rows and slots were dropped.`);
817
+ else if (row.kind !== "divider") dropped();
780
818
  }
781
819
  return lines;
782
820
  }
821
+
822
+ // src/graphWrite.ts
823
+ function nodeLines(node, warnings, format) {
824
+ return rowLines(node, () => warnings.add(`${format} holds only text in a shape; its port rows and slots were dropped.`));
825
+ }
783
826
  function clusterTree(page, theme, warnings, format) {
784
827
  const parent = /* @__PURE__ */ new Map();
785
828
  const claim2 = (member, owner) => {
@@ -872,7 +915,8 @@ var attrList = (attrs2) => {
872
915
  var color = (key, value) => value === void 0 ? null : `${key}="${hexColor(value)}"`;
873
916
  var num = (n) => String(Math.round(n * 1e4) / 1e4);
874
917
  function nodeAttrs(out, node, placed) {
875
- const { shape, rounded } = shapeOf(node.outline);
918
+ const { shape, rounded, missing, marked } = shapeOf(node.outline);
919
+ if (missing) out.warnings.add("DOT has no shape for some outlines; they were written as boxes.");
876
920
  const own = changed(nodeStyleIn(out, node), nodeStyleIn(out));
877
921
  const styles = [rounded ? "rounded" : null, "filled", own.dash !== void 0 ? "dashed" : null].filter((s) => s !== null);
878
922
  const page = out.page.height;
@@ -880,6 +924,7 @@ function nodeAttrs(out, node, placed) {
880
924
  `label=${quoteLabel(nodeLines(node, out.warnings, "DOT"))}`,
881
925
  shape !== "box" ? `shape=${shape}` : null,
882
926
  styles.length > 1 ? `style="${styles.join(",")}"` : null,
927
+ marked ? `${OUTLINE_ATTR}=${dotId(node.outline)}` : null,
883
928
  color("fillcolor", own.fill),
884
929
  color("color", own.stroke),
885
930
  color("fontcolor", own.text),
@@ -1208,6 +1253,10 @@ function cellLines(value, html) {
1208
1253
 
1209
1254
  // src/drawXml/mapping.ts
1210
1255
  var STADIUM_ARC = 50;
1256
+ var LABEL_BELOW = [["verticalLabelPosition", "bottom"], ["verticalAlign", "top"]];
1257
+ var event = (outline) => [["shape", "mxgraph.bpmn.event"], ["outline", outline], ["symbol", "general"], ...LABEL_BELOW];
1258
+ var gateway = (...parts) => [["shape", "mxgraph.bpmn.gateway2"], ...parts, ...LABEL_BELOW];
1259
+ var device = (name) => [["shape", `mxgraph.networks.${name}`], ...LABEL_BELOW];
1211
1260
  var SHAPES = [
1212
1261
  { name: "rhombus", outline: "diamond", write: ["rhombus"] },
1213
1262
  { name: "ellipse", outline: "ellipse", write: ["ellipse"] },
@@ -1217,22 +1266,72 @@ var SHAPES = [
1217
1266
  name: "trapezoid",
1218
1267
  outline: "trapezoid",
1219
1268
  write: [["shape", "trapezoid"], ["perimeter", "trapezoidPerimeter"], ["direction", "north"], ["size", 0.25]]
1220
- }
1269
+ },
1270
+ { name: "cylinder3", outline: "cylinder", write: [["shape", "cylinder3"], ["boundedLbl", 1], ["backgroundOutline", 1], ["size", 15]] },
1271
+ { name: "document", outline: "document", write: [["shape", "document"], ["boundedLbl", 1]] },
1272
+ { name: "note", outline: "note", write: [["shape", "note"], ["size", 20]] },
1273
+ { name: "cloud", outline: "cloud", write: ["ellipse", ["shape", "cloud"]] },
1274
+ { name: "triangle", outline: "triangle", write: ["triangle", ["direction", "north"]] },
1275
+ { name: "cube", outline: "cube", write: [["shape", "cube"], ["boundedLbl", 1], ["flipH", 1]] },
1276
+ { name: "folder", outline: "folder", write: [["shape", "folder"], ["tabPosition", "left"]] },
1277
+ { name: "umlActor", outline: "actor", write: [["shape", "umlActor"], ["verticalLabelPosition", "bottom"], ["verticalAlign", "top"]] },
1278
+ { name: "doubleEllipse", outline: "doubleEllipse", write: ["ellipse", ["shape", "doubleEllipse"]] },
1279
+ { name: "mxgraph.bpmn.event", when: ["outline", "standard"], outline: "event", write: event("standard") },
1280
+ { name: "mxgraph.bpmn.event", when: ["outline", "catching"], outline: "intermediateEvent", write: event("catching") },
1281
+ { name: "mxgraph.bpmn.event", when: ["outline", "throwing"], outline: "intermediateEvent" },
1282
+ { name: "mxgraph.bpmn.event", outline: "event" },
1283
+ // As draw.io's own BPMN palette (Sidebar-BPMN.js) writes them: only exclusive, parallel and complex are a `gwType`;
1284
+ // the default, `event`, draws the event `outline` and `symbol` name inside the diamond.
1285
+ { name: "mxgraph.bpmn.gateway2", when: ["gwType", "exclusive"], outline: "exclusiveGateway", write: gateway(["outline", "none"], ["symbol", "none"], ["gwType", "exclusive"]) },
1286
+ { name: "mxgraph.bpmn.gateway2", when: ["gwType", "parallel"], outline: "parallelGateway", write: gateway(["outline", "none"], ["symbol", "none"], ["gwType", "parallel"]) },
1287
+ { name: "mxgraph.bpmn.gateway2", when: ["gwType", "complex"], outline: "diamond" },
1288
+ { name: "mxgraph.bpmn.gateway2", when: ["outline", "end"], outline: "inclusiveGateway", write: gateway(["outline", "end"], ["symbol", "general"]) },
1289
+ { name: "mxgraph.bpmn.gateway2", when: ["outline", "catching"], outline: "eventGateway", write: gateway(["outline", "catching"], ["symbol", "multiple"]) },
1290
+ // What this package wrote before 2026-10-27, which draw.io draws as a bare diamond.
1291
+ { name: "mxgraph.bpmn.gateway2", when: ["gwType", "inclusive"], outline: "inclusiveGateway" },
1292
+ { name: "mxgraph.bpmn.gateway2", when: ["gwType", "eventBased"], outline: "eventGateway" },
1293
+ { name: "mxgraph.bpmn.gateway2", outline: "diamond" },
1294
+ {
1295
+ name: "mxgraph.bpmn.task",
1296
+ when: ["isLoopSub", "1"],
1297
+ outline: "subprocess",
1298
+ write: [["shape", "mxgraph.bpmn.task"], ["taskMarker", "abstract"], ["isLoopSub", 1], ["rounded", 1]]
1299
+ },
1300
+ { name: "mxgraph.networks.server", outline: "server", write: device("server") },
1301
+ { name: "mxgraph.networks.router", outline: "router", write: device("router") },
1302
+ { name: "mxgraph.networks.switch", outline: "switch", write: device("switch") },
1303
+ { name: "mxgraph.networks.firewall", outline: "firewall", write: device("firewall") },
1304
+ { name: "mxgraph.networks.laptop", outline: "laptop", write: device("laptop") },
1305
+ { name: "mxgraph.networks.pc", outline: "desktop", write: device("pc") },
1306
+ { name: "mxgraph.networks.mobile", outline: "phone", write: device("mobile") },
1307
+ { name: "mxgraph.networks.printer", outline: "printer", write: device("printer") },
1308
+ { name: "mxgraph.networks.user_male", outline: "user", write: device("user_male") },
1309
+ // mxgraph.networks has no globe; this is the Office set's.
1310
+ { name: "mxgraph.office.concepts.globe_internet", outline: "globe", write: [["shape", "mxgraph.office.concepts.globe_internet"], ...LABEL_BELOW] }
1221
1311
  ];
1312
+ function shapeEntry(name, value) {
1313
+ return SHAPES.find((s) => s.name === name && (s.when === void 0 || value(s.when[0]) === s.when[1]));
1314
+ }
1222
1315
  var BOX_NAMES = /* @__PURE__ */ new Set(["rect", "rectangle", "text", "label"]);
1223
1316
  var ORTHOGONAL_EDGE_STYLES = /* @__PURE__ */ new Set(["orthogonalEdgeStyle", "elbowEdgeStyle", "entityRelationEdgeStyle"]);
1224
1317
  var MARKERS_READ = {
1225
1318
  classic: { filled: "arrow" },
1226
1319
  classicThin: { filled: "arrow" },
1227
- block: { filled: "arrow", hollow: "arrow-open" },
1228
- blockThin: { filled: "arrow", hollow: "arrow-open" },
1320
+ block: { filled: "arrow", hollow: "triangle-hollow" },
1321
+ blockThin: { filled: "arrow", hollow: "triangle-hollow" },
1229
1322
  open: { filled: "arrow-open" },
1230
1323
  openThin: { filled: "arrow-open" },
1231
1324
  diamond: { filled: "diamond", hollow: "diamond-hollow" },
1232
1325
  diamondThin: { filled: "diamond", hollow: "diamond-hollow" },
1233
1326
  oval: { filled: "circle" },
1234
1327
  box: { filled: "square" },
1235
- dash: { filled: "bar" }
1328
+ dash: { filled: "bar" },
1329
+ ERone: { filled: "bar" },
1330
+ ERmandOne: { filled: "crow-one" },
1331
+ ERmany: { filled: "crow-many" },
1332
+ ERzeroToOne: { filled: "crow-zero-one" },
1333
+ ERoneToMany: { filled: "crow-one-many" },
1334
+ ERzeroToMany: { filled: "crow-zero-many" }
1236
1335
  };
1237
1336
  function markerOf2(name, fill) {
1238
1337
  if (name === "none" || name === "") return null;
@@ -1248,7 +1347,13 @@ var MARKERS_WRITE = {
1248
1347
  "diamond-hollow": ["diamond", 0],
1249
1348
  "circle": ["oval", 1],
1250
1349
  "square": ["box", 1],
1251
- "bar": ["dash", 1]
1350
+ "bar": ["dash", 1],
1351
+ "triangle-hollow": ["block", 0],
1352
+ "crow-one": ["ERmandOne", 0],
1353
+ "crow-many": ["ERmany", 0],
1354
+ "crow-zero-one": ["ERzeroToOne", 0],
1355
+ "crow-one-many": ["ERoneToMany", 0],
1356
+ "crow-zero-many": ["ERzeroToMany", 0]
1252
1357
  };
1253
1358
  function markerStyle(marker2) {
1254
1359
  if (marker2 === null || marker2 === void 0) return ["none", 1];
@@ -1258,9 +1363,9 @@ function markerStyle(marker2) {
1258
1363
  // src/drawXml/readStyle.ts
1259
1364
  function outlineOf2(style, warn) {
1260
1365
  const shape = shapeOf2(style);
1261
- const known = SHAPES.find((s) => s.name === shape);
1366
+ const known = shapeEntry(shape, (key) => style.values.get(key));
1262
1367
  if (known !== void 0) return known.outline;
1263
- if (styleFlag(style, "rounded") && (styleNumber(style, "arcSize") ?? 0) >= STADIUM_ARC) return "stadium";
1368
+ if (styleFlag(style, "rounded")) return (styleNumber(style, "arcSize") ?? 0) >= STADIUM_ARC ? "stadium" : "roundRect";
1264
1369
  if (shape !== void 0 && !BOX_NAMES.has(shape)) warn(`Shapes of kind "${shape}" were drawn as rects.`);
1265
1370
  return "rect";
1266
1371
  }
@@ -1295,13 +1400,19 @@ function textOf(cell) {
1295
1400
  const style = defined({
1296
1401
  fontSize: styleNumber(cell.style, "fontSize"),
1297
1402
  fontFamily: cell.style.values.get("fontFamily") || void 0,
1298
- bold: fontStyle !== void 0 && (fontStyle & 1) === 1 ? true : void 0
1403
+ bold: fontStyle !== void 0 && (fontStyle & 1) === 1 ? true : void 0,
1404
+ italic: fontStyle !== void 0 && (fontStyle & 2) === 2 ? true : void 0
1299
1405
  });
1300
1406
  if (style === void 0) return { lines };
1301
1407
  return { rows: lines.map((text) => ({ kind: "label", text, style })) };
1302
1408
  }
1303
1409
  var VERTICAL = { top: "top", middle: "center", bottom: "bottom" };
1304
- var verticalAlignOf = (style) => VERTICAL[style.values.get("verticalAlign") ?? ""];
1410
+ function verticalAlignOf(style) {
1411
+ const raw = style.values.get("verticalAlign") ?? "";
1412
+ const own = shapeEntry(shapeOf2(style), (key) => style.values.get(key))?.write;
1413
+ if (own?.some((part) => Array.isArray(part) && part[0] === "verticalAlign" && part[1] === raw)) return void 0;
1414
+ return VERTICAL[raw];
1415
+ }
1305
1416
  function routerOf(style) {
1306
1417
  if (styleFlag(style, "curved")) return "bezier";
1307
1418
  return ORTHOGONAL_EDGE_STYLES.has(style.values.get("edgeStyle") ?? "") ? "orthogonal" : "straight";
@@ -1579,25 +1690,24 @@ function colorParts(style, fill) {
1579
1690
  function outlineParts(node, warn) {
1580
1691
  const outline = node.outline ?? "rect";
1581
1692
  if (outline === "stadium") return [["rounded", 1], ["arcSize", STADIUM_ARC]];
1582
- const shape = SHAPES.find((s) => s.outline === outline);
1583
- if (shape !== void 0) return shape.write;
1693
+ if (outline === "roundRect") return [["rounded", 1]];
1694
+ const shape = SHAPES.find((s) => s.outline === outline && s.write !== void 0);
1695
+ if (shape?.write !== void 0) return shape.write;
1584
1696
  if (typeof outline !== "string") warn("Shapes drawn with an outline path of their own were written as rects.");
1697
+ else if (outline !== "rect") warn(`Shapes of kind "${outline}" were written as rects.`);
1585
1698
  return [["rounded", 0]];
1586
1699
  }
1587
1700
  function nodeLines2(node, warn) {
1588
- if (node.rows === void 0) return [...node.lines ?? []];
1589
- const lines = [];
1590
- for (const row of node.rows) {
1591
- if (row.kind === "label") lines.push(row.text);
1592
- else if (row.kind === "field") lines.push(`${row.label}: ${row.value}`);
1593
- else warn("Port rows and slots inside shapes were left out.");
1594
- }
1595
- return lines;
1701
+ return rowLines(node, () => warn("Port rows and slots inside shapes were left out."));
1702
+ }
1703
+ function fontBits(style) {
1704
+ const bits = (style.bold === true ? 1 : 0) | (style.italic === true ? 2 : 0);
1705
+ return bits === 0 ? void 0 : bits;
1596
1706
  }
1597
1707
  function fontParts(rows) {
1598
1708
  const style = rows?.find((r) => r.kind === "label" || r.kind === "field")?.style;
1599
1709
  if (style === void 0) return [];
1600
- return [["fontSize", style.fontSize], ["fontFamily", style.fontFamily], ["fontStyle", style.bold === true ? 1 : void 0]];
1710
+ return [["fontSize", style.fontSize], ["fontFamily", style.fontFamily], ["fontStyle", fontBits(style)]];
1601
1711
  }
1602
1712
  var VERTICAL2 = { top: "top", center: "middle", bottom: "bottom" };
1603
1713
  function nodeStyle(node, theme, warn) {
@@ -1813,7 +1923,7 @@ function vertices(data, theme, headerOf, warn) {
1813
1923
  function writePage(page, index, theme, warn) {
1814
1924
  const laid = needsLayout(page) ? laidOutPage(page, { theme }) : page;
1815
1925
  const { data } = laid;
1816
- const specs = new Map(diagramScene(data, { layout: "none", theme }).map((s) => [s.id, s]));
1926
+ const specs = new Map(diagramScene(data, { layout: "none", theme, composition: IDENTITY_POSE_COMPOSITION }).map((s) => [s.id, s]));
1817
1927
  const headerOf = (id) => specs.get(id)?.data.diagram?.container?.header;
1818
1928
  const items = vertices(data, theme, headerOf, warn);
1819
1929
  const ids = new Set(items.map((v) => v.id));
@@ -2290,11 +2400,12 @@ var DIRECTIONS2 = {
2290
2400
  };
2291
2401
  var SHAPE_OUTLINES = {
2292
2402
  rect: "rect",
2293
- rounded: "stadium",
2403
+ rounded: "roundRect",
2294
2404
  stadium: "stadium",
2295
2405
  circle: "ellipse",
2296
- "double-circle": "ellipse",
2406
+ "double-circle": "doubleEllipse",
2297
2407
  diamond: "diamond",
2408
+ cylinder: "cylinder",
2298
2409
  hexagon: "hexagon",
2299
2410
  "lean-right": "parallelogram",
2300
2411
  "lean-left": "parallelogram",
@@ -2306,15 +2417,25 @@ var META_OUTLINES = {
2306
2417
  rectangle: "rect",
2307
2418
  proc: "rect",
2308
2419
  process: "rect",
2309
- rounded: "stadium",
2310
- event: "stadium",
2420
+ rounded: "roundRect",
2421
+ event: "roundRect",
2311
2422
  stadium: "stadium",
2312
2423
  pill: "stadium",
2313
2424
  terminal: "stadium",
2314
2425
  circle: "ellipse",
2315
2426
  circ: "ellipse",
2316
- "dbl-circ": "ellipse",
2317
- "double-circle": "ellipse",
2427
+ "dbl-circ": "doubleEllipse",
2428
+ "double-circle": "doubleEllipse",
2429
+ cyl: "cylinder",
2430
+ cylinder: "cylinder",
2431
+ db: "cylinder",
2432
+ database: "cylinder",
2433
+ doc: "document",
2434
+ document: "document",
2435
+ cloud: "cloud",
2436
+ tri: "triangle",
2437
+ triangle: "triangle",
2438
+ extract: "triangle",
2318
2439
  diam: "diamond",
2319
2440
  diamond: "diamond",
2320
2441
  decision: "diamond",
@@ -2526,7 +2647,19 @@ var BRACKETS = {
2526
2647
  ellipse: ["((", "))"],
2527
2648
  hexagon: ["{{", "}}"],
2528
2649
  parallelogram: ["[/", "/]"],
2529
- trapezoid: ["[/", "\\]"]
2650
+ trapezoid: ["[/", "\\]"],
2651
+ cylinder: ["[(", ")]"],
2652
+ doubleEllipse: ["(((", ")))"],
2653
+ roundRect: ["(", ")"]
2654
+ };
2655
+ var NEAREST = {
2656
+ event: "ellipse",
2657
+ intermediateEvent: "doubleEllipse",
2658
+ exclusiveGateway: "diamond",
2659
+ parallelGateway: "diamond",
2660
+ inclusiveGateway: "diamond",
2661
+ eventGateway: "diamond",
2662
+ subprocess: "roundRect"
2530
2663
  };
2531
2664
  var valid = (id) => /^[A-Za-z_]\w*$/.test(id) && !RESERVED.has(id.toLowerCase());
2532
2665
  function mermaidIds(ids) {
@@ -2574,7 +2707,15 @@ var MermaidWriter = class {
2574
2707
  }
2575
2708
  node(node, indent) {
2576
2709
  const outline = node.outline ?? "rect";
2577
- const [open, close] = BRACKETS[typeof outline === "string" ? outline : "rect"];
2710
+ const nearest = typeof outline === "string" ? NEAREST[outline] : void 0;
2711
+ if (nearest !== void 0) {
2712
+ this.out.warnings.add("Mermaid has no BPMN figures; events were written as circles, gateways as diamonds without their markers, and subprocesses as rounded rectangles.");
2713
+ }
2714
+ const brackets = typeof outline === "string" ? BRACKETS[nearest ?? outline] : void 0;
2715
+ if (brackets === void 0 && typeof outline === "string") {
2716
+ this.out.warnings.add("Mermaid has no bracket shape for some outlines; they were written as rectangles.");
2717
+ }
2718
+ const [open, close] = brackets ?? BRACKETS.rect;
2578
2719
  this.lines.push(`${indent}${this.id(node.id)}${open}${mermaidText(nodeLines(node, this.out.warnings, "Mermaid"))}${close}`);
2579
2720
  }
2580
2721
  cluster(c, indent) {
@@ -2711,6 +2852,10 @@ var textOf2 = (scene, id) => {
2711
2852
  const text = dataOf(scene.get(id)).text;
2712
2853
  return typeof text === "string" ? text : void 0;
2713
2854
  };
2855
+ function withDividers(text, dividers) {
2856
+ const all = [...text, ...dividers.map((d) => ({ index: d.index, row: d.inset === void 0 ? { kind: "divider" } : { kind: "divider", inset: d.inset } }))];
2857
+ return all.sort((a, b) => a.index - b.index).map((e) => e.row);
2858
+ }
2714
2859
  function readShape(scene, node, page, theme) {
2715
2860
  const trait = traitOf(node);
2716
2861
  const data = dataOf(node);
@@ -2726,10 +2871,14 @@ function readShape(scene, node, page, theme) {
2726
2871
  dash: data.stroke?.dash
2727
2872
  }, { ...themed, strokeWidth: themed.strokeWidth ?? NODE_STROKE_WIDTH }, trait.ownStyle);
2728
2873
  const body = trait.body;
2874
+ const dividers = body?.dividers ?? [];
2729
2875
  return {
2730
2876
  id: node.id,
2731
2877
  outline: trait.outline,
2732
- ...ownSize ? { rows: rows.map((r) => ({ kind: "label", text: dataOf(r).text, style: { fontSize: dataOf(r).style?.fontSize } })) } : { lines: rows.map((r) => dataOf(r).text) },
2878
+ ...ownSize || dividers.length > 0 ? { rows: withDividers(rows.map((r) => ({
2879
+ index: dataOf(r).bodyRow,
2880
+ row: { kind: "label", text: dataOf(r).text, ...ownSize ? { style: { fontSize: dataOf(r).style?.fontSize } } : {} }
2881
+ })), dividers) } : { lines: rows.map((r) => dataOf(r).text) },
2733
2882
  at: moved2(pose, page),
2734
2883
  width: pose.width,
2735
2884
  height: pose.height,
@@ -2867,7 +3016,7 @@ function contentPage(scene) {
2867
3016
  return { id: "page-1", x, y, width, height, index: 0 };
2868
3017
  }
2869
3018
  function documentFromScene(scene, opts = {}) {
2870
- const s = scene;
3019
+ const s = inWorld(scene);
2871
3020
  const themeValue = s.doc.get(DIAGRAM_THEME_KEY);
2872
3021
  const theme = diagramThemeFrom(themeValue, opts.theme);
2873
3022
  const placed = placedPagesOf(scene);
@@ -2937,6 +3086,21 @@ var isContainerOrPool = (node) => {
2937
3086
  const trait = node.data.diagram;
2938
3087
  return trait?.container?.role === "container" || trait?.container?.role === "pool";
2939
3088
  };
3089
+ function inWorld(scene) {
3090
+ const raw = scene;
3091
+ const poses = scenePoseAdapter(scene);
3092
+ const placed = (node) => ({ ...node, pose: composeWorldPose(poses, node.id, scene.composition.compose) });
3093
+ return {
3094
+ roots: raw.roots,
3095
+ doc: raw.doc,
3096
+ childrenOf: (id) => raw.childrenOf(id),
3097
+ get: (id) => {
3098
+ const node = raw.get(id);
3099
+ return node === void 0 ? void 0 : placed(node);
3100
+ },
3101
+ renderOrderNodes: () => raw.renderOrderNodes().map(placed)
3102
+ };
3103
+ }
2940
3104
  function documentSpecs(document, opts = {}) {
2941
3105
  const theme = opts.theme ?? diagramThemeFrom(document.theme);
2942
3106
  const measure = opts.measure ? { measure: opts.measure } : {};