@zenuml/core 4.10.1 → 4.10.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.
@@ -1,9 +1,154 @@
1
1
  #!/usr/bin/env bun
2
2
  import antlr4 from 'antlr4';
3
+ import { readFileSync, statSync, writeFileSync, mkdirSync, watch } from 'node:fs';
4
+ import { resolve, extname, basename, join, dirname } from 'node:path';
3
5
  import { marked } from 'marked';
4
6
  import colorString from 'color-string';
5
- import { readFileSync, statSync, mkdirSync, writeFileSync, watch } from 'node:fs';
6
- import { resolve, join, dirname, basename, extname } from 'node:path';
7
+
8
+ var TextType = /* @__PURE__ */ ((TextType2) => {
9
+ TextType2[TextType2["MessageContent"] = 0] = "MessageContent";
10
+ TextType2[TextType2["ParticipantName"] = 1] = "ParticipantName";
11
+ return TextType2;
12
+ })(TextType || {});
13
+
14
+ let dic = {};
15
+ let persistDic = {};
16
+ const getCache = (key) => {
17
+ if (key != null) {
18
+ const cacheValue = dic[key] ?? persistDic[key];
19
+ return cacheValue !== void 0 ? cacheValue : null;
20
+ }
21
+ return null;
22
+ };
23
+ const setCache = (key, value, persist = false) => {
24
+ dic[key] = value;
25
+ if (persist) {
26
+ persistDic[key] = value;
27
+ }
28
+ };
29
+ const clearPersistentCache = () => {
30
+ persistDic = {};
31
+ dic = {};
32
+ };
33
+
34
+ const IBM_PLEX_SANS_FAMILY = "IBM Plex Sans";
35
+ const DIAGRAM_FONT_STACK = `"${IBM_PLEX_SANS_FAMILY}", Helvetica, Verdana, serif`;
36
+ const IBM_PLEX_SANS_400_WOFF2_BASE64 = "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";
37
+ const IBM_PLEX_SANS_400_DATA_URI = `data:font/woff2;base64,${IBM_PLEX_SANS_400_WOFF2_BASE64}`;
38
+ const IBM_PLEX_SANS_FONT_FACE_CSS = `@font-face { font-family: "${IBM_PLEX_SANS_FAMILY}"; font-weight: 400; font-style: normal; src: url(${IBM_PLEX_SANS_400_DATA_URI}) format("woff2"); }`;
39
+
40
+ const FONT_FAMILY = DIAGRAM_FONT_STACK;
41
+ const FONT_SIZE_PARTICIPANT = "14px";
42
+ const FONT_SIZE_MESSAGE = "15px";
43
+ const FONT_SIZE_FRAGMENT = "14px";
44
+ function getFontSize(type) {
45
+ return type === TextType.MessageContent ? FONT_SIZE_MESSAGE : FONT_SIZE_PARTICIPANT;
46
+ }
47
+ function getFontSpec(type) {
48
+ return `${getFontSize(type)} ${FONT_FAMILY}`;
49
+ }
50
+ let canvasCtx = null;
51
+ function setCanvasContext(ctx) {
52
+ if (ctx === canvasCtx) return;
53
+ canvasCtx = ctx;
54
+ clearPersistentCache();
55
+ }
56
+ function getCanvasContext() {
57
+ if (canvasCtx) return canvasCtx;
58
+ try {
59
+ if (typeof OffscreenCanvas !== "undefined") {
60
+ canvasCtx = new OffscreenCanvas(1, 1).getContext("2d");
61
+ } else if (typeof document !== "undefined") {
62
+ canvasCtx = document.createElement("canvas").getContext("2d");
63
+ }
64
+ } catch {
65
+ }
66
+ return canvasCtx;
67
+ }
68
+ function WidthProviderOnCanvas(text, type) {
69
+ const measured = text.trim();
70
+ const cacheKey = `WidthProviderOnCanvas_${getFontSpec(type)}_${measured}_${type}`;
71
+ const cacheValue = getCache(cacheKey);
72
+ if (cacheValue != null) {
73
+ return cacheValue;
74
+ }
75
+ const ctx = getCanvasContext();
76
+ if (!ctx) {
77
+ const width2 = Math.ceil(
78
+ measured.length * Number.parseFloat(getFontSize(type)) * 0.6
79
+ );
80
+ setCache(cacheKey, width2);
81
+ return width2;
82
+ }
83
+ ctx.font = getFontSpec(type);
84
+ ctx.fontVariantCaps = "normal";
85
+ const width = Math.round(ctx.measureText(measured).width);
86
+ setCache(cacheKey, width, true);
87
+ return width;
88
+ }
89
+ const EMOJI_PATTERN = (
90
+ // eslint-disable-next-line no-misleading-character-class
91
+ /[\u{1F300}-\u{1FAFF}\u{2600}-\u{27BF}\u{FE00}-\u{FE0F}\u{200D}]/u
92
+ );
93
+ function measureWithSvg(text, fontSize, caps = "normal") {
94
+ if (typeof document === "undefined") return null;
95
+ const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
96
+ svg.setAttribute("style", "position:absolute;left:-9999px;top:-9999px");
97
+ const textEl = document.createElementNS("http://www.w3.org/2000/svg", "text");
98
+ textEl.setAttribute("font-family", FONT_FAMILY);
99
+ textEl.setAttribute("font-size", fontSize);
100
+ textEl.style.fontVariantCaps = caps;
101
+ if (typeof textEl.getBBox !== "function") return null;
102
+ textEl.textContent = text;
103
+ svg.appendChild(textEl);
104
+ document.body.appendChild(svg);
105
+ const width = textEl.getBBox().width;
106
+ document.body.removeChild(svg);
107
+ return Number.isFinite(width) && width > 0 ? width : null;
108
+ }
109
+ function measureTextWithFont(text, fontSize, caps = "normal") {
110
+ const measured = text.trim();
111
+ if (!measured) return 0;
112
+ const hasEmoji = EMOJI_PATTERN.test(measured);
113
+ const font = `${fontSize} ${FONT_FAMILY}`;
114
+ const cacheKey = (hasEmoji ? `measureTextWithFont_svg_${font}_${measured}` : `measureTextWithFont_${font}_${measured}`) + `_${caps}`;
115
+ const cacheValue = getCache(cacheKey);
116
+ if (cacheValue != null) {
117
+ return cacheValue;
118
+ }
119
+ if (hasEmoji || caps !== "normal") {
120
+ const svgWidth = measureWithSvg(measured, fontSize, caps);
121
+ if (svgWidth != null) {
122
+ setCache(cacheKey, svgWidth, true);
123
+ return svgWidth;
124
+ }
125
+ }
126
+ const ctx = getCanvasContext();
127
+ if (!ctx) {
128
+ const px = Number.parseFloat(fontSize) || 14;
129
+ const width2 = Math.ceil(measured.length * px * 0.6);
130
+ setCache(cacheKey, width2);
131
+ return width2;
132
+ }
133
+ ctx.font = font;
134
+ ctx.fontVariantCaps = "normal";
135
+ const normalWidth = ctx.measureText(measured).width;
136
+ let width = normalWidth;
137
+ if (caps !== "normal") {
138
+ const normalProbe = ctx.measureText("iiii").width;
139
+ ctx.fontVariantCaps = caps;
140
+ width = Math.abs(ctx.measureText("iiii").width - normalProbe) > 0.01 ? ctx.measureText(measured).width : Math.max(normalWidth, ctx.measureText(measured.toUpperCase()).width);
141
+ ctx.fontVariantCaps = "normal";
142
+ }
143
+ setCache(cacheKey, width, true);
144
+ return width;
145
+ }
146
+ function measureSvgFragmentLabelWidth(text) {
147
+ return measureTextWithFont(text, FONT_SIZE_FRAGMENT);
148
+ }
149
+ function measureSvgParticipantLabelWidth(text) {
150
+ return measureTextWithFont(text, FONT_SIZE_PARTICIPANT);
151
+ }
7
152
 
8
153
  // Generated from java-escape by ANTLR 4.11.1
9
154
  // jshint ignore: start
@@ -8943,27 +9088,17 @@ let Participants$1 = class Participants {
8943
9088
  }
8944
9089
  };
8945
9090
 
8946
- let participants = undefined;
8947
- // Depth counter: parameters and conditions nest, and an inner exit must not
8948
- // re-enable collection while the outer one is still open.
9091
+ let participants = void 0;
8949
9092
  let isBlind = 0;
8950
- let groupId = undefined;
9093
+ let groupId = void 0;
8951
9094
  const ToCollector = new sequenceParserListener();
8952
-
8953
- // Rules:
8954
- // 1. Later declaration win
8955
- // 2. Participant declaration overwrite cannot be overwritten by To or Starter
8956
- const onParticipant = function (ctx) {
8957
- // if(!(ctx?.name())) return;
9095
+ const onParticipant = function(ctx) {
8958
9096
  if (isBlind) return;
8959
9097
  const type = ctx?.participantType()?.getFormattedText().replace("@", "");
8960
- const participant =
8961
- ctx?.name()?.getFormattedText() || "Missing `Participant`";
9098
+ const participant = ctx?.name()?.getFormattedText() || "Missing `Participant`";
8962
9099
  const stereotype = ctx.stereotype()?.name()?.getFormattedText();
8963
9100
  const emoji = ctx.emoji?.()?.name?.()?.getFormattedText();
8964
- const width =
8965
- (ctx.width && ctx.width() && Number.parseInt(ctx.width().getText())) ||
8966
- undefined;
9101
+ const width = ctx.width && ctx.width() && Number.parseInt(ctx.width().getText()) || void 0;
8967
9102
  const labelCtx = ctx.label && ctx.label();
8968
9103
  const label = labelCtx?.name()?.getFormattedText();
8969
9104
  const explicit = true;
@@ -8971,8 +9106,6 @@ const onParticipant = function (ctx) {
8971
9106
  const comment = ctx.getComment();
8972
9107
  const nameCtx = ctx.name();
8973
9108
  let start, end;
8974
-
8975
- // When label is present, it means we edit label in diagram and update its code regardless of the occurrence of the participant name
8976
9109
  if (labelCtx) {
8977
9110
  const labelNameCtx = labelCtx.name();
8978
9111
  if (labelNameCtx) {
@@ -8983,7 +9116,6 @@ const onParticipant = function (ctx) {
8983
9116
  start = nameCtx.start.start;
8984
9117
  end = nameCtx.stop.stop + 1;
8985
9118
  }
8986
-
8987
9119
  participants.Add(participant, {
8988
9120
  isStarter: false,
8989
9121
  type,
@@ -8995,131 +9127,106 @@ const onParticipant = function (ctx) {
8995
9127
  explicit,
8996
9128
  color,
8997
9129
  comment,
8998
- position: [start, end],
9130
+ // `start`/`end` stay undefined when neither a label nor a name node exists.
9131
+ position: [start, end]
8999
9132
  });
9000
9133
  };
9001
9134
  ToCollector.enterParticipant = onParticipant;
9002
-
9003
- const onTo = function (ctx) {
9135
+ const onTo = function(ctx) {
9004
9136
  if (isBlind) return;
9005
- let participant = ctx.name?.()?.getFormattedText() || ctx.getFormattedText();
9137
+ const participant = ctx.name?.()?.getFormattedText() || ctx.getFormattedText();
9006
9138
  const emoji = ctx.emoji?.()?.name?.()?.getFormattedText();
9007
9139
  const participantInstance = participants.Get(participant);
9008
-
9009
- // Skip adding participant position if label is present
9010
9140
  if (participantInstance?.label) {
9011
9141
  participants.Add(participant, { isStarter: false, emoji });
9012
9142
  } else if (participantInstance?.assignee) {
9013
- // If the participant has an assignee, calculate the position of the ctor and store it only.
9014
- // Let's say the participant name is `"${assignee}:${type}"`, we need to get the position of ${type}
9015
- // e.g. ret = new A() "ret:A".method()
9016
9143
  const start = ctx.start.start + participantInstance.assignee.length + 2;
9017
9144
  const position = [start, ctx.stop.stop];
9018
9145
  const assigneePosition = [
9019
9146
  ctx.start.start + 1,
9020
- ctx.start.start + participantInstance.assignee.length + 1,
9147
+ ctx.start.start + participantInstance.assignee.length + 1
9021
9148
  ];
9022
9149
  participants.Add(participant, {
9023
9150
  isStarter: false,
9024
9151
  emoji,
9025
- position: position,
9026
- assigneePosition: assigneePosition,
9152
+ position,
9153
+ assigneePosition
9027
9154
  });
9028
9155
  } else {
9029
9156
  participants.Add(participant, {
9030
9157
  isStarter: false,
9031
9158
  emoji,
9032
- position: [ctx.start.start, ctx.stop.stop + 1],
9159
+ position: [ctx.start.start, ctx.stop.stop + 1]
9033
9160
  });
9034
9161
  }
9035
9162
  };
9036
-
9037
9163
  ToCollector.enterFrom = onTo;
9038
9164
  ToCollector.enterTo = onTo;
9039
-
9040
- ToCollector.enterStarter = function (ctx) {
9041
- let participant = ctx.getFormattedText();
9165
+ ToCollector.enterStarter = function(ctx) {
9166
+ const participant = ctx.getFormattedText();
9042
9167
  participants.Add(participant, {
9043
9168
  isStarter: true,
9044
- position: [ctx.start.start, ctx.stop.stop + 1],
9169
+ position: [ctx.start.start, ctx.stop.stop + 1]
9045
9170
  });
9046
9171
  };
9047
-
9048
- ToCollector.enterCreation = function (ctx) {
9172
+ ToCollector.enterCreation = function(ctx) {
9049
9173
  if (isBlind) return;
9050
9174
  const participant = ctx.Owner();
9051
9175
  const ctor = ctx?.creationBody()?.construct();
9052
9176
  const participantInstance = participants.Get(participant);
9053
- // Skip adding participant constructor position if label is present
9054
9177
  if (ctor && !participantInstance?.label) {
9055
9178
  const assignee = ctx.Assignee();
9056
9179
  const assigneePosition = ctx.AssigneePosition();
9057
9180
  participants.Add(participant, {
9058
9181
  isStarter: false,
9059
9182
  position: [ctor.start.start, ctor.stop.stop + 1],
9060
- assignee: assignee,
9061
- assigneePosition: assigneePosition,
9183
+ assignee,
9184
+ assigneePosition
9062
9185
  });
9063
9186
  } else {
9064
9187
  participants.Add(participant, {
9065
- isStarter: false,
9188
+ isStarter: false
9066
9189
  });
9067
9190
  }
9068
9191
  };
9069
-
9070
- ToCollector.enterRef = function (ctx) {
9192
+ ToCollector.enterRef = function(ctx) {
9071
9193
  ctx.Participants().forEach((participant) => {
9072
9194
  participants.Add(participant.getText(), {
9073
9195
  isStarter: false,
9074
- position: [participant.start.start, participant.stop.stop + 1],
9196
+ position: [participant.start.start, participant.stop.stop + 1]
9075
9197
  });
9076
9198
  });
9077
9199
  };
9078
-
9079
- ToCollector.enterParameters = function () {
9200
+ ToCollector.enterParameters = function() {
9080
9201
  isBlind++;
9081
9202
  };
9082
-
9083
- ToCollector.exitParameters = function () {
9203
+ ToCollector.exitParameters = function() {
9084
9204
  isBlind--;
9085
9205
  };
9086
-
9087
- ToCollector.enterCondition = function () {
9206
+ ToCollector.enterCondition = function() {
9088
9207
  isBlind++;
9089
9208
  };
9090
-
9091
- ToCollector.exitCondition = function () {
9209
+ ToCollector.exitCondition = function() {
9092
9210
  isBlind--;
9093
9211
  };
9094
-
9095
- ToCollector.enterGroup = function (ctx) {
9096
- // group { A } => groupId = undefined
9097
- // group group1 { A } => groupId = "group1"
9212
+ ToCollector.enterGroup = function(ctx) {
9098
9213
  groupId = ctx.name()?.getFormattedText();
9099
9214
  };
9100
-
9101
- ToCollector.exitGroup = function () {
9102
- groupId = undefined;
9215
+ ToCollector.exitGroup = function() {
9216
+ groupId = void 0;
9103
9217
  };
9104
-
9105
- ToCollector.enterRet = function (ctx) {
9218
+ ToCollector.enterRet = function(ctx) {
9106
9219
  if (ctx.asyncMessage()) {
9107
- // it will visit the asyncMessage later
9108
9220
  return;
9109
9221
  }
9110
9222
  const returnFrom = ctx.From();
9111
- returnFrom && participants.Add(returnFrom);
9223
+ if (returnFrom) participants.Add(returnFrom);
9112
9224
  const returnTo = ctx.ReturnTo();
9113
- returnTo && participants.Add(returnTo);
9225
+ if (returnTo) participants.Add(returnTo);
9114
9226
  };
9115
-
9116
9227
  const walker$1 = antlr4.tree.ParseTreeWalker.DEFAULT;
9117
-
9118
- // The walk is a pure function of the (immutable) parse tree and consumers only
9119
- // read the returned Participants, so results are cached per context node.
9120
- const participantsCache = new WeakMap();
9121
-
9122
- ToCollector.getParticipants = function (context) {
9228
+ const participantsCache = /* @__PURE__ */ new WeakMap();
9229
+ ToCollector.getParticipants = function(context) {
9123
9230
  if (!context) return new Participants$1();
9124
9231
  const cached = participantsCache.get(context);
9125
9232
  if (cached) return cached;
@@ -9132,7 +9239,7 @@ ToCollector.getParticipants = function (context) {
9132
9239
 
9133
9240
  const seqParser$9 = sequenceParser;
9134
9241
  const TitleContext = seqParser$9.TitleContext;
9135
- TitleContext.prototype.content = function () {
9242
+ TitleContext.prototype.content = function() {
9136
9243
  if (this.children.length < 2) {
9137
9244
  return "";
9138
9245
  } else {
@@ -9141,63 +9248,47 @@ TitleContext.prototype.content = function () {
9141
9248
  };
9142
9249
 
9143
9250
  const seqParser$8 = sequenceParser;
9144
-
9145
9251
  const CreationContext$7 = seqParser$8.CreationContext;
9146
9252
  CreationContext$7.prototype.Body = CreationContext$7.prototype.creationBody;
9147
- CreationContext$7.prototype.isCurrent = function (cursor) {
9253
+ CreationContext$7.prototype.isCurrent = function(cursor) {
9148
9254
  return isCurrent.bind(this)(cursor);
9149
9255
  };
9150
-
9151
9256
  const MessageContext$7 = seqParser$8.MessageContext;
9152
9257
  MessageContext$7.prototype.Body = MessageContext$7.prototype.messageBody;
9153
- MessageContext$7.prototype.isCurrent = function (cursor) {
9258
+ MessageContext$7.prototype.isCurrent = function(cursor) {
9154
9259
  return isCurrent.bind(this)(cursor);
9155
9260
  };
9156
-
9157
9261
  function isCurrent(cursor) {
9158
9262
  try {
9159
- if (cursor === null || cursor === undefined) return false;
9263
+ if (cursor === null || cursor === void 0) return false;
9160
9264
  const start = this.start.start;
9161
9265
  const stop = this.Body().stop.stop + 1;
9162
-
9163
9266
  return cursor >= start && cursor <= stop;
9164
- } catch (e) {
9267
+ } catch {
9165
9268
  return false;
9166
9269
  }
9167
9270
  }
9168
9271
 
9169
- /**
9170
- * Owner is the receiver of the message.
9171
- * For example, in `S -> A.m1 {B.m2 {C.m3}} D->E:m4`,
9172
- * | | | |
9173
- * Owner of m1 m2 m3 m4
9174
- */
9175
-
9176
-
9177
9272
  const seqParser$7 = sequenceParser;
9178
9273
  const CreationContext$6 = seqParser$7.CreationContext;
9179
9274
  const MessageContext$6 = seqParser$7.MessageContext;
9180
9275
  const AsyncMessageContext$2 = seqParser$7.AsyncMessageContext;
9181
9276
  const ReturnAsyncMessageContext$2 = seqParser$7.ReturnAsyncMessageContext;
9182
9277
  const RetMessageContext = seqParser$7.RetContext;
9183
-
9184
- CreationContext$6.prototype.Assignee = function () {
9278
+ CreationContext$6.prototype.Assignee = function() {
9185
9279
  return this.creationBody()?.assignment()?.assignee()?.getFormattedText();
9186
9280
  };
9187
-
9188
- CreationContext$6.prototype.AssigneePosition = function () {
9281
+ CreationContext$6.prototype.AssigneePosition = function() {
9189
9282
  const assignee = this.creationBody()?.assignment()?.assignee();
9190
9283
  if (!assignee) {
9191
- return undefined;
9284
+ return void 0;
9192
9285
  }
9193
9286
  return [assignee.start.start, assignee.stop.stop + 1];
9194
9287
  };
9195
-
9196
- CreationContext$6.prototype.Constructor = function () {
9288
+ CreationContext$6.prototype.Constructor = function() {
9197
9289
  return this.creationBody()?.construct()?.getFormattedText();
9198
9290
  };
9199
-
9200
- CreationContext$6.prototype.Owner = function () {
9291
+ CreationContext$6.prototype.Owner = function() {
9201
9292
  if (!this.Constructor()) {
9202
9293
  return "Missing Constructor";
9203
9294
  }
@@ -9205,12 +9296,10 @@ CreationContext$6.prototype.Owner = function () {
9205
9296
  const type = this.Constructor();
9206
9297
  return assignee ? `${assignee}:${type}` : type;
9207
9298
  };
9208
-
9209
- MessageContext$6.prototype.To = function () {
9299
+ MessageContext$6.prototype.To = function() {
9210
9300
  const toCtx = this.messageBody()?.fromTo()?.to();
9211
9301
  return toCtx?.name?.()?.getFormattedText() || toCtx?.getFormattedText();
9212
9302
  };
9213
-
9214
9303
  function getOwnerFromAncestor(ctx) {
9215
9304
  while (ctx) {
9216
9305
  if (ctx instanceof CreationContext$6 || ctx instanceof MessageContext$6) {
@@ -9218,81 +9307,32 @@ function getOwnerFromAncestor(ctx) {
9218
9307
  }
9219
9308
  ctx = ctx.parentCtx;
9220
9309
  }
9221
- return undefined;
9310
+ return void 0;
9222
9311
  }
9223
-
9224
- // MessageContext, AsyncMessageContext, ReturnAsyncMessageContext and
9225
- // RetContext all resolve Owner the same way: prefer their own To(), else
9226
- // look up the nearest CreationContext/MessageContext ancestor. Assigning
9227
- // the same function to each prototype keeps the body single-sourced while
9228
- // each context class still gets its own Owner property.
9229
9312
  function ownerFromToOrAncestor() {
9230
9313
  return this.To() || getOwnerFromAncestor(this.parentCtx);
9231
9314
  }
9232
-
9233
9315
  [
9234
9316
  MessageContext$6,
9235
9317
  AsyncMessageContext$2,
9236
9318
  ReturnAsyncMessageContext$2,
9237
- RetMessageContext,
9319
+ RetMessageContext
9238
9320
  ].forEach((ContextClass) => {
9239
9321
  ContextClass.prototype.Owner = ownerFromToOrAncestor;
9240
9322
  });
9241
-
9242
- // AsyncMessageContext and ReturnAsyncMessageContext resolve To() identically
9243
- // (unlike MessageContext, which reaches its `to` node through
9244
- // messageBody()?.fromTo(), and RetContext, which delegates to ReturnTo()).
9245
9323
  function toFromDirectTo() {
9246
9324
  const toCtx = this.to();
9247
9325
  return toCtx?.name?.()?.getFormattedText() || toCtx?.getFormattedText();
9248
9326
  }
9249
-
9250
9327
  AsyncMessageContext$2.prototype.To = toFromDirectTo;
9251
9328
  ReturnAsyncMessageContext$2.prototype.To = toFromDirectTo;
9252
-
9253
- RetMessageContext.prototype.To = function () {
9329
+ RetMessageContext.prototype.To = function() {
9254
9330
  return this.ReturnTo();
9255
9331
  };
9256
9332
 
9257
9333
  const ProgContext$2 = sequenceParser.ProgContext;
9258
-
9259
- /**
9260
- * When does Starter need to be treated differently?
9261
- *
9262
- * 0. "". A default starter CAN be rendered as otherwise the diagram is empty.
9263
- *
9264
- * 1. A.method
9265
- * There is no starter indicated in the code at all. _STARTER_ is used.
9266
- *
9267
- * 2. A->B.method
9268
- * There seems no need to even consider a starter and all messages have a provided sender.
9269
- *
9270
- * 3. if(x) { A.method }.
9271
- * Similar to #1
9272
- *
9273
- * 4. if(x) { A->B.method }.
9274
- * Similar to #2
9275
- *
9276
- * 5. @Starter(A).
9277
- * Starter is clearly defined. It must be used anywhere a sender is not provided
9278
- * and not inferrable.
9279
- *
9280
- * 6. A B.
9281
- * Only the participants are defined. There is no need to consider a starter.
9282
- *
9283
- * From the above analysis, it is clear that whether we should consider a starter is base on
9284
- * messages only. Thus, the following rules are established:
9285
- *
9286
- * For the ProgContext, if there is `@starter(x)` then Starter returns x, otherwise it returns undefined.
9287
- * It is left to the LifelineLayer to determine whether a default starter is rendered based on the messages.
9288
- *
9289
- * The ToCollector should not be concerned with the default starter.
9290
- *
9291
- * _STARTER_ is of the renderer's concern. It is not a concern of the parser.
9292
- */
9293
-
9294
- ProgContext$2.prototype.Starter = function () {
9295
- return this.head()?.starterExp()?.starter()?.getFormattedText();
9334
+ ProgContext$2.prototype.Starter = function() {
9335
+ return this.head()?.starterExp()?.starter()?.getFormattedText?.();
9296
9336
  };
9297
9337
 
9298
9338
  const seqParser$6 = sequenceParser;
@@ -9300,23 +9340,15 @@ const RetContext$2 = seqParser$6.RetContext;
9300
9340
  const ProgContext$1 = seqParser$6.ProgContext;
9301
9341
  const MessageContext$5 = seqParser$6.MessageContext;
9302
9342
  const CreationContext$5 = seqParser$6.CreationContext;
9303
-
9304
- RetContext$2.prototype.Signature = function () {
9305
- return (
9306
- this.asyncMessage()?.content()?.getFormattedText() ||
9307
- this.returnAsyncMessage()?.content()?.getFormattedText() ||
9308
- this.expr()?.getFormattedText()
9309
- );
9343
+ RetContext$2.prototype.Signature = function() {
9344
+ return this.asyncMessage()?.content()?.getFormattedText() || this.returnAsyncMessage()?.content()?.getFormattedText() || this.expr()?.getFormattedText();
9310
9345
  };
9311
-
9312
- RetContext$2.prototype.ReturnTo = function () {
9313
- // Check asyncMessage 'to' first
9346
+ RetContext$2.prototype.ReturnTo = function() {
9314
9347
  const asyncToCtx = this.asyncMessage()?.to() || this.returnAsyncMessage()?.to();
9315
9348
  const asyncTo = asyncToCtx?.name?.()?.getFormattedText() || asyncToCtx?.getFormattedText();
9316
9349
  if (asyncTo) {
9317
9350
  return asyncTo;
9318
9351
  }
9319
-
9320
9352
  const stat = this.parentCtx;
9321
9353
  const block = stat.parentCtx;
9322
9354
  const blockParent = block.parentCtx;
@@ -9324,22 +9356,15 @@ RetContext$2.prototype.ReturnTo = function () {
9324
9356
  return blockParent.Starter();
9325
9357
  } else {
9326
9358
  let ctx = blockParent;
9327
- while (
9328
- ctx &&
9329
- !(ctx instanceof MessageContext$5) &&
9330
- !(ctx instanceof CreationContext$5)
9331
- ) {
9359
+ while (ctx && !(ctx instanceof MessageContext$5) && !(ctx instanceof CreationContext$5)) {
9332
9360
  if (ctx instanceof ProgContext$1) {
9333
9361
  return ctx.Starter();
9334
9362
  }
9335
9363
  ctx = ctx.parentCtx;
9336
9364
  }
9337
9365
  if (ctx instanceof MessageContext$5) {
9338
- return (
9339
- ctx.messageBody()?.fromTo()?.from()?.name?.()?.getFormattedText() ||
9340
- ctx.messageBody()?.fromTo()?.from()?.getFormattedText() ||
9341
- ctx.ClosestAncestorStat().Origin()
9342
- );
9366
+ const messageCtx = ctx;
9367
+ return messageCtx.messageBody()?.fromTo()?.from()?.name?.()?.getFormattedText() || messageCtx.messageBody()?.fromTo()?.from()?.getFormattedText() || messageCtx.ClosestAncestorStat().Origin();
9343
9368
  }
9344
9369
  return ctx.ClosestAncestorStat().Origin();
9345
9370
  }
@@ -9359,20 +9384,15 @@ RefContext.prototype.Participants = function() {
9359
9384
  return this.name().slice(1) ?? [];
9360
9385
  };
9361
9386
 
9362
- const ParserRuleContext$1 = antlr4.ParserRuleContext;
9387
+ const ParserRuleContext$2 = antlr4.ParserRuleContext;
9363
9388
  const StatContext$2 = sequenceParser.StatContext;
9364
9389
  const ProgContext = sequenceParser.ProgContext;
9365
9390
  const MessageContext$4 = sequenceParser.MessageContext;
9366
9391
  const CreationContext$4 = sequenceParser.CreationContext;
9367
-
9368
- ParserRuleContext$1.prototype.Origin = function () {
9392
+ ParserRuleContext$2.prototype.Origin = function() {
9369
9393
  return this.ClosestAncestorStat()?.Origin();
9370
9394
  };
9371
- // Origin is essentially the 'from' of a message.
9372
- // For example, in `S -> A.m1 {B.m2 {C.m3}}`,
9373
- // | | |
9374
- // Origin of m1 m2 m3
9375
- StatContext$2.prototype.Origin = function () {
9395
+ StatContext$2.prototype.Origin = function() {
9376
9396
  let ctx = this.parentCtx;
9377
9397
  while (ctx) {
9378
9398
  if (ctx instanceof ProgContext) {
@@ -9386,10 +9406,9 @@ StatContext$2.prototype.Origin = function () {
9386
9406
  }
9387
9407
  ctx = ctx.parentCtx;
9388
9408
  }
9389
- return undefined;
9409
+ return void 0;
9390
9410
  };
9391
-
9392
- ProgContext.prototype.Origin = function () {
9411
+ ProgContext.prototype.Origin = function() {
9393
9412
  return this.Starter();
9394
9413
  };
9395
9414
 
@@ -9559,8 +9578,8 @@ RetContext.prototype.From = function() {
9559
9578
 
9560
9579
  const seqParser = sequenceParser;
9561
9580
  const StatContext = seqParser.StatContext;
9562
- const ParserRuleContext = antlr4.ParserRuleContext;
9563
- ParserRuleContext.prototype.ClosestAncestorStat = function() {
9581
+ const ParserRuleContext$1 = antlr4.ParserRuleContext;
9582
+ ParserRuleContext$1.prototype.ClosestAncestorStat = function() {
9564
9583
  if (this instanceof StatContext) {
9565
9584
  return this;
9566
9585
  }
@@ -9593,30 +9612,24 @@ const formatText = (text) => text.replace(/[\n\r]/g, " ").replace(/\s+/g, " ").r
9593
9612
 
9594
9613
  const errorDetails = [];
9595
9614
  class SeqErrorListener extends antlr4.error.ErrorListener {
9596
- syntaxError(recognizer, offendingSymbol, line, column, msg) {
9615
+ syntaxError(_recognizer, _offendingSymbol, line, column, msg) {
9597
9616
  errorDetails.push({
9598
9617
  line,
9599
9618
  column,
9600
- msg,
9619
+ msg
9601
9620
  });
9602
9621
  }
9603
9622
  }
9604
-
9605
- // Reentrant error listener: collects syntax errors into its OWN instance array
9606
- // instead of the shared module-level `errorDetails`. This is what lets
9607
- // validate()/parse() below run repeatedly or concurrently (e.g. server-side)
9608
- // without the clear-before/clear-after dance the legacy globals require.
9609
9623
  class CollectingErrorListener extends antlr4.error.ErrorListener {
9624
+ errorDetails;
9610
9625
  constructor() {
9611
9626
  super();
9612
- /** @type {{ line: number, column: number, msg: string }[]} */
9613
9627
  this.errorDetails = [];
9614
9628
  }
9615
- syntaxError(recognizer, offendingSymbol, line, column, msg) {
9629
+ syntaxError(_recognizer, _offendingSymbol, line, column, msg) {
9616
9630
  this.errorDetails.push({ line, column, msg });
9617
9631
  }
9618
9632
  }
9619
-
9620
9633
  function createParser(code, { silent = false } = {}) {
9621
9634
  const chars = new antlr4.InputStream(code);
9622
9635
  const lexer = new sequenceLexer(chars);
@@ -9630,23 +9643,13 @@ function createParser(code, { silent = false } = {}) {
9630
9643
  }
9631
9644
  return parser;
9632
9645
  }
9633
-
9634
- // Memoize error-free parse results so the same code is parsed once even when
9635
- // multiple render paths (store, SVG export, CLI) need the tree.
9636
- const rootContextCache = new Map();
9646
+ const rootContextCache = /* @__PURE__ */ new Map();
9637
9647
  const ROOT_CONTEXT_CACHE_MAX = 10;
9638
-
9639
9648
  function rootContext(code) {
9640
9649
  const cached = rootContextCache.get(code);
9641
9650
  if (cached) {
9642
9651
  return cached;
9643
9652
  }
9644
-
9645
- // Two-stage parsing: SLL prediction is an order of magnitude faster than
9646
- // full LL and, when it succeeds, is guaranteed to produce the same parse
9647
- // tree. BailErrorStrategy aborts on the first syntax error so invalid input
9648
- // falls through to the full LL parse below, which keeps error recovery and
9649
- // error reporting behavior unchanged.
9650
9653
  const sllParser = createParser(code, { silent: true });
9651
9654
  sllParser._interp.predictionMode = antlr4.atn.PredictionMode.SLL;
9652
9655
  sllParser._errHandler = new antlr4.error.BailErrorStrategy();
@@ -9658,47 +9661,25 @@ function rootContext(code) {
9658
9661
  }
9659
9662
  return tree;
9660
9663
  } catch {
9661
- // fall through to full LL parse
9662
9664
  }
9663
-
9664
9665
  const parser = createParser(code);
9665
9666
  parser.addErrorListener(new SeqErrorListener());
9666
9667
  return parser.prog();
9667
9668
  }
9668
-
9669
- antlr4.ParserRuleContext.prototype.getFormattedText = function () {
9669
+ const ParserRuleContext = antlr4.ParserRuleContext;
9670
+ ParserRuleContext.prototype.getFormattedText = function() {
9670
9671
  const code = this.parser.getTokenStream().getText(this.getSourceInterval());
9671
- // remove extra quotes, spaces and new lines
9672
9672
  return formatText(code);
9673
9673
  };
9674
-
9675
- // Comment is where users have the most flexibility. The parser should make minimal assumptions about
9676
- // the content and the style including change of line, indentation, etc.
9677
- antlr4.ParserRuleContext.prototype.getComment = function () {
9674
+ ParserRuleContext.prototype.getComment = function() {
9678
9675
  let tokenIndex = this.start.tokenIndex;
9679
- let channel = sequenceLexer.channelNames.indexOf("COMMENT_CHANNEL");
9676
+ const channel = sequenceLexer.channelNames.indexOf("COMMENT_CHANNEL");
9680
9677
  if (this.constructor.name === "BraceBlockContext") {
9681
9678
  tokenIndex = this.stop.tokenIndex;
9682
9679
  }
9683
- let hiddenTokensToLeft = this.parser
9684
- .getTokenStream()
9685
- .getHiddenTokensToLeft(tokenIndex, channel);
9686
- return (
9687
- hiddenTokensToLeft &&
9688
- hiddenTokensToLeft
9689
- .map((t) => t.text.substring(2)) // skip '//'
9690
- .join("\n")
9691
- );
9680
+ const hiddenTokensToLeft = this.parser.getTokenStream().getHiddenTokensToLeft(tokenIndex, channel);
9681
+ return hiddenTokensToLeft && hiddenTokensToLeft.map((t) => t.text.substring(2)).join("\n");
9692
9682
  };
9693
-
9694
- /**
9695
- * Parse ZenUML DSL with a per-call (reentrant) error listener and return both
9696
- * the error-recovered parse tree and a structured error list. Safe to call
9697
- * repeatedly/concurrently — it does not touch the module-level ErrorDetails.
9698
- *
9699
- * @param {string} code ZenUML DSL source
9700
- * @returns {{ rootContext: object, pass: boolean, errorDetails: { line: number, column: number, msg: string }[] }}
9701
- */
9702
9683
  function parse(code) {
9703
9684
  const listener = new CollectingErrorListener();
9704
9685
  const chars = new antlr4.InputStream(code);
@@ -9713,452 +9694,800 @@ function parse(code) {
9713
9694
  return {
9714
9695
  rootContext: tree,
9715
9696
  pass: listener.errorDetails.length === 0,
9716
- errorDetails: listener.errorDetails,
9697
+ errorDetails: listener.errorDetails
9717
9698
  };
9718
9699
  }
9719
-
9720
- /**
9721
- * Validate ZenUML DSL syntax without exposing the parse tree. Reentrant.
9722
- *
9723
- * @param {string} code ZenUML DSL source
9724
- * @returns {{ pass: boolean, errorDetails: { line: number, column: number, msg: string }[] }}
9725
- */
9726
9700
  function validate(code) {
9727
- const { pass, errorDetails } = parse(code);
9728
- return { pass, errorDetails };
9701
+ const { pass, errorDetails: errorDetails2 } = parse(code);
9702
+ return { pass, errorDetails: errorDetails2 };
9729
9703
  }
9730
-
9731
9704
  sequenceParser.ProgContext;
9732
9705
  const RootContext = rootContext;
9733
9706
  const GroupContext = sequenceParser.GroupContext;
9734
9707
  sequenceParser.ParticipantContext;
9735
- const Participants = function (ctx) {
9708
+ const Participants = function(ctx) {
9736
9709
  const toCollector = ToCollector;
9737
9710
  return toCollector.getParticipants(ctx);
9738
9711
  };
9739
-
9740
9712
  const Parser = {
9741
9713
  RootContext: rootContext,
9742
9714
  ProgContext: sequenceParser.ProgContext,
9743
9715
  GroupContext: sequenceParser.GroupContext,
9744
9716
  ParticipantContext: sequenceParser.ParticipantContext,
9745
- Participants: function (ctx) {
9717
+ Participants: function(ctx) {
9746
9718
  const toCollector = ToCollector;
9747
9719
  return toCollector.getParticipants(ctx);
9748
9720
  },
9749
9721
  parse,
9750
9722
  validate,
9751
- ErrorDetails: errorDetails,
9723
+ ErrorDetails: errorDetails
9752
9724
  };
9753
9725
 
9754
- const FRAGMENT_PADDING_X = 10;
9755
- const FRAGMENT_MIN_WIDTH = 100;
9756
- const MARGIN = 20;
9757
- const ARROW_HEAD_WIDTH = 10;
9758
- const OCCURRENCE_WIDTH = 15;
9759
- const OCCURRENCE_BAR_SIDE_WIDTH = (OCCURRENCE_WIDTH - 1) / 2;
9760
- const MIN_PARTICIPANT_WIDTH = 80;
9761
- const PARTICIPANT_ICON_WIDTH = 40;
9762
- const LIFELINE_WIDTH = 1;
9763
- const PARTICIPANT_TOP_SPACE_FOR_GROUP = 20;
9764
- const OCCURRENCE_EMPTY_HEIGHT = 24;
9765
- const DIAGRAM_HEADER_HEIGHT = 24 + 4 * 2 + 1;
9766
-
9767
- var TextType = /* @__PURE__ */ ((TextType2) => {
9768
- TextType2[TextType2["MessageContent"] = 0] = "MessageContent";
9769
- TextType2[TextType2["ParticipantName"] = 1] = "ParticipantName";
9770
- return TextType2;
9771
- })(TextType || {});
9772
-
9773
- var OwnableMessageType = /* @__PURE__ */ ((OwnableMessageType2) => {
9774
- OwnableMessageType2[OwnableMessageType2["SyncMessage"] = 0] = "SyncMessage";
9775
- OwnableMessageType2[OwnableMessageType2["AsyncMessage"] = 1] = "AsyncMessage";
9776
- OwnableMessageType2[OwnableMessageType2["CreationMessage"] = 2] = "CreationMessage";
9777
- OwnableMessageType2[OwnableMessageType2["ReturnMessage"] = 3] = "ReturnMessage";
9778
- return OwnableMessageType2;
9779
- })(OwnableMessageType || {});
9780
-
9781
- class MessageCollector extends sequenceParserListener {
9782
- isBlind = false;
9783
- ownableMessages = [];
9784
- enterMessage = (ctx) => this._addOwnedMessage(OwnableMessageType.SyncMessage)(ctx);
9785
- enterAsyncMessage = (ctx) => this._addOwnedMessage(OwnableMessageType.AsyncMessage)(ctx);
9786
- enterCreation = (ctx) => this._addOwnedMessage(OwnableMessageType.CreationMessage)(ctx);
9787
- enterReturnAsyncMessage = (ctx) => this._addOwnedMessage(OwnableMessageType.ReturnMessage)(ctx);
9788
- enterRet = (ctx) => {
9789
- if (ctx.asyncMessage() || ctx.returnAsyncMessage()) {
9790
- return;
9791
- }
9792
- this._addOwnedMessage(OwnableMessageType.ReturnMessage)(ctx);
9793
- };
9794
- _addOwnedMessage = (type) => (ctx) => {
9795
- if (this.isBlind) {
9796
- return;
9797
- }
9798
- const from = ctx.From();
9799
- const owner = ctx?.Owner();
9800
- let signature = ctx?.SignatureText();
9801
- if (from === owner && ctx.Assignment) {
9802
- const assignment = ctx.Assignment();
9803
- if (assignment) {
9804
- signature = `${assignment.getText()} = ${signature}`;
9805
- }
9806
- }
9807
- this.ownableMessages.push({
9808
- from,
9809
- signature,
9810
- type,
9811
- to: owner
9812
- });
9726
+ function parseArgs(argv) {
9727
+ const args = {
9728
+ inputs: [],
9729
+ check: false,
9730
+ parse: false,
9731
+ json: false,
9732
+ quiet: false,
9733
+ help: false,
9734
+ version: false,
9735
+ md: false,
9736
+ watch: false
9813
9737
  };
9814
- enterParameters() {
9815
- this.isBlind = true;
9738
+ let i = 0;
9739
+ while (i < argv.length) {
9740
+ const arg = argv[i];
9741
+ switch (arg) {
9742
+ case "-i":
9743
+ case "--input":
9744
+ i++;
9745
+ args.inputs.push(argv[i]);
9746
+ break;
9747
+ case "-o":
9748
+ case "--output":
9749
+ i++;
9750
+ args.output = argv[i];
9751
+ break;
9752
+ case "-e":
9753
+ case "--outputFormat":
9754
+ i++;
9755
+ args.outputFormat = argv[i];
9756
+ break;
9757
+ case "-s":
9758
+ case "--scale":
9759
+ i++;
9760
+ args.scale = Number(argv[i]);
9761
+ break;
9762
+ case "-t":
9763
+ case "--theme":
9764
+ i++;
9765
+ args.theme = argv[i];
9766
+ break;
9767
+ case "-c":
9768
+ case "--configFile":
9769
+ i++;
9770
+ args.configFile = argv[i];
9771
+ break;
9772
+ case "--md":
9773
+ args.md = true;
9774
+ break;
9775
+ case "--check":
9776
+ args.check = true;
9777
+ break;
9778
+ case "--parse":
9779
+ args.parse = true;
9780
+ break;
9781
+ case "--json":
9782
+ args.json = true;
9783
+ break;
9784
+ case "-q":
9785
+ case "--quiet":
9786
+ args.quiet = true;
9787
+ break;
9788
+ case "-h":
9789
+ case "--help":
9790
+ args.help = true;
9791
+ break;
9792
+ case "-V":
9793
+ case "--version":
9794
+ args.version = true;
9795
+ break;
9796
+ case "-w":
9797
+ case "--watch":
9798
+ args.watch = true;
9799
+ break;
9800
+ default:
9801
+ process.stderr.write(
9802
+ `Unknown option: ${arg}
9803
+ Run "zenuml --help" for usage.
9804
+ `
9805
+ );
9806
+ process.exit(1);
9807
+ }
9808
+ i++;
9816
9809
  }
9817
- exitParameters() {
9818
- this.isBlind = false;
9810
+ return args;
9811
+ }
9812
+ function loadConfigFile(filePath) {
9813
+ const resolved = resolve(filePath);
9814
+ let raw;
9815
+ try {
9816
+ raw = readFileSync(resolved, "utf-8");
9817
+ } catch {
9818
+ process.stderr.write(`Error: Cannot read config file: ${resolved}
9819
+ `);
9820
+ process.exit(1);
9819
9821
  }
9820
- result() {
9821
- return this.ownableMessages;
9822
+ try {
9823
+ return JSON.parse(raw);
9824
+ } catch {
9825
+ process.stderr.write(`Error: Invalid JSON in config file: ${resolved}
9826
+ `);
9827
+ process.exit(1);
9822
9828
  }
9823
9829
  }
9824
- const allMessagesCache = /* @__PURE__ */ new WeakMap();
9825
- function AllMessages(ctx) {
9826
- if (!ctx) return [];
9827
- const cached = allMessagesCache.get(ctx);
9828
- if (cached) return cached;
9829
- const walker = antlr4.tree.ParseTreeWalker.DEFAULT;
9830
- const listener = new MessageCollector();
9831
- walker.walk(listener, ctx);
9832
- const result = listener.result();
9833
- allMessagesCache.set(ctx, result);
9834
- return result;
9835
- }
9836
9830
 
9837
- const _STARTER_ = "_STARTER_";
9838
- class Participant {
9839
- name;
9840
- left;
9841
- label;
9842
- type;
9843
- stereotype;
9844
- color;
9845
- emoji;
9846
- groupId;
9847
- constructor(name, left, label, type, stereotype, color, groupId, emoji) {
9848
- this.name = name;
9849
- this.left = left;
9850
- this.label = label;
9851
- this.type = type;
9852
- this.stereotype = stereotype;
9853
- this.color = color;
9854
- this.groupId = groupId;
9855
- this.emoji = emoji;
9831
+ function getRuleNames(ctx) {
9832
+ return ctx?.parser?.ruleNames;
9833
+ }
9834
+ function isFacadeNode(node) {
9835
+ return !!node && node.symbol === void 0 && !node.parser && !!node._doc && typeof node.constructor?.name === "string" && node.constructor.name.endsWith("Context");
9836
+ }
9837
+ function facadeRuleName(className) {
9838
+ const base = className.endsWith("Context") ? className.slice(0, -"Context".length) : className;
9839
+ return base.charAt(0).toLowerCase() + base.slice(1);
9840
+ }
9841
+ function serializeFacadeNode(node) {
9842
+ const result = {
9843
+ type: "rule",
9844
+ ruleName: facadeRuleName(node.constructor.name)
9845
+ };
9846
+ const ruleChildren = node.children ?? [];
9847
+ const childSpans = ruleChildren.map((c) => ({
9848
+ c,
9849
+ start: c.start?.start ?? null,
9850
+ end: c.stop?.stop ?? null
9851
+ // inclusive
9852
+ }));
9853
+ const items = [];
9854
+ for (const cs of childSpans) {
9855
+ if (cs.start !== null) {
9856
+ items.push({ off: cs.start, node: serializeParseTree(cs.c) });
9857
+ }
9856
9858
  }
9857
- getDisplayName() {
9858
- return this.label || this.name;
9859
+ const nodeStart = node.start?.start;
9860
+ const nodeStop = node.stop?.stop;
9861
+ if (nodeStart !== void 0 && nodeStop !== null && nodeStop !== void 0) {
9862
+ for (const leaf of node._doc.leaves) {
9863
+ if (leaf.offset < nodeStart) continue;
9864
+ if (leaf.offset > nodeStop) break;
9865
+ if (leaf.hidden) continue;
9866
+ const covered = childSpans.some(
9867
+ (cs) => cs.start !== null && cs.end !== null && leaf.offset >= cs.start && leaf.offset <= cs.end
9868
+ );
9869
+ if (covered) continue;
9870
+ items.push({
9871
+ off: leaf.offset,
9872
+ node: { type: "terminal", text: leaf.text }
9873
+ });
9874
+ }
9859
9875
  }
9860
- hasIcon() {
9861
- return this.type !== void 0;
9876
+ items.sort((a, b) => a.off - b.off);
9877
+ if (items.length > 0) {
9878
+ result.children = items.map((it) => it.node);
9862
9879
  }
9880
+ return result;
9863
9881
  }
9864
- const orderedParticipantsCache = /* @__PURE__ */ new WeakMap();
9865
- function OrderedParticipants(rootContext) {
9866
- if (!rootContext) return [];
9867
- const cached = orderedParticipantsCache.get(rootContext);
9868
- if (cached) return cached;
9869
- const participants = ToCollector.getParticipants(rootContext);
9870
- const participantEntries = participants.Array().map((p) => p.ToValue());
9871
- const allMessages = AllMessages(rootContext);
9872
- const emptyContext = allMessages.length === 0 && participantEntries.length === 0;
9873
- const someMessagesMissFrom = allMessages.some((m) => !m.from);
9874
- const needDefaultStarter = emptyContext || someMessagesMissFrom;
9875
- if (needDefaultStarter) {
9876
- participantEntries.unshift({
9877
- ...blankParticipant,
9878
- name: _STARTER_,
9879
- isStarter: true
9880
- });
9882
+ function serializeParseTree(node) {
9883
+ if (!node) return { type: "null" };
9884
+ if (node.symbol !== void 0) {
9885
+ return {
9886
+ type: "terminal",
9887
+ text: node.getText()
9888
+ };
9889
+ }
9890
+ if (isFacadeNode(node)) {
9891
+ return serializeFacadeNode(node);
9892
+ }
9893
+ const ruleNames = getRuleNames(node);
9894
+ const ruleName = ruleNames && node.ruleIndex !== void 0 ? ruleNames[node.ruleIndex] : void 0;
9895
+ const result = {
9896
+ type: "rule"
9897
+ };
9898
+ if (ruleName) {
9899
+ result.ruleName = ruleName;
9900
+ }
9901
+ const children = node.children;
9902
+ if (children && children.length > 0) {
9903
+ result.children = children.map((child) => serializeParseTree(child));
9881
9904
  }
9882
- const result = participantEntries.map((participant, index, entries) => {
9883
- const previousName = index > 0 ? entries[index - 1].name : "";
9884
- return new Participant(
9885
- participant.name,
9886
- previousName,
9887
- participant.label,
9888
- participant.type,
9889
- participant.stereotype,
9890
- participant.color,
9891
- participant.groupId,
9892
- participant.emoji
9893
- );
9894
- });
9895
- orderedParticipantsCache.set(rootContext, result);
9896
9905
  return result;
9897
9906
  }
9898
9907
 
9899
- function Dual(p, v) {
9900
- return { position: p, velocity: v };
9901
- }
9902
- function dualPlus(x, y) {
9903
- return Dual(x.position + y.position, x.velocity + y.velocity);
9904
- }
9905
- const epsilon = Math.sqrt(Number.EPSILON);
9906
- function dualLessThan(x, y) {
9907
- const d = x.position - y.position;
9908
- return d < -epsilon || Math.abs(d) <= epsilon && x.velocity < y.velocity;
9909
- }
9910
- function DeltaTracker() {
9911
- return {
9912
- delta: Infinity,
9913
- dualLessThan: function(x, y) {
9914
- const lessThan = dualLessThan(x, y);
9915
- if (lessThan) {
9916
- [x, y] = [y, x];
9917
- }
9918
- if (x.velocity < y.velocity) {
9919
- this.delta = Math.min(
9920
- this.delta,
9921
- (x.position - y.position) / (y.velocity - x.velocity)
9922
- );
9923
- }
9924
- return lessThan;
9925
- }
9926
- };
9908
+ function isGlobPattern(s) {
9909
+ return /[*?[]/.test(s);
9927
9910
  }
9928
- function graphFromMatrix(n, matrix) {
9929
- const graph = Array();
9930
- for (let j = 0; j < n; j++) {
9931
- graph.push([]);
9932
- for (let i = 0; i < j; i++) {
9933
- if (matrix[i][j] > 0) {
9934
- graph[j].push({ i, length: Dual(matrix[i][j], 0) });
9935
- }
9911
+ function expandInputs(inputs) {
9912
+ const result = [];
9913
+ for (const input of inputs) {
9914
+ if (input === "-" || !isGlobPattern(input)) {
9915
+ result.push(input);
9916
+ continue;
9936
9917
  }
9937
- }
9938
- return graph;
9939
- }
9940
- function longestPathTable(graph, gaps) {
9941
- const tracker = DeltaTracker();
9942
- let maximum = Dual(0, 0);
9943
- const table = [];
9944
- for (let j = 0; j < graph.length; j++) {
9945
- let argument = null;
9946
- if (j > 0) {
9947
- maximum = dualPlus(maximum, gaps[j - 1]);
9918
+ const glob = new Bun.Glob(input);
9919
+ const matches = [];
9920
+ for (const match of glob.scanSync({
9921
+ cwd: process.cwd(),
9922
+ onlyFiles: true
9923
+ })) {
9924
+ matches.push(match);
9948
9925
  }
9949
- for (const edge of graph[j]) {
9950
- const x = dualPlus(table[edge.i].maximum, edge.length);
9951
- if (tracker.dualLessThan(maximum, x)) {
9952
- argument = edge.i;
9953
- maximum = x;
9954
- }
9926
+ if (matches.length === 0) {
9927
+ throw new Error(`Glob pattern "${input}" matched no files`);
9955
9928
  }
9956
- table.push({ argument, maximum });
9929
+ matches.sort();
9930
+ result.push(...matches);
9957
9931
  }
9958
- return [tracker.delta, table];
9932
+ return result;
9959
9933
  }
9960
- function freezeCriticalGaps(table, gaps) {
9961
- let j = table.length - 1;
9962
- while (j > 0) {
9963
- const argument = table[j].argument;
9964
- if (argument !== null) {
9965
- j = argument;
9966
- } else {
9967
- j--;
9968
- gaps[j].velocity = 0;
9969
- }
9934
+ function isDirectory(p) {
9935
+ try {
9936
+ return statSync(p).isDirectory();
9937
+ } catch {
9938
+ return false;
9970
9939
  }
9971
9940
  }
9972
- function advanceGaps(gaps, delta) {
9973
- for (let i = 0; i < gaps.length; i++) {
9974
- gaps[i].position += gaps[i].velocity * delta;
9941
+ async function readCode(input) {
9942
+ if (input === "-") {
9943
+ return readStdin();
9944
+ }
9945
+ const inputPath = resolve(input);
9946
+ try {
9947
+ return readFileSync(inputPath, "utf-8");
9948
+ } catch {
9949
+ throw new Error(`Cannot read input file: ${inputPath}`);
9975
9950
  }
9976
9951
  }
9977
- function positionsFromTable(table) {
9978
- const positions = [];
9979
- for (const entry of table) {
9980
- positions.push(entry.maximum.position);
9952
+ function resolveOutput(input, output, defaultExt = ".svg") {
9953
+ if (output !== void 0) {
9954
+ if (output === "-") return "-";
9955
+ const resolvedOutput = resolve(output);
9956
+ if (isDirectory(resolvedOutput)) {
9957
+ if (input === "-") return "-";
9958
+ const ext2 = extname(input);
9959
+ const base2 = basename(input, ext2);
9960
+ return join(resolvedOutput, `${base2}${defaultExt}`);
9961
+ }
9962
+ return resolvedOutput;
9981
9963
  }
9982
- return positions;
9964
+ if (input === "-") return "-";
9965
+ const ext = extname(input);
9966
+ const base = basename(input, ext);
9967
+ const dir = dirname(resolve(input));
9968
+ return join(dir, `${base}${defaultExt}`);
9983
9969
  }
9984
- function find_optimal(matrix) {
9985
- const n = matrix.length;
9986
- const graph = graphFromMatrix(n, matrix);
9987
- const gaps = [];
9988
- for (let j = 1; j < n; j++) {
9989
- gaps.push(Dual(0, 1));
9970
+ async function readStdin() {
9971
+ const chunks = [];
9972
+ for await (const chunk of Bun.stdin.stream()) {
9973
+ chunks.push(chunk);
9990
9974
  }
9991
- while (true) {
9992
- const [delta, table] = longestPathTable(graph, gaps);
9993
- if (delta == Infinity) {
9994
- return positionsFromTable(table);
9995
- }
9996
- if (table[n - 1].maximum.velocity > 0) {
9997
- freezeCriticalGaps(table, gaps);
9998
- } else {
9999
- advanceGaps(gaps, delta);
10000
- }
9975
+ return Buffer.concat(chunks).toString("utf-8");
9976
+ }
9977
+
9978
+ async function checkOne(input) {
9979
+ const fileName = input === "-" ? "<stdin>" : input;
9980
+ let code;
9981
+ try {
9982
+ code = await readCode(input);
9983
+ } catch (err) {
9984
+ return {
9985
+ file: fileName,
9986
+ pass: false,
9987
+ errors: [{ line: 0, column: 0, msg: err.message }]
9988
+ };
10001
9989
  }
9990
+ Parser.ErrorDetails.length = 0;
9991
+ Parser.RootContext(code);
9992
+ const errors = Parser.ErrorDetails.map((e) => ({
9993
+ line: e.line,
9994
+ column: e.column,
9995
+ msg: e.msg
9996
+ }));
9997
+ return {
9998
+ file: fileName,
9999
+ pass: errors.length === 0,
10000
+ errors
10001
+ };
10002
10002
  }
10003
10003
 
10004
- class Coordinates {
10005
- m = [];
10006
- widthProvider;
10007
- participantModels;
10008
- ownableMessages;
10009
- participantModelsByName = /* @__PURE__ */ new Map();
10010
- participantIndexByName = /* @__PURE__ */ new Map();
10011
- participantWidthCache = /* @__PURE__ */ new Map();
10012
- // Solved positions for all participants; the solver runs once per instance.
10013
- positionsCache = null;
10014
- constructor(ctx, widthProvider) {
10015
- this.participantModels = OrderedParticipants(ctx);
10016
- this.ownableMessages = AllMessages(ctx);
10017
- this.participantModels.forEach((p, i) => {
10018
- this.participantModelsByName.set(p.name, p);
10019
- this.participantIndexByName.set(p.name, i);
10020
- });
10021
- this.widthProvider = widthProvider;
10022
- this.walkThrough();
10004
+ function extractZenumlBlocks(md) {
10005
+ const results = [];
10006
+ const fencePattern = /^(`{3,})zenuml([^\n]*)\n([\s\S]*?)\n?\1\s*$/gm;
10007
+ let match;
10008
+ let blockIndex = 0;
10009
+ while ((match = fencePattern.exec(md)) !== null) {
10010
+ const raw = match[0];
10011
+ const infoExtra = match[2];
10012
+ const code = match[3];
10013
+ const title = infoExtra.trim();
10014
+ const empty = code.trim().length === 0;
10015
+ results.push({ index: blockIndex++, code, title, raw, empty });
10023
10016
  }
10024
- orderedParticipantNames() {
10025
- return this.participantModels.map((p) => p.name);
10017
+ return results;
10018
+ }
10019
+
10020
+ let _browser = null;
10021
+ function pngRuntimeHelp(detail) {
10022
+ return [
10023
+ detail,
10024
+ "",
10025
+ "PNG output requires Playwright's Chromium runtime.",
10026
+ "Install it with:",
10027
+ " npm install playwright-core",
10028
+ " npx playwright-core install chromium",
10029
+ "",
10030
+ "Or point ZenUML at an existing Chrome/Chromium binary:",
10031
+ " ZENUML_CHROMIUM_PATH=/path/to/chrome zenuml -i diagram.zenuml -o diagram.png"
10032
+ ].join("\n");
10033
+ }
10034
+ async function getPlaywrightBrowser() {
10035
+ if (_browser) return _browser;
10036
+ let playwright;
10037
+ try {
10038
+ playwright = await import('playwright-core');
10039
+ } catch (error) {
10040
+ throw new Error(
10041
+ pngRuntimeHelp(
10042
+ `Cannot load optional dependency "playwright-core": ${error instanceof Error ? error.message : String(error)}`
10043
+ )
10044
+ );
10026
10045
  }
10027
- getPosition(participantName) {
10028
- if (!participantName) return 0;
10029
- const pIndex = this.participantIndexByName.get(participantName);
10030
- if (pIndex === void 0) {
10031
- console.warn(`Participant ${participantName} not found`);
10032
- return 0;
10033
- }
10034
- if (!this.positionsCache) {
10035
- this.positionsCache = find_optimal(this.m);
10036
- }
10037
- const leftGap = this.getParticipantGap(this.participantModels[0]);
10038
- const position = leftGap + this.positionsCache[pIndex];
10039
- return position;
10046
+ const executablePath = process.env["ZENUML_CHROMIUM_PATH"];
10047
+ try {
10048
+ _browser = await playwright.chromium.launch(
10049
+ executablePath ? { executablePath } : void 0
10050
+ );
10051
+ return _browser;
10052
+ } catch (error) {
10053
+ throw new Error(
10054
+ pngRuntimeHelp(
10055
+ `Cannot launch Chromium${executablePath ? ` at ${executablePath}` : ""}: ${error instanceof Error ? error.message : String(error)}`
10056
+ )
10057
+ );
10040
10058
  }
10041
- walkThrough() {
10042
- this.withParticipantGaps(this.participantModels);
10043
- this.withMessageGaps(this.ownableMessages);
10044
- }
10045
- half(participantName) {
10046
- const participant = this.getParticipantModel(participantName);
10047
- return participant ? this._getParticipantWidth(participant) / 2 : 0;
10048
- }
10049
- left(participantName) {
10050
- return this.getPosition(participantName) - this.half(participantName);
10051
- }
10052
- right(participantName) {
10053
- return this.getPosition(participantName) + this.half(participantName);
10054
- }
10055
- getWidth() {
10056
- const lastParticipant = this.participantModels[this.participantModels.length - 1].name;
10057
- const calculatedWidth = this.getPosition(lastParticipant) + this.half(lastParticipant);
10058
- return Math.max(calculatedWidth, 200);
10059
+ }
10060
+ async function closeBrowser() {
10061
+ if (_browser) {
10062
+ await _browser.close();
10063
+ _browser = null;
10059
10064
  }
10060
- distance(left, right) {
10061
- return this.getPosition(right) - this.getPosition(left);
10065
+ }
10066
+ async function rasterizeToPng(svgString, svgWidth, svgHeight, scale) {
10067
+ const browser = await getPlaywrightBrowser();
10068
+ const page = await browser.newPage({
10069
+ viewport: {
10070
+ width: Math.ceil(svgWidth),
10071
+ height: Math.ceil(svgHeight)
10072
+ },
10073
+ deviceScaleFactor: scale
10074
+ });
10075
+ try {
10076
+ const html = `<!DOCTYPE html>
10077
+ <html><head><style>
10078
+ html, body { margin: 0; padding: 0; background: white; overflow: hidden; }
10079
+ svg { display: block; width: ${svgWidth}px; height: ${svgHeight}px; }
10080
+ </style></head><body>${svgString}</body></html>`;
10081
+ await page.setContent(html, { waitUntil: "load" });
10082
+ const png = await page.screenshot({ type: "png" });
10083
+ return Buffer.from(png);
10084
+ } finally {
10085
+ await page.close();
10062
10086
  }
10063
- getMessageWidth(message) {
10064
- const halfSelf = this.half(message.to);
10065
- let messageWidth = this.widthProvider(
10066
- message.signature,
10067
- TextType.MessageContent
10068
- );
10069
- if (message.type === OwnableMessageType.CreationMessage) {
10070
- messageWidth += halfSelf;
10087
+ }
10088
+
10089
+ const FRAGMENT_PADDING_X = 10;
10090
+ const FRAGMENT_MIN_WIDTH = 100;
10091
+ const MARGIN = 20;
10092
+ const ARROW_HEAD_WIDTH = 10;
10093
+ const OCCURRENCE_WIDTH = 15;
10094
+ const OCCURRENCE_BAR_SIDE_WIDTH = (OCCURRENCE_WIDTH - 1) / 2;
10095
+ const MIN_PARTICIPANT_WIDTH = 80;
10096
+ const PARTICIPANT_ICON_WIDTH = 40;
10097
+ const LIFELINE_WIDTH = 1;
10098
+ const PARTICIPANT_TOP_SPACE_FOR_GROUP = 20;
10099
+ const OCCURRENCE_EMPTY_HEIGHT = 24;
10100
+ const DIAGRAM_HEADER_HEIGHT = 24 + 4 * 2 + 1;
10101
+
10102
+ var OwnableMessageType = /* @__PURE__ */ ((OwnableMessageType2) => {
10103
+ OwnableMessageType2[OwnableMessageType2["SyncMessage"] = 0] = "SyncMessage";
10104
+ OwnableMessageType2[OwnableMessageType2["AsyncMessage"] = 1] = "AsyncMessage";
10105
+ OwnableMessageType2[OwnableMessageType2["CreationMessage"] = 2] = "CreationMessage";
10106
+ OwnableMessageType2[OwnableMessageType2["ReturnMessage"] = 3] = "ReturnMessage";
10107
+ return OwnableMessageType2;
10108
+ })(OwnableMessageType || {});
10109
+
10110
+ class MessageCollector extends sequenceParserListener {
10111
+ isBlind = false;
10112
+ ownableMessages = [];
10113
+ enterMessage = (ctx) => this._addOwnedMessage(OwnableMessageType.SyncMessage)(ctx);
10114
+ enterAsyncMessage = (ctx) => this._addOwnedMessage(OwnableMessageType.AsyncMessage)(ctx);
10115
+ enterCreation = (ctx) => this._addOwnedMessage(OwnableMessageType.CreationMessage)(ctx);
10116
+ enterReturnAsyncMessage = (ctx) => this._addOwnedMessage(OwnableMessageType.ReturnMessage)(ctx);
10117
+ enterRet = (ctx) => {
10118
+ if (ctx.asyncMessage() || ctx.returnAsyncMessage()) {
10119
+ return;
10071
10120
  }
10072
- return messageWidth;
10073
- }
10074
- withMessageGaps(ownableMessages) {
10075
- for (const message of ownableMessages) {
10076
- const from = message.from || _STARTER_;
10077
- const indexFrom = this.participantIndexByName.get(from) ?? -1;
10078
- const indexTo = this.participantIndexByName.get(message.to) ?? -1;
10079
- if (indexFrom === -1 || indexTo === -1) {
10080
- console.warn(`Participant ${from} or ${message.to} not found`);
10081
- continue;
10121
+ this._addOwnedMessage(OwnableMessageType.ReturnMessage)(ctx);
10122
+ };
10123
+ _addOwnedMessage = (type) => (ctx) => {
10124
+ if (this.isBlind) {
10125
+ return;
10126
+ }
10127
+ const from = ctx.From();
10128
+ const owner = ctx?.Owner();
10129
+ let signature = ctx?.SignatureText();
10130
+ if (from === owner && ctx.Assignment) {
10131
+ const assignment = ctx.Assignment();
10132
+ if (assignment) {
10133
+ signature = `${assignment.getText()} = ${signature}`;
10082
10134
  }
10083
- const leftIndex = Math.min(indexFrom, indexTo);
10084
- const rightIndex = Math.max(indexFrom, indexTo);
10085
- const messageWidth = this.getMessageWidth(message);
10086
- this.m[leftIndex][rightIndex] = Math.max(
10087
- messageWidth + ARROW_HEAD_WIDTH + OCCURRENCE_WIDTH,
10088
- this.m[leftIndex][rightIndex]
10089
- );
10090
10135
  }
10091
- }
10092
- withParticipantGaps(participantModels) {
10093
- this.m = participantModels.map((_, i) => {
10094
- return participantModels.map((v, j) => {
10095
- return j - i === 1 ? this.getParticipantGap(v) : 0;
10096
- });
10136
+ this.ownableMessages.push({
10137
+ from,
10138
+ signature,
10139
+ type,
10140
+ to: owner
10097
10141
  });
10142
+ };
10143
+ enterParameters() {
10144
+ this.isBlind = true;
10098
10145
  }
10099
- getParticipantGap(p) {
10100
- return this.half(p.left) + this.half(p.name);
10101
- }
10102
- getParticipantModel(name) {
10103
- return this.participantModelsByName.get(name);
10146
+ exitParameters() {
10147
+ this.isBlind = false;
10104
10148
  }
10105
- _getParticipantWidth(participant) {
10106
- const cachedWidth = this.participantWidthCache.get(participant.name);
10107
- if (cachedWidth != null) {
10108
- return cachedWidth;
10109
- }
10110
- const hasIcon = participant.hasIcon();
10111
- const iconWidth = hasIcon ? PARTICIPANT_ICON_WIDTH : 0;
10112
- const emojiWidth = participant.emoji ? 24 : 0;
10113
- const labelWidth = this.widthProvider(
10114
- participant.getDisplayName(),
10115
- TextType.ParticipantName
10116
- );
10117
- const participantWidth = Math.max(labelWidth + iconWidth + emojiWidth, MIN_PARTICIPANT_WIDTH) + MARGIN;
10118
- this.participantWidthCache.set(participant.name, participantWidth);
10119
- return participantWidth;
10149
+ result() {
10150
+ return this.ownableMessages;
10120
10151
  }
10121
10152
  }
10153
+ const allMessagesCache = /* @__PURE__ */ new WeakMap();
10154
+ function AllMessages(ctx) {
10155
+ if (!ctx) return [];
10156
+ const cached = allMessagesCache.get(ctx);
10157
+ if (cached) return cached;
10158
+ const walker = antlr4.tree.ParseTreeWalker.DEFAULT;
10159
+ const listener = new MessageCollector();
10160
+ walker.walk(listener, ctx);
10161
+ const result = listener.result();
10162
+ allMessagesCache.set(ctx, result);
10163
+ return result;
10164
+ }
10122
10165
 
10123
- const createStatementKey = (statement) => {
10124
- if (!statement?.start || !statement?.stop) {
10125
- return "";
10166
+ const _STARTER_ = "_STARTER_";
10167
+ class Participant {
10168
+ name;
10169
+ left;
10170
+ label;
10171
+ type;
10172
+ stereotype;
10173
+ color;
10174
+ emoji;
10175
+ groupId;
10176
+ constructor(name, left, label, type, stereotype, color, groupId, emoji) {
10177
+ this.name = name;
10178
+ this.left = left;
10179
+ this.label = label;
10180
+ this.type = type;
10181
+ this.stereotype = stereotype;
10182
+ this.color = color;
10183
+ this.groupId = groupId;
10184
+ this.emoji = emoji;
10126
10185
  }
10127
- return `${statement.start.start}-${statement.stop.stop}`;
10128
- };
10129
-
10130
- class NodeVM {
10131
- constructor(context, runtime) {
10132
- this.context = context;
10133
- this.runtime = runtime;
10186
+ getDisplayName() {
10187
+ return this.label || this.name;
10134
10188
  }
10135
- layoutBlock(blockContext, origin, startTop, parentKind) {
10136
- if (!blockContext) {
10137
- return startTop;
10138
- }
10139
- return new BlockVM(blockContext, this.runtime).layout(
10140
- origin,
10141
- startTop,
10142
- parentKind
10143
- );
10189
+ hasIcon() {
10190
+ return this.type !== void 0;
10191
+ }
10192
+ }
10193
+ const orderedParticipantsCache = /* @__PURE__ */ new WeakMap();
10194
+ function OrderedParticipants(rootContext) {
10195
+ if (!rootContext) return [];
10196
+ const cached = orderedParticipantsCache.get(rootContext);
10197
+ if (cached) return cached;
10198
+ const participants = ToCollector.getParticipants(rootContext);
10199
+ const participantEntries = participants.Array().map((p) => p.ToValue());
10200
+ const allMessages = AllMessages(rootContext);
10201
+ const emptyContext = allMessages.length === 0 && participantEntries.length === 0;
10202
+ const someMessagesMissFrom = allMessages.some((m) => !m.from);
10203
+ const needDefaultStarter = emptyContext || someMessagesMissFrom;
10204
+ if (needDefaultStarter) {
10205
+ participantEntries.unshift({
10206
+ ...blankParticipant,
10207
+ name: _STARTER_,
10208
+ isStarter: true
10209
+ });
10144
10210
  }
10211
+ const result = participantEntries.map((participant, index, entries) => {
10212
+ const previousName = index > 0 ? entries[index - 1].name : "";
10213
+ return new Participant(
10214
+ participant.name,
10215
+ previousName,
10216
+ participant.label,
10217
+ participant.type,
10218
+ participant.stereotype,
10219
+ participant.color,
10220
+ participant.groupId,
10221
+ participant.emoji
10222
+ );
10223
+ });
10224
+ orderedParticipantsCache.set(rootContext, result);
10225
+ return result;
10145
10226
  }
10146
10227
 
10147
- const SPACING_UNIT = 4;
10148
- const tw = (value) => value * SPACING_UNIT;
10149
- const DEFAULT_LAYOUT_METRICS = {
10150
- statementMarginY: tw(4),
10151
- // .statement-container .my-4
10152
- fragmentHeaderHeight: 25,
10153
- // .fragment .leading-4 => line-height: 1rem
10154
- fragmentPaddingBottom: 10
10155
- // .zenuml .fragment =>padding-bottom: 10px
10156
- };
10157
- const MESSAGE_HEIGHT = 16;
10158
- const SELF_MESSAGE_HEIGHT = 30;
10159
- const ASYNC_SELF_MESSAGE_HEIGHT = 44;
10160
- const CREATION_MESSAGE_HEIGHT = 40;
10161
- const COMMENT_LINE_HEIGHT = tw(5);
10228
+ function Dual(p, v) {
10229
+ return { position: p, velocity: v };
10230
+ }
10231
+ function dualPlus(x, y) {
10232
+ return Dual(x.position + y.position, x.velocity + y.velocity);
10233
+ }
10234
+ const epsilon = Math.sqrt(Number.EPSILON);
10235
+ function dualLessThan(x, y) {
10236
+ const d = x.position - y.position;
10237
+ return d < -epsilon || Math.abs(d) <= epsilon && x.velocity < y.velocity;
10238
+ }
10239
+ function DeltaTracker() {
10240
+ return {
10241
+ delta: Infinity,
10242
+ dualLessThan: function(x, y) {
10243
+ const lessThan = dualLessThan(x, y);
10244
+ if (lessThan) {
10245
+ [x, y] = [y, x];
10246
+ }
10247
+ if (x.velocity < y.velocity) {
10248
+ this.delta = Math.min(
10249
+ this.delta,
10250
+ (x.position - y.position) / (y.velocity - x.velocity)
10251
+ );
10252
+ }
10253
+ return lessThan;
10254
+ }
10255
+ };
10256
+ }
10257
+ function graphFromMatrix(n, matrix) {
10258
+ const graph = Array();
10259
+ for (let j = 0; j < n; j++) {
10260
+ graph.push([]);
10261
+ for (let i = 0; i < j; i++) {
10262
+ if (matrix[i][j] > 0) {
10263
+ graph[j].push({ i, length: Dual(matrix[i][j], 0) });
10264
+ }
10265
+ }
10266
+ }
10267
+ return graph;
10268
+ }
10269
+ function longestPathTable(graph, gaps) {
10270
+ const tracker = DeltaTracker();
10271
+ let maximum = Dual(0, 0);
10272
+ const table = [];
10273
+ for (let j = 0; j < graph.length; j++) {
10274
+ let argument = null;
10275
+ if (j > 0) {
10276
+ maximum = dualPlus(maximum, gaps[j - 1]);
10277
+ }
10278
+ for (const edge of graph[j]) {
10279
+ const x = dualPlus(table[edge.i].maximum, edge.length);
10280
+ if (tracker.dualLessThan(maximum, x)) {
10281
+ argument = edge.i;
10282
+ maximum = x;
10283
+ }
10284
+ }
10285
+ table.push({ argument, maximum });
10286
+ }
10287
+ return [tracker.delta, table];
10288
+ }
10289
+ function freezeCriticalGaps(table, gaps) {
10290
+ let j = table.length - 1;
10291
+ while (j > 0) {
10292
+ const argument = table[j].argument;
10293
+ if (argument !== null) {
10294
+ j = argument;
10295
+ } else {
10296
+ j--;
10297
+ gaps[j].velocity = 0;
10298
+ }
10299
+ }
10300
+ }
10301
+ function advanceGaps(gaps, delta) {
10302
+ for (let i = 0; i < gaps.length; i++) {
10303
+ gaps[i].position += gaps[i].velocity * delta;
10304
+ }
10305
+ }
10306
+ function positionsFromTable(table) {
10307
+ const positions = [];
10308
+ for (const entry of table) {
10309
+ positions.push(entry.maximum.position);
10310
+ }
10311
+ return positions;
10312
+ }
10313
+ function find_optimal(matrix) {
10314
+ const n = matrix.length;
10315
+ const graph = graphFromMatrix(n, matrix);
10316
+ const gaps = [];
10317
+ for (let j = 1; j < n; j++) {
10318
+ gaps.push(Dual(0, 1));
10319
+ }
10320
+ while (true) {
10321
+ const [delta, table] = longestPathTable(graph, gaps);
10322
+ if (delta == Infinity) {
10323
+ return positionsFromTable(table);
10324
+ }
10325
+ if (table[n - 1].maximum.velocity > 0) {
10326
+ freezeCriticalGaps(table, gaps);
10327
+ } else {
10328
+ advanceGaps(gaps, delta);
10329
+ }
10330
+ }
10331
+ }
10332
+
10333
+ class Coordinates {
10334
+ m = [];
10335
+ widthProvider;
10336
+ participantModels;
10337
+ ownableMessages;
10338
+ participantModelsByName = /* @__PURE__ */ new Map();
10339
+ participantIndexByName = /* @__PURE__ */ new Map();
10340
+ participantWidthCache = /* @__PURE__ */ new Map();
10341
+ // Solved positions for all participants; the solver runs once per instance.
10342
+ positionsCache = null;
10343
+ constructor(ctx, widthProvider) {
10344
+ this.participantModels = OrderedParticipants(ctx);
10345
+ this.ownableMessages = AllMessages(ctx);
10346
+ this.participantModels.forEach((p, i) => {
10347
+ this.participantModelsByName.set(p.name, p);
10348
+ this.participantIndexByName.set(p.name, i);
10349
+ });
10350
+ this.widthProvider = widthProvider;
10351
+ this.walkThrough();
10352
+ }
10353
+ orderedParticipantNames() {
10354
+ return this.participantModels.map((p) => p.name);
10355
+ }
10356
+ getPosition(participantName) {
10357
+ if (!participantName) return 0;
10358
+ const pIndex = this.participantIndexByName.get(participantName);
10359
+ if (pIndex === void 0) {
10360
+ console.warn(`Participant ${participantName} not found`);
10361
+ return 0;
10362
+ }
10363
+ if (!this.positionsCache) {
10364
+ this.positionsCache = find_optimal(this.m);
10365
+ }
10366
+ const leftGap = this.getParticipantGap(this.participantModels[0]);
10367
+ const position = leftGap + this.positionsCache[pIndex];
10368
+ return position;
10369
+ }
10370
+ walkThrough() {
10371
+ this.withParticipantGaps(this.participantModels);
10372
+ this.withMessageGaps(this.ownableMessages);
10373
+ }
10374
+ half(participantName) {
10375
+ const participant = this.getParticipantModel(participantName);
10376
+ return participant ? this._getParticipantWidth(participant) / 2 : 0;
10377
+ }
10378
+ left(participantName) {
10379
+ return this.getPosition(participantName) - this.half(participantName);
10380
+ }
10381
+ right(participantName) {
10382
+ return this.getPosition(participantName) + this.half(participantName);
10383
+ }
10384
+ getWidth() {
10385
+ const lastParticipant = this.participantModels[this.participantModels.length - 1].name;
10386
+ const calculatedWidth = this.getPosition(lastParticipant) + this.half(lastParticipant);
10387
+ return Math.max(calculatedWidth, 200);
10388
+ }
10389
+ distance(left, right) {
10390
+ return this.getPosition(right) - this.getPosition(left);
10391
+ }
10392
+ getMessageWidth(message) {
10393
+ const halfSelf = this.half(message.to);
10394
+ let messageWidth = this.widthProvider(
10395
+ message.signature,
10396
+ TextType.MessageContent
10397
+ );
10398
+ if (message.type === OwnableMessageType.CreationMessage) {
10399
+ messageWidth += halfSelf;
10400
+ }
10401
+ return messageWidth;
10402
+ }
10403
+ withMessageGaps(ownableMessages) {
10404
+ for (const message of ownableMessages) {
10405
+ const from = message.from || _STARTER_;
10406
+ const indexFrom = this.participantIndexByName.get(from) ?? -1;
10407
+ const indexTo = this.participantIndexByName.get(message.to) ?? -1;
10408
+ if (indexFrom === -1 || indexTo === -1) {
10409
+ console.warn(`Participant ${from} or ${message.to} not found`);
10410
+ continue;
10411
+ }
10412
+ const leftIndex = Math.min(indexFrom, indexTo);
10413
+ const rightIndex = Math.max(indexFrom, indexTo);
10414
+ const messageWidth = this.getMessageWidth(message);
10415
+ this.m[leftIndex][rightIndex] = Math.max(
10416
+ messageWidth + ARROW_HEAD_WIDTH + OCCURRENCE_WIDTH,
10417
+ this.m[leftIndex][rightIndex]
10418
+ );
10419
+ }
10420
+ }
10421
+ withParticipantGaps(participantModels) {
10422
+ this.m = participantModels.map((_, i) => {
10423
+ return participantModels.map((v, j) => {
10424
+ return j - i === 1 ? this.getParticipantGap(v) : 0;
10425
+ });
10426
+ });
10427
+ }
10428
+ getParticipantGap(p) {
10429
+ return this.half(p.left) + this.half(p.name);
10430
+ }
10431
+ getParticipantModel(name) {
10432
+ return this.participantModelsByName.get(name);
10433
+ }
10434
+ _getParticipantWidth(participant) {
10435
+ const cachedWidth = this.participantWidthCache.get(participant.name);
10436
+ if (cachedWidth != null) {
10437
+ return cachedWidth;
10438
+ }
10439
+ const hasIcon = participant.hasIcon();
10440
+ const iconWidth = hasIcon ? PARTICIPANT_ICON_WIDTH : 0;
10441
+ const emojiWidth = participant.emoji ? 24 : 0;
10442
+ const labelWidth = this.widthProvider(
10443
+ participant.getDisplayName(),
10444
+ TextType.ParticipantName
10445
+ );
10446
+ const participantWidth = Math.max(labelWidth + iconWidth + emojiWidth, MIN_PARTICIPANT_WIDTH) + MARGIN;
10447
+ this.participantWidthCache.set(participant.name, participantWidth);
10448
+ return participantWidth;
10449
+ }
10450
+ }
10451
+
10452
+ const createStatementKey = (statement) => {
10453
+ if (!statement?.start || !statement?.stop) {
10454
+ return "";
10455
+ }
10456
+ return `${statement.start.start}-${statement.stop.stop}`;
10457
+ };
10458
+
10459
+ class NodeVM {
10460
+ constructor(context, runtime) {
10461
+ this.context = context;
10462
+ this.runtime = runtime;
10463
+ }
10464
+ layoutBlock(blockContext, origin, startTop, parentKind) {
10465
+ if (!blockContext) {
10466
+ return startTop;
10467
+ }
10468
+ return new BlockVM(blockContext, this.runtime).layout(
10469
+ origin,
10470
+ startTop,
10471
+ parentKind
10472
+ );
10473
+ }
10474
+ }
10475
+
10476
+ const SPACING_UNIT = 4;
10477
+ const tw = (value) => value * SPACING_UNIT;
10478
+ const DEFAULT_LAYOUT_METRICS = {
10479
+ statementMarginY: tw(4),
10480
+ // .statement-container .my-4
10481
+ fragmentHeaderHeight: 25,
10482
+ // .fragment .leading-4 => line-height: 1rem
10483
+ fragmentPaddingBottom: 10
10484
+ // .zenuml .fragment =>padding-bottom: 10px
10485
+ };
10486
+ const MESSAGE_HEIGHT = 16;
10487
+ const SELF_MESSAGE_HEIGHT = 30;
10488
+ const ASYNC_SELF_MESSAGE_HEIGHT = 44;
10489
+ const CREATION_MESSAGE_HEIGHT = 40;
10490
+ const COMMENT_LINE_HEIGHT = tw(5);
10162
10491
  const FRAGMENT_BORDER_WIDTH = 1;
10163
10492
  const FRAGMENT_GUARD_HEIGHT = 28;
10164
10493
 
@@ -10167,6 +10496,11 @@ function getLocalParticipantNames(ctx) {
10167
10496
  return [ctx.Origin() || _STARTER_, ...Participants(ctx).Names()];
10168
10497
  }
10169
10498
 
10499
+ const COMMENT_MARKDOWN_OPTIONS = { gfm: true, breaks: true };
10500
+ function lexComment(text) {
10501
+ return marked.lexer(text, COMMENT_MARKDOWN_OPTIONS);
10502
+ }
10503
+
10170
10504
  const cssColors = [
10171
10505
  "aliceblue",
10172
10506
  "antiquewhite",
@@ -10577,17 +10911,13 @@ class CommentClass {
10577
10911
  }
10578
10912
  }
10579
10913
 
10580
- const defaultTokensOptions = {
10581
- gfm: true,
10582
- breaks: true
10583
- };
10584
10914
  class MarkdownMeasurer {
10585
10915
  measure(_text) {
10586
10916
  if (!_text || !_text.trim()) {
10587
10917
  return 0;
10588
10918
  }
10589
10919
  const commentObj = new CommentClass(_text);
10590
- const tokens = marked.lexer(commentObj?.text ?? "", defaultTokensOptions);
10920
+ const tokens = lexComment(commentObj?.text ?? "");
10591
10921
  if (!tokens.length) {
10592
10922
  return 0;
10593
10923
  }
@@ -10849,6 +11179,92 @@ const SINGLE_BLOCK_FRAGMENT_KINDS = [
10849
11179
  "critical"
10850
11180
  ];
10851
11181
 
11182
+ const blockOf = (ctx) => ctx?.braceBlock?.()?.block?.();
11183
+ const conditionText = (ctx) => ctx?.parExpr?.()?.condition?.()?.getFormattedText?.() || "";
11184
+ function fragmentOf(stat) {
11185
+ for (const kind of SINGLE_BLOCK_FRAGMENT_KINDS) {
11186
+ const frag = stat[kind]?.();
11187
+ if (frag) {
11188
+ return {
11189
+ kind,
11190
+ context: frag,
11191
+ sections: [
11192
+ {
11193
+ guardKeyword: kind === "loop" ? frag.WHILE?.()?.getText?.() : void 0,
11194
+ condition: conditionText(frag),
11195
+ isLeading: true,
11196
+ block: blockOf(frag)
11197
+ }
11198
+ ]
11199
+ };
11200
+ }
11201
+ }
11202
+ const alt = stat.alt?.();
11203
+ if (alt) {
11204
+ const sections = [];
11205
+ const ifBlock = alt.ifBlock?.();
11206
+ if (ifBlock) {
11207
+ sections.push({
11208
+ guardKeyword: "if",
11209
+ condition: conditionText(ifBlock),
11210
+ isLeading: true,
11211
+ block: blockOf(ifBlock)
11212
+ });
11213
+ }
11214
+ for (const elseIf of alt.elseIfBlock?.() || []) {
11215
+ sections.push({
11216
+ guardKeyword: "else if",
11217
+ condition: conditionText(elseIf),
11218
+ isLeading: false,
11219
+ block: blockOf(elseIf)
11220
+ });
11221
+ }
11222
+ const elseBlock = alt.elseBlock?.();
11223
+ if (elseBlock) {
11224
+ sections.push({
11225
+ guardKeyword: "else",
11226
+ isLeading: false,
11227
+ block: blockOf(elseBlock)
11228
+ });
11229
+ }
11230
+ return { kind: "alt", context: alt, sections };
11231
+ }
11232
+ const tcf = stat.tcf?.();
11233
+ if (tcf) {
11234
+ const sections = [];
11235
+ const tryBlock = tcf.tryBlock?.();
11236
+ if (tryBlock) {
11237
+ sections.push({
11238
+ guardKeyword: "try",
11239
+ isLeading: true,
11240
+ block: blockOf(tryBlock)
11241
+ });
11242
+ }
11243
+ for (const catchBlock of tcf.catchBlock?.() || []) {
11244
+ sections.push({
11245
+ guardKeyword: "catch",
11246
+ condition: catchBlock.invocation?.()?.parameters?.()?.getFormattedText?.() || "",
11247
+ isLeading: false,
11248
+ block: blockOf(catchBlock)
11249
+ });
11250
+ }
11251
+ const finallyBlock = tcf.finallyBlock?.();
11252
+ if (finallyBlock) {
11253
+ sections.push({
11254
+ guardKeyword: "finally",
11255
+ isLeading: false,
11256
+ block: blockOf(finallyBlock)
11257
+ });
11258
+ }
11259
+ return { kind: "tcf", context: tcf, sections };
11260
+ }
11261
+ const ref = stat.ref?.();
11262
+ if (ref) {
11263
+ return { kind: "ref", context: ref, sections: [] };
11264
+ }
11265
+ return null;
11266
+ }
11267
+
10852
11268
  class SyncMessageStatementVM extends StatementVM {
10853
11269
  constructor(statement, message, runtime) {
10854
11270
  super(statement, runtime);
@@ -10894,224 +11310,86 @@ const createStatementVM = (statement, runtime) => {
10894
11310
  return new AsyncMessageStatementVM(statement, asyncMessage, runtime);
10895
11311
  }
10896
11312
  if (statement.ret?.()) {
10897
- return new ReturnStatementVM(statement, runtime);
10898
- }
10899
- if (statement.divider?.()) {
10900
- return new DividerStatementVM(statement, runtime);
10901
- }
10902
- for (const kind of SINGLE_BLOCK_FRAGMENT_KINDS) {
10903
- const fragment = statement[kind]?.();
10904
- if (fragment) {
10905
- return new FragmentSingleBlockVM(statement, fragment, runtime, kind);
10906
- }
10907
- }
10908
- const tcf = statement.tcf?.();
10909
- if (tcf) {
10910
- return new FragmentTryCatchVM(statement, tcf, runtime);
10911
- }
10912
- const alt = statement.alt?.();
10913
- if (alt) {
10914
- return new FragmentAltVM(statement, alt, runtime);
10915
- }
10916
- if (statement.ref?.()) {
10917
- return new FragmentRefVM(statement, runtime);
10918
- }
10919
- return new EmptyStatementVM(statement, runtime);
10920
- };
10921
-
10922
- class BlockVM extends NodeVM {
10923
- statements;
10924
- constructor(context, runtime) {
10925
- super(context, runtime);
10926
- this.statements = context?.stat?.() || [];
10927
- }
10928
- layout(originParticipant, startTop, parentKind) {
10929
- if (!this.statements.length) return startTop;
10930
- const metrics = this.runtime.metrics;
10931
- let cursor = startTop + metrics.statementMarginY;
10932
- this.statements.forEach((statement, index) => {
10933
- if (parentKind === "par" && index !== 0) cursor += 1;
10934
- const statementVM = createStatementVM(statement, this.runtime);
10935
- const coordinate = statementVM.measure(cursor, originParticipant);
10936
- this.runtime.recordCoordinate(statement, coordinate);
10937
- cursor = coordinate.top + coordinate.height + metrics.statementMarginY;
10938
- });
10939
- return cursor;
10940
- }
10941
- }
10942
-
10943
- class VerticalCoordinates {
10944
- statementMap = /* @__PURE__ */ new Map();
10945
- creationTops = /* @__PURE__ */ new Map();
10946
- totalHeight;
10947
- constructor(rootContext) {
10948
- const rootBlock = rootContext?.block?.() ?? rootContext;
10949
- const participants = OrderedParticipants(rootContext).map((p) => p.name);
10950
- const messages = AllMessages(rootContext);
10951
- const originParticipant = messages.length === 0 ? _STARTER_ : messages[0].from || _STARTER_;
10952
- const runtime = {
10953
- metrics: DEFAULT_LAYOUT_METRICS,
10954
- participants,
10955
- recordCoordinate: (statement, coordinate) => {
10956
- const key = createStatementKey(statement);
10957
- this.statementMap.set(key, coordinate);
10958
- },
10959
- updateCreationTop: (participant, top) => {
10960
- const paddingTop = top - 8;
10961
- this.creationTops.set(participant, paddingTop);
10962
- }
10963
- };
10964
- const rootBlockVM = new BlockVM(rootBlock, runtime);
10965
- this.totalHeight = rootBlockVM.layout(originParticipant, 56);
10966
- }
10967
- getCreationTop(participant) {
10968
- return this.creationTops.get(participant);
10969
- }
10970
- getStatementCoordinate(key) {
10971
- return this.statementMap.get(key);
10972
- }
10973
- getTotalHeight() {
10974
- return this.totalHeight;
10975
- }
10976
- }
10977
-
10978
- let dic = {};
10979
- let persistDic = {};
10980
- const getCache = (key) => {
10981
- if (key != null) {
10982
- const cacheValue = dic[key] ?? persistDic[key];
10983
- return cacheValue !== void 0 ? cacheValue : null;
10984
- }
10985
- return null;
10986
- };
10987
- const setCache = (key, value, persist = false) => {
10988
- dic[key] = value;
10989
- if (persist) {
10990
- persistDic[key] = value;
10991
- }
10992
- };
10993
- const clearPersistentCache = () => {
10994
- persistDic = {};
10995
- dic = {};
10996
- };
10997
-
10998
- const IBM_PLEX_SANS_FAMILY = "IBM Plex Sans";
10999
- const DIAGRAM_FONT_STACK = `"${IBM_PLEX_SANS_FAMILY}", Helvetica, Verdana, serif`;
11000
- const IBM_PLEX_SANS_400_WOFF2_BASE64 = "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";
11001
- const IBM_PLEX_SANS_400_DATA_URI = `data:font/woff2;base64,${IBM_PLEX_SANS_400_WOFF2_BASE64}`;
11002
- const IBM_PLEX_SANS_FONT_FACE_CSS = `@font-face { font-family: "${IBM_PLEX_SANS_FAMILY}"; font-weight: 400; font-style: normal; src: url(${IBM_PLEX_SANS_400_DATA_URI}) format("woff2"); }`;
11003
-
11004
- const FONT_FAMILY = DIAGRAM_FONT_STACK;
11005
- const FONT_SIZE_PARTICIPANT = "14px";
11006
- const FONT_SIZE_MESSAGE = "15px";
11007
- const FONT_SIZE_FRAGMENT = "14px";
11008
- function getFontSize(type) {
11009
- return type === TextType.MessageContent ? FONT_SIZE_MESSAGE : FONT_SIZE_PARTICIPANT;
11010
- }
11011
- function getFontSpec(type) {
11012
- return `${getFontSize(type)} ${FONT_FAMILY}`;
11013
- }
11014
- let canvasCtx = null;
11015
- function setCanvasContext(ctx) {
11016
- if (ctx === canvasCtx) return;
11017
- canvasCtx = ctx;
11018
- clearPersistentCache();
11019
- }
11020
- function getCanvasContext() {
11021
- if (canvasCtx) return canvasCtx;
11022
- try {
11023
- if (typeof OffscreenCanvas !== "undefined") {
11024
- canvasCtx = new OffscreenCanvas(1, 1).getContext("2d");
11025
- } else if (typeof document !== "undefined") {
11026
- canvasCtx = document.createElement("canvas").getContext("2d");
11313
+ return new ReturnStatementVM(statement, runtime);
11314
+ }
11315
+ if (statement.divider?.()) {
11316
+ return new DividerStatementVM(statement, runtime);
11317
+ }
11318
+ const fragment = fragmentOf(statement);
11319
+ if (fragment) {
11320
+ switch (fragment.kind) {
11321
+ case "tcf":
11322
+ return new FragmentTryCatchVM(statement, fragment.context, runtime);
11323
+ case "alt":
11324
+ return new FragmentAltVM(statement, fragment.context, runtime);
11325
+ case "ref":
11326
+ return new FragmentRefVM(statement, runtime);
11327
+ default:
11328
+ return new FragmentSingleBlockVM(
11329
+ statement,
11330
+ fragment.context,
11331
+ runtime,
11332
+ fragment.kind
11333
+ );
11027
11334
  }
11028
- } catch {
11029
11335
  }
11030
- return canvasCtx;
11031
- }
11032
- function WidthProviderOnCanvas(text, type) {
11033
- const measured = text.trim();
11034
- const cacheKey = `WidthProviderOnCanvas_${getFontSpec(type)}_${measured}_${type}`;
11035
- const cacheValue = getCache(cacheKey);
11036
- if (cacheValue != null) {
11037
- return cacheValue;
11336
+ return new EmptyStatementVM(statement, runtime);
11337
+ };
11338
+
11339
+ class BlockVM extends NodeVM {
11340
+ statements;
11341
+ constructor(context, runtime) {
11342
+ super(context, runtime);
11343
+ this.statements = context?.stat?.() || [];
11038
11344
  }
11039
- const ctx = getCanvasContext();
11040
- if (!ctx) {
11041
- const width2 = Math.ceil(
11042
- measured.length * Number.parseFloat(getFontSize(type)) * 0.6
11043
- );
11044
- setCache(cacheKey, width2);
11045
- return width2;
11345
+ layout(originParticipant, startTop, parentKind) {
11346
+ if (!this.statements.length) return startTop;
11347
+ const metrics = this.runtime.metrics;
11348
+ let cursor = startTop + metrics.statementMarginY;
11349
+ this.statements.forEach((statement, index) => {
11350
+ if (parentKind === "par" && index !== 0) cursor += 1;
11351
+ const statementVM = createStatementVM(statement, this.runtime);
11352
+ const coordinate = statementVM.measure(cursor, originParticipant);
11353
+ this.runtime.recordCoordinate(statement, coordinate);
11354
+ cursor = coordinate.top + coordinate.height + metrics.statementMarginY;
11355
+ });
11356
+ return cursor;
11046
11357
  }
11047
- ctx.font = getFontSpec(type);
11048
- ctx.fontVariantCaps = "normal";
11049
- const width = Math.round(ctx.measureText(measured).width);
11050
- setCache(cacheKey, width, true);
11051
- return width;
11052
- }
11053
- const EMOJI_PATTERN = (
11054
- // eslint-disable-next-line no-misleading-character-class
11055
- /[\u{1F300}-\u{1FAFF}\u{2600}-\u{27BF}\u{FE00}-\u{FE0F}\u{200D}]/u
11056
- );
11057
- function measureWithSvg(text, fontSize, caps = "normal") {
11058
- if (typeof document === "undefined") return null;
11059
- const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
11060
- svg.setAttribute("style", "position:absolute;left:-9999px;top:-9999px");
11061
- const textEl = document.createElementNS("http://www.w3.org/2000/svg", "text");
11062
- textEl.setAttribute("font-family", FONT_FAMILY);
11063
- textEl.setAttribute("font-size", fontSize);
11064
- textEl.style.fontVariantCaps = caps;
11065
- if (typeof textEl.getBBox !== "function") return null;
11066
- textEl.textContent = text;
11067
- svg.appendChild(textEl);
11068
- document.body.appendChild(svg);
11069
- const width = textEl.getBBox().width;
11070
- document.body.removeChild(svg);
11071
- return Number.isFinite(width) && width > 0 ? width : null;
11072
11358
  }
11073
- function measureTextWithFont(text, fontSize, caps = "normal") {
11074
- const measured = text.trim();
11075
- if (!measured) return 0;
11076
- const hasEmoji = EMOJI_PATTERN.test(measured);
11077
- const font = `${fontSize} ${FONT_FAMILY}`;
11078
- const cacheKey = (hasEmoji ? `measureTextWithFont_svg_${font}_${measured}` : `measureTextWithFont_${font}_${measured}`) + `_${caps}`;
11079
- const cacheValue = getCache(cacheKey);
11080
- if (cacheValue != null) {
11081
- return cacheValue;
11359
+
11360
+ class VerticalCoordinates {
11361
+ statementMap = /* @__PURE__ */ new Map();
11362
+ creationTops = /* @__PURE__ */ new Map();
11363
+ totalHeight;
11364
+ constructor(rootContext) {
11365
+ const rootBlock = rootContext?.block?.() ?? rootContext;
11366
+ const participants = OrderedParticipants(rootContext).map((p) => p.name);
11367
+ const messages = AllMessages(rootContext);
11368
+ const originParticipant = messages.length === 0 ? _STARTER_ : messages[0].from || _STARTER_;
11369
+ const runtime = {
11370
+ metrics: DEFAULT_LAYOUT_METRICS,
11371
+ participants,
11372
+ recordCoordinate: (statement, coordinate) => {
11373
+ const key = createStatementKey(statement);
11374
+ this.statementMap.set(key, coordinate);
11375
+ },
11376
+ updateCreationTop: (participant, top) => {
11377
+ const paddingTop = top - 8;
11378
+ this.creationTops.set(participant, paddingTop);
11379
+ }
11380
+ };
11381
+ const rootBlockVM = new BlockVM(rootBlock, runtime);
11382
+ this.totalHeight = rootBlockVM.layout(originParticipant, 56);
11082
11383
  }
11083
- if (hasEmoji || caps !== "normal") {
11084
- const svgWidth = measureWithSvg(measured, fontSize, caps);
11085
- if (svgWidth != null) {
11086
- setCache(cacheKey, svgWidth, true);
11087
- return svgWidth;
11088
- }
11384
+ getCreationTop(participant) {
11385
+ return this.creationTops.get(participant);
11089
11386
  }
11090
- const ctx = getCanvasContext();
11091
- if (!ctx) {
11092
- const px = Number.parseFloat(fontSize) || 14;
11093
- const width2 = Math.ceil(measured.length * px * 0.6);
11094
- setCache(cacheKey, width2);
11095
- return width2;
11387
+ getStatementCoordinate(key) {
11388
+ return this.statementMap.get(key);
11096
11389
  }
11097
- ctx.font = font;
11098
- ctx.fontVariantCaps = "normal";
11099
- const normalWidth = ctx.measureText(measured).width;
11100
- let width = normalWidth;
11101
- if (caps !== "normal") {
11102
- const normalProbe = ctx.measureText("iiii").width;
11103
- ctx.fontVariantCaps = caps;
11104
- width = Math.abs(ctx.measureText("iiii").width - normalProbe) > 0.01 ? ctx.measureText(measured).width : Math.max(normalWidth, ctx.measureText(measured.toUpperCase()).width);
11105
- ctx.fontVariantCaps = "normal";
11390
+ getTotalHeight() {
11391
+ return this.totalHeight;
11106
11392
  }
11107
- setCache(cacheKey, width, true);
11108
- return width;
11109
- }
11110
- function measureSvgFragmentLabelWidth(text) {
11111
- return measureTextWithFont(text, FONT_SIZE_FRAGMENT);
11112
- }
11113
- function measureSvgParticipantLabelWidth(text) {
11114
- return measureTextWithFont(text, FONT_SIZE_PARTICIPANT);
11115
11393
  }
11116
11394
 
11117
11395
  const fragmentGuardKeyword = (kind, sourceKeyword) => kind === "alt" || kind === "opt" ? "if" : kind === "loop" ? sourceKeyword ?? "loop" : void 0;
@@ -11376,7 +11654,7 @@ function buildLifelines(participants, diagramHeight) {
11376
11654
  }
11377
11655
  function collectGroupSpecs(head) {
11378
11656
  return (head?.children ?? []).filter((c) => c instanceof GroupContext).map((g) => ({
11379
- // getFormattedText is installed on every context in src/parser/index.js
11657
+ // getFormattedText is installed on every context in src/parser/index.ts
11380
11658
  name: g.name()?.getFormattedText() ?? "",
11381
11659
  participantNames: Participants(g).Array().map((e) => e.name)
11382
11660
  }));
@@ -11591,17 +11869,7 @@ function buildFragmentGeometry(info, coord, coordinates, verticalCoordinates, al
11591
11869
  };
11592
11870
  }
11593
11871
  function findFragmentContext(stat) {
11594
- for (const kind of SINGLE_BLOCK_FRAGMENT_KINDS) {
11595
- const frag = stat[kind]?.();
11596
- if (frag) return frag;
11597
- }
11598
- const alt = stat.alt?.();
11599
- if (alt) return alt;
11600
- const tcf = stat.tcf?.();
11601
- if (tcf) return tcf;
11602
- const ref = stat.ref?.();
11603
- if (ref) return ref;
11604
- return null;
11872
+ return fragmentOf(stat)?.context ?? null;
11605
11873
  }
11606
11874
  function getDeepParticipantNames(fragmentCtx, sections) {
11607
11875
  const names = new Set(getLocalParticipantNames(fragmentCtx));
@@ -11811,86 +12079,60 @@ function walkBlock(block, currentOrigin, activeOccurrences, parentNumber, depth,
11811
12079
  return results;
11812
12080
  }
11813
12081
  function extractFragmentInfo(stat) {
11814
- for (const kind of SINGLE_BLOCK_FRAGMENT_KINDS) {
11815
- const frag = stat[kind]?.();
11816
- if (frag) {
11817
- const condition = frag.parExpr?.()?.condition?.();
11818
- const label = condition?.getFormattedText?.() || "";
12082
+ const view = fragmentOf(stat);
12083
+ if (!view) return null;
12084
+ switch (view.kind) {
12085
+ case "ref":
11819
12086
  return {
11820
- fragmentKind: kind,
11821
- headerLabel: frag.atom?.()?.getFormattedText?.(),
11822
- label,
11823
- guardKeyword: kind === "loop" ? frag.WHILE?.()?.getText?.() : void 0,
11824
- sections: [{ label, blockNode: frag.braceBlock?.()?.block?.() }]
12087
+ fragmentKind: "ref",
12088
+ label: view.context.getFormattedText?.() || "",
12089
+ sections: []
11825
12090
  };
11826
- }
11827
- }
11828
- const alt = stat.alt?.();
11829
- if (alt) {
11830
- const sections = [];
11831
- const ifBlock = alt.ifBlock?.();
11832
- if (ifBlock) {
11833
- sections.push({
11834
- label: "Alt",
11835
- guardKeyword: "if",
11836
- condition: ifBlock.parExpr?.()?.condition?.()?.getFormattedText?.() || "",
11837
- blockNode: ifBlock.braceBlock?.()?.block?.()
11838
- });
11839
- }
11840
- for (const elseIf of alt.elseIfBlock?.() || []) {
11841
- const condition = elseIf.parExpr?.()?.condition?.();
11842
- const label = condition?.getFormattedText?.() || "";
11843
- sections.push({
11844
- label: `else if ${label}`,
11845
- guardKeyword: "else if",
11846
- condition: label,
11847
- blockNode: elseIf.braceBlock?.()?.block?.()
11848
- });
11849
- }
11850
- const elseBlock = alt.elseBlock?.();
11851
- if (elseBlock) {
11852
- sections.push({
11853
- label: "else",
11854
- guardKeyword: "else",
11855
- blockNode: elseBlock.braceBlock?.()?.block?.()
11856
- });
11857
- }
11858
- const ifCondition = alt.ifBlock?.()?.parExpr?.()?.condition?.();
11859
- const firstLabel = ifCondition?.getFormattedText?.() || "";
11860
- return { fragmentKind: "alt", label: firstLabel, sections };
11861
- }
11862
- const tcf = stat.tcf?.();
11863
- if (tcf) {
11864
- const sections = [];
11865
- const tryBlock = tcf.tryBlock?.();
11866
- if (tryBlock) {
11867
- sections.push({
11868
- label: "Try",
11869
- blockNode: tryBlock.braceBlock?.()?.block?.()
11870
- });
11871
- }
11872
- for (const catchBlock of tcf.catchBlock?.() || []) {
11873
- const exception = catchBlock.invocation?.()?.parameters?.()?.getFormattedText?.() || "";
11874
- sections.push({
11875
- label: `catch ${exception}`,
11876
- blockNode: catchBlock.braceBlock?.()?.block?.()
12091
+ case "alt": {
12092
+ const sections = view.sections.map((s) => {
12093
+ if (s.guardKeyword === "if") {
12094
+ return {
12095
+ label: "Alt",
12096
+ guardKeyword: "if",
12097
+ condition: s.condition,
12098
+ blockNode: s.block
12099
+ };
12100
+ }
12101
+ if (s.guardKeyword === "else") {
12102
+ return { label: "else", guardKeyword: "else", blockNode: s.block };
12103
+ }
12104
+ return {
12105
+ label: `else if ${s.condition}`,
12106
+ guardKeyword: "else if",
12107
+ condition: s.condition,
12108
+ blockNode: s.block
12109
+ };
11877
12110
  });
12111
+ const [first] = view.sections;
12112
+ const firstLabel = first?.guardKeyword === "if" ? first.condition ?? "" : "";
12113
+ return { fragmentKind: "alt", label: firstLabel, sections };
12114
+ }
12115
+ case "tcf": {
12116
+ const sections = view.sections.map(
12117
+ (s) => ({
12118
+ label: s.guardKeyword === "try" ? "Try" : s.guardKeyword === "catch" ? `catch ${s.condition}` : "finally",
12119
+ blockNode: s.block
12120
+ })
12121
+ );
12122
+ return { fragmentKind: "tcf", label: "", sections };
11878
12123
  }
11879
- const finallyBlock = tcf.finallyBlock?.();
11880
- if (finallyBlock) {
11881
- sections.push({
11882
- label: "finally",
11883
- blockNode: finallyBlock.braceBlock?.()?.block?.()
11884
- });
12124
+ default: {
12125
+ const [section] = view.sections;
12126
+ const label = section.condition ?? "";
12127
+ return {
12128
+ fragmentKind: view.kind,
12129
+ headerLabel: view.context.atom?.()?.getFormattedText?.(),
12130
+ label,
12131
+ guardKeyword: section.guardKeyword,
12132
+ sections: [{ label, blockNode: section.block }]
12133
+ };
11885
12134
  }
11886
- return { fragmentKind: "tcf", label: "", sections };
11887
- }
11888
- const ref = stat.ref?.();
11889
- if (ref) {
11890
- const label = ref.getFormattedText?.() || "";
11891
- return { fragmentKind: "ref", label, sections: [] };
11892
12135
  }
11893
- return null;
11894
12136
  }
11895
12137
  function blockLength(block) {
11896
12138
  return (block?.stat?.() || []).filter(
@@ -11898,138 +12140,26 @@ function blockLength(block) {
11898
12140
  ).length;
11899
12141
  }
11900
12142
  function walkFragmentBlocks(stat, origin, results, activeOccurrences, parentNumber, depth) {
11901
- for (const kind of SINGLE_BLOCK_FRAGMENT_KINDS) {
11902
- const frag = stat[kind]?.();
11903
- if (frag) {
11904
- const block = frag.braceBlock?.()?.block?.();
11905
- if (block)
11906
- results.push(
11907
- ...walkBlock(
11908
- block,
11909
- origin,
11910
- activeOccurrences,
11911
- parentNumber,
11912
- depth + 1,
11913
- null,
11914
- 0
11915
- )
11916
- );
11917
- return;
11918
- }
11919
- }
11920
- const alt = stat.alt?.();
11921
- if (alt) {
11922
- const ifBlock = alt.ifBlock?.();
11923
- let sectionOffset = 0;
11924
- if (ifBlock) {
11925
- const block = ifBlock.braceBlock?.()?.block?.();
11926
- if (block) {
11927
- results.push(
11928
- ...walkBlock(
11929
- block,
11930
- origin,
11931
- activeOccurrences,
11932
- parentNumber,
11933
- depth + 1,
11934
- null,
11935
- sectionOffset
11936
- )
11937
- );
11938
- sectionOffset += blockLength(block);
11939
- }
11940
- }
11941
- for (const elseIf of alt.elseIfBlock?.() || []) {
11942
- const block = elseIf.braceBlock?.()?.block?.();
11943
- if (block) {
11944
- const sectionStmts = walkBlock(
11945
- block,
11946
- origin,
11947
- activeOccurrences,
11948
- parentNumber,
11949
- depth + 1,
11950
- null,
11951
- sectionOffset
11952
- );
11953
- if (sectionStmts.length > 0) sectionStmts[0].sectionReset = true;
11954
- results.push(...sectionStmts);
11955
- sectionOffset += blockLength(block);
11956
- }
11957
- }
11958
- const elseBlock = alt.elseBlock?.();
11959
- if (elseBlock) {
11960
- const block = elseBlock.braceBlock?.()?.block?.();
11961
- if (block) {
11962
- const sectionStmts = walkBlock(
11963
- block,
11964
- origin,
11965
- activeOccurrences,
11966
- parentNumber,
11967
- depth + 1,
11968
- null,
11969
- sectionOffset
11970
- );
11971
- if (sectionStmts.length > 0) sectionStmts[0].sectionReset = true;
11972
- results.push(...sectionStmts);
11973
- }
11974
- }
11975
- return;
11976
- }
11977
- const tcf = stat.tcf?.();
11978
- if (tcf) {
11979
- const tryBlock = tcf.tryBlock?.();
11980
- let sectionOffset = 0;
11981
- if (tryBlock) {
11982
- const block = tryBlock.braceBlock?.()?.block?.();
11983
- if (block) {
11984
- results.push(
11985
- ...walkBlock(
11986
- block,
11987
- origin,
11988
- activeOccurrences,
11989
- parentNumber,
11990
- depth + 1,
11991
- null,
11992
- sectionOffset
11993
- )
11994
- );
11995
- sectionOffset += blockLength(block);
11996
- }
11997
- }
11998
- for (const catchBlock of tcf.catchBlock?.() || []) {
11999
- const block = catchBlock.braceBlock?.()?.block?.();
12000
- if (block) {
12001
- const sectionStmts = walkBlock(
12002
- block,
12003
- origin,
12004
- activeOccurrences,
12005
- parentNumber,
12006
- depth + 1,
12007
- null,
12008
- sectionOffset
12009
- );
12010
- if (sectionStmts.length > 0) sectionStmts[0].sectionReset = true;
12011
- results.push(...sectionStmts);
12012
- sectionOffset += blockLength(block);
12013
- }
12014
- }
12015
- const finallyBlock = tcf.finallyBlock?.();
12016
- if (finallyBlock) {
12017
- const block = finallyBlock.braceBlock?.()?.block?.();
12018
- if (block) {
12019
- const sectionStmts = walkBlock(
12020
- block,
12021
- origin,
12022
- activeOccurrences,
12023
- parentNumber,
12024
- depth + 1,
12025
- null,
12026
- sectionOffset
12027
- );
12028
- if (sectionStmts.length > 0) sectionStmts[0].sectionReset = true;
12029
- results.push(...sectionStmts);
12030
- }
12143
+ const view = fragmentOf(stat);
12144
+ if (!view) return;
12145
+ let sectionOffset = 0;
12146
+ for (const section of view.sections) {
12147
+ const block = section.block;
12148
+ if (!block) continue;
12149
+ const sectionStmts = walkBlock(
12150
+ block,
12151
+ origin,
12152
+ activeOccurrences,
12153
+ parentNumber,
12154
+ depth + 1,
12155
+ null,
12156
+ sectionOffset
12157
+ );
12158
+ if (!section.isLeading && sectionStmts.length > 0) {
12159
+ sectionStmts[0].sectionReset = true;
12031
12160
  }
12032
- return;
12161
+ results.push(...sectionStmts);
12162
+ sectionOffset += blockLength(block);
12033
12163
  }
12034
12164
  }
12035
12165
 
@@ -12638,43 +12768,43 @@ function buildGeometry(input) {
12638
12768
  const ActorSvg = "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <g>\n <path d=\"M15.5489 4.19771C15.5489 5.18773 15.1485 6.13721 14.4358 6.83726C13.7231 7.53731 12.7565 7.93058 11.7486 7.93058C10.7407 7.93058 9.77403 7.53731 9.06133 6.83726C8.34863 6.13721 7.94824 5.18773 7.94824 4.19771C7.94824 3.20768 8.34863 2.25822 9.06133 1.55818C9.77403 0.858126 10.7407 0.464844 11.7486 0.464844C12.7565 0.464844 13.7231 0.858126 14.4358 1.55818C15.1485 2.25822 15.5489 3.20768 15.5489 4.19771Z\" stroke=\"currentColor\"/>\n <path d=\"M6.54883 11.2152L17.2025 11.2073M11.7471 8.06641V19.5806V8.06641ZM11.7471 19.4385L6.79789 23.5738L11.7471 19.4385ZM11.7551 19.4385L17.1864 23.3055L11.7551 19.4385Z\" stroke=\"currentColor\"/>\n </g>\n</svg>\n";
12639
12769
 
12640
12770
  const actor = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
12641
- __proto__: null,
12642
- default: ActorSvg
12771
+ __proto__: null,
12772
+ default: ActorSvg
12643
12773
  }, Symbol.toStringTag, { value: 'Module' }));
12644
12774
 
12645
12775
  const BoundarySvg = "<svg width=\"101\" height=\"78\" viewBox=\"0 0 101 78\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n\t<path d=\"M96.3563 39.4479C96.3563 48.4904 92.6755 57.1625 86.1237 63.5566C79.5718 69.9506 70.6856 73.5427 61.4199 73.5427C52.1541 73.5427 43.2679 69.9506 36.7161 63.5566C30.1642 57.1625 26.4834 48.4904 26.4834 39.4479C26.4834 30.147 30.1642 21.2271 36.7161 14.6504C43.2679 8.07366 52.1541 4.37891 61.4199 4.37891C70.6856 4.37891 79.5718 8.07366 86.1237 14.6504C92.6755 21.2271 96.3563 30.147 96.3563 39.4479V39.4479Z\" stroke=\"currentColor\" stroke-width=\"4.2083\"/>\n\t<path d=\"M27.3611 39.4482H3.93945\" stroke=\"currentColor\" stroke-width=\"4.2083\"/>\n\t<path d=\"M4.91504 4.37891V74.5168\" stroke=\"currentColor\" stroke-width=\"4.2083\"/>\n</svg>\n";
12646
12776
 
12647
12777
  const Robustness_Diagram_Boundary = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
12648
- __proto__: null,
12649
- default: BoundarySvg
12778
+ __proto__: null,
12779
+ default: BoundarySvg
12650
12780
  }, Symbol.toStringTag, { value: 'Module' }));
12651
12781
 
12652
12782
  const ControlSvg = "<svg width=\"77\" height=\"86\" viewBox=\"0 0 77 86\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n\t<g>\n\t\t<path d=\"M74.0149 46.8888C74.0149 51.5755 73.0918 56.2163 71.2983 60.5463C69.5048 64.8762 66.876 68.8105 63.562 72.1245C60.248 75.4385 56.3137 78.0673 51.9838 79.8608C47.6538 81.6543 43.013 82.5774 38.3263 82.5774C33.6396 82.5774 28.9988 81.6543 24.6689 79.8608C20.3389 78.0673 16.4046 75.4385 13.0907 72.1245C9.77666 68.8105 7.14785 64.8762 5.35433 60.5463C3.56081 56.2163 2.6377 51.5755 2.6377 46.8888C2.6377 42.2021 3.56081 37.5613 5.35433 33.2314C7.14785 28.9014 9.77666 24.9671 13.0907 21.6532C16.4046 18.3392 20.3389 15.7104 24.6689 13.9168C28.9988 12.1233 33.6396 11.2002 38.3263 11.2002C43.013 11.2002 47.6538 12.1233 51.9838 13.9168C56.3137 15.7104 60.248 18.3392 63.562 21.6532C66.876 24.9671 69.5048 28.9014 71.2983 33.2314C73.0918 37.5613 74.0149 42.2021 74.0149 46.8888V46.8888Z\" stroke=\"currentColor\" stroke-width=\"3.5833\"/>\n\t\t<path d=\"M47.5352 2.30371L37.5352 11.5001L47.5352 20.6966\" stroke=\"currentColor\" stroke-width=\"3.5833\"/>\n\t</g>\n</svg>\n";
12653
12783
 
12654
12784
  const Robustness_Diagram_Control = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
12655
- __proto__: null,
12656
- default: ControlSvg
12785
+ __proto__: null,
12786
+ default: ControlSvg
12657
12787
  }, Symbol.toStringTag, { value: 'Module' }));
12658
12788
 
12659
12789
  const DatabaseSvg = "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <ellipse cx=\"12\" cy=\"4.5\" rx=\"9.75\" ry=\"2.75\" stroke=\"currentColor\" stroke-width=\"1\"/>\n <path d=\"M2.25 4.5v15a9.75 2.75 0 0 0 19.5 0v-15\" stroke=\"currentColor\" stroke-width=\"1\"/>\n <path d=\"M2.25 9.5a9.75 2.75 0 0 0 19.5 0\" stroke=\"currentColor\" stroke-width=\"1\"/>\n <path d=\"M2.25 14.5a9.75 2.75 0 0 0 19.5 0\" stroke=\"currentColor\" stroke-width=\"1\"/>\n</svg>\n";
12660
12790
 
12661
12791
  const database = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
12662
- __proto__: null,
12663
- default: DatabaseSvg
12792
+ __proto__: null,
12793
+ default: DatabaseSvg
12664
12794
  }, Symbol.toStringTag, { value: 'Module' }));
12665
12795
 
12666
12796
  const QueueSvg = "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4.75 6.25h14.5M4.75 17.75h14.5\" stroke=\"currentColor\" stroke-width=\"1\"/>\n <path d=\"M4.75 6.25a2.5 5.75 0 0 0 0 11.5\" stroke=\"currentColor\" stroke-width=\"1\"/>\n <ellipse cx=\"19.25\" cy=\"12\" rx=\"2.5\" ry=\"5.75\" stroke=\"currentColor\" stroke-width=\"1\"/>\n</svg>\n";
12667
12797
 
12668
12798
  const queue = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
12669
- __proto__: null,
12670
- default: QueueSvg
12799
+ __proto__: null,
12800
+ default: QueueSvg
12671
12801
  }, Symbol.toStringTag, { value: 'Module' }));
12672
12802
 
12673
12803
  const EntitySvg = "<svg width=\"77\" height=\"80\" viewBox=\"0 0 77 80\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n\t<g>\n\t\t<path d=\"M74.0149 38.8888C74.0149 43.5755 73.0918 48.2163 71.2983 52.5463C69.5048 56.8762 66.876 60.8105 63.562 64.1245C60.248 67.4385 56.3137 70.0673 51.9838 71.8608C47.6538 73.6543 43.013 74.5774 38.3263 74.5774C33.6396 74.5774 28.9988 73.6543 24.6689 71.8608C20.3389 70.0673 16.4046 67.4385 13.0907 64.1245C9.77666 60.8105 7.14785 56.8762 5.35433 52.5463C3.56081 48.2163 2.6377 43.5755 2.6377 38.8888C2.6377 34.2021 3.56081 29.5613 5.35433 25.2314C7.14785 20.9014 9.77666 16.9671 13.0907 13.6532C16.4046 10.3392 20.3389 7.71035 24.6689 5.91683C28.9988 4.12331 33.6396 3.2002 38.3263 3.2002C43.013 3.2002 47.6538 4.12331 51.9838 5.91683C56.3137 7.71035 60.248 10.3392 63.562 13.6532C66.876 16.9671 69.5048 20.9014 71.2983 25.2314C73.0918 29.5613 74.0149 34.2021 74.0149 38.8888V38.8888Z\" stroke=\"currentColor\" stroke-width=\"3.3333\"/>\n\t\t<path d=\"M2.69922 75.4727L75.6992 75.5154\" stroke=\"currentColor\" stroke-width=\"3.3333\"/>\n\t</g>\n</svg>\n";
12674
12804
 
12675
12805
  const Robustness_Diagram_Entity = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
12676
- __proto__: null,
12677
- default: EntitySvg
12806
+ __proto__: null,
12807
+ default: EntitySvg
12678
12808
  }, Symbol.toStringTag, { value: 'Module' }));
12679
12809
 
12680
12810
  const icon_374 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<svg width=\"48px\" height=\"48px\" viewBox=\"0 0 48 48\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n <title>Icon-Resource/Compute/Res_Amazon-EC2_Instance_48</title>\n <g id=\"Icon-Resource/Compute/Res_Amazon-EC2_Instance_48\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n <path d=\"M9,39 L39,39 L39,9 L9,9 L9,39 Z M46,13 L46,11 L41,11 L41,8 C41,7.448 40.552,7 40,7 L37,7 L37,2 L35,2 L35,7 L31,7 L31,2 L29,2 L29,7 L25,7 L25,2 L23,2 L23,7 L19,7 L19,2 L17,2 L17,7 L13,7 L13,2 L11,2 L11,7 L8,7 C7.447,7 7,7.448 7,8 L7,11 L2,11 L2,13 L7,13 L7,17 L2,17 L2,19 L7,19 L7,23 L2,23 L2,25 L7,25 L7,29 L2,29 L2,31 L7,31 L7,35 L2,35 L2,37 L7,37 L7,40 C7,40.553 7.447,41 8,41 L11,41 L11,46 L13,46 L13,41 L17,41 L17,46 L19,46 L19,41 L23,41 L23,46 L25,46 L25,41 L29,41 L29,46 L31,46 L31,41 L35,41 L35,46 L37,46 L37,41 L40,41 C40.552,41 41,40.553 41,40 L41,37 L46,37 L46,35 L41,35 L41,31 L46,31 L46,29 L41,29 L41,25 L46,25 L46,23 L41,23 L41,19 L46,19 L46,17 L41,17 L41,13 L46,13 Z\" id=\"Amazon-EC2-Instance_Resource-Icon_light-bg\" fill=\"#ED7100\"></path>\n </g>\n</svg>\n";
@@ -12703,7 +12833,7 @@ const coreIcons = {
12703
12833
  sagemaker: () => import('./assets/Arch_Amazon-SageMaker_16-DrLi5pZN.mjs')
12704
12834
  };
12705
12835
  const loadCloudIcon = async (key) => {
12706
- const { cloudIcons } = await import('./assets/CloudIcons-De45wK6e.mjs');
12836
+ const { cloudIcons } = await import('./assets/CloudIcons-BXI_VQtG.mjs');
12707
12837
  return cloudIcons[key] ?? null;
12708
12838
  };
12709
12839
  const loadIcon = async (iconKey) => {
@@ -13273,7 +13403,7 @@ function renderDivider(d) {
13273
13403
  }
13274
13404
 
13275
13405
  function markdownToSvgLines(text) {
13276
- const tokens = marked.lexer(text, { gfm: true, breaks: true });
13406
+ const tokens = lexComment(text);
13277
13407
  return collectLines(tokens);
13278
13408
  }
13279
13409
  function collectLines(tokens) {
@@ -13313,10 +13443,14 @@ function collectLines(tokens) {
13313
13443
  pushFragment(esc(token.text));
13314
13444
  return;
13315
13445
  case "strong":
13316
- pushFragment(`<tspan font-weight="bold">${collectLines(token.tokens || []).join("")}</tspan>`);
13446
+ pushFragment(
13447
+ `<tspan font-weight="bold">${collectLines(token.tokens || []).join("")}</tspan>`
13448
+ );
13317
13449
  return;
13318
13450
  case "em":
13319
- pushFragment(`<tspan font-style="italic">${collectLines(token.tokens || []).join("")}</tspan>`);
13451
+ pushFragment(
13452
+ `<tspan font-style="italic">${collectLines(token.tokens || []).join("")}</tspan>`
13453
+ );
13320
13454
  return;
13321
13455
  case "text":
13322
13456
  if ("tokens" in token && token.tokens) {
@@ -13491,720 +13625,355 @@ const THEME_PALETTES = {
13491
13625
  // resolves every slot through tailwind.config.js and checks them.
13492
13626
  "theme-dark": DARK_PALETTE,
13493
13627
  "theme-clean-dark": DARK_PALETTE,
13494
- "theme-darcula": DARK_PALETTE,
13495
- // src/assets/tailwind.css `.theme-neon`. The DOM theme also swaps in the
13496
- // MS Sans Serif webfont (`.zenuml .theme-neon`); the SVG names it first and
13497
- // keeps the Helvetica stack behind it, since a consumer embedding the SVG
13498
- // will not have that @font-face rule.
13499
- "theme-neon": {
13500
- frameBorder: "#60ff33",
13501
- frameBg: "#000000",
13502
- titleText: "#8ffc5b",
13503
- participantBg: "#000000",
13504
- participantBorder: "#8ffc5b",
13505
- lifeline: "#60ff33",
13506
- participantText: "#8ffc5b",
13507
- messageArrow: "#8ffc5b",
13508
- messageText: "#8ffc5b",
13509
- occurrenceBg: "#8ffc5b",
13510
- occurrenceBorder: "#8ffc5b",
13511
- fragmentBorder: "#60ff33",
13512
- fragmentHeaderBg: "#000000",
13513
- fragmentHeaderOpacity: "1",
13514
- fragmentHeaderText: "#8ffc5b",
13515
- fragmentText: "#8ffc5b",
13516
- guardOpacity: "0.65",
13517
- // Neither slot is set by `.theme-neon`; the DOM shows the defaults.
13518
- fragmentSeparator: "#e5e7eb",
13519
- commentText: "#333",
13520
- commentOpacity: "0.5",
13521
- // Slots every DOM theme still renders with the theme-default literals
13522
- // (their CSS chains fall back to these values; only a theme that sets the
13523
- // slot changes them).
13524
- groupOutline: "#666",
13525
- dividerLine: "#aaaa33",
13526
- dividerBg: "#fff5ad",
13527
- dividerText: "#333",
13528
- numberText: "#6b7280",
13529
- fragmentNumberText: "#6b7280",
13530
- numberBg: "#6b7280",
13531
- numberBgOpacity: "0.1",
13532
- guardText: "#6b7280",
13533
- fontFamily: `"MS Sans Serif", ${DIAGRAM_FONT_STACK}`
13534
- }
13535
- };
13536
- function resolvePalette(theme) {
13537
- if (theme && theme in THEME_PALETTES) {
13538
- return THEME_PALETTES[theme];
13539
- }
13540
- return DEFAULT_PALETTE;
13541
- }
13542
- function buildThemeStyles(p) {
13543
- return `
13544
- ${IBM_PLEX_SANS_FONT_FACE_CSS}
13545
- .frame-border-outer { fill: ${p.frameBorder}; }
13546
- .frame-border-inner { fill: ${p.frameBg}; }
13547
- .frame-header-bg { fill: ${p.frameBg}; }
13548
- .frame-header-line { stroke: ${p.frameBorder}; stroke-width: 1; shape-rendering: crispEdges; }
13549
- .frame-title { font-family: ${p.fontFamily}; font-size: 14px; font-weight: 400; fill: ${p.titleText}; }
13550
- .participant-box { fill: ${p.participantBg}; stroke: ${p.participantBorder}; stroke-width: 1; }
13551
- .participant-label { font-family: ${p.fontFamily}; font-size: 14px; fill: ${p.participantText}; }
13552
- .stereotype-label { fill: ${p.participantText}; }
13553
- .participant-icon { color: ${p.participantText}; }
13554
- .lifeline { stroke: ${p.lifeline}; stroke-width: 1; }
13555
- .message-line { stroke: ${p.messageArrow}; stroke-width: 1; shape-rendering: crispEdges; }
13556
- .message-label { font-family: ${p.fontFamily}; font-size: 15px; fill: ${p.messageText}; }
13557
- .arrow-head { fill: ${p.messageArrow}; stroke: ${p.messageArrow}; stroke-width: 1; }
13558
- .arrow-open { fill: none; }
13559
- .self-call-line { stroke: ${p.messageArrow}; stroke-width: 1; fill: none; }
13560
- .occurrence { fill: ${p.occurrenceBg}; stroke: ${p.occurrenceBorder}; stroke-width: 1; shape-rendering: crispEdges; }
13561
- .fragment-border { fill: none; stroke: ${p.fragmentBorder}; stroke-width: 1; }
13562
- .fragment-header { fill: ${p.fragmentHeaderBg}; fill-opacity: ${p.fragmentHeaderOpacity}; stroke: none; shape-rendering: crispEdges; }
13563
- .fragment-number-bg { fill: ${p.numberBg}; fill-opacity: ${p.numberBgOpacity}; stroke: none; }
13564
- .message-number-bg { fill: ${p.numberBg}; fill-opacity: ${p.numberBgOpacity}; stroke: none; }
13565
- .fragment-label { font-family: ${p.fontFamily}; font-size: 14px; font-weight: 400; font-variant-caps: all-small-caps; fill: ${p.fragmentHeaderText}; }
13566
- .fragment-condition { font-family: ${p.fontFamily}; font-size: 14px; fill: ${p.fragmentText}; opacity: ${p.guardOpacity}; }
13567
- .fragment-section-dim { opacity: ${p.guardOpacity}; }
13568
- .fragment-section-bg { fill: ${p.frameBg}; }
13569
- .fragment-icon { color: ${p.fragmentHeaderText}; }
13570
- .fragment-separator { stroke: ${p.fragmentSeparator}; stroke-width: 1; shape-rendering: crispEdges; }
13571
- .fragment-section-keyword { font-variant-caps: all-small-caps; }
13572
- .fragment-section-label { font-family: ${p.fontFamily}; font-size: 14px; fill: ${p.fragmentText}; }
13573
- .return-line { stroke: ${p.messageArrow}; stroke-width: 1; stroke-dasharray: 6,4; shape-rendering: crispEdges; }
13574
- .return-arrow { stroke: ${p.messageArrow}; stroke-width: 1; fill: none; }
13575
- .return-label { font-family: ${p.fontFamily}; font-size: 15px; fill: ${p.messageText}; }
13576
- .return-icon { fill: ${p.messageText}; }
13577
- .divider-line { stroke: ${p.dividerLine}; stroke-width: 1; }
13578
- .divider-bg { fill: ${p.dividerBg}; stroke: ${p.dividerLine}; stroke-width: 1; }
13579
- .divider-label { font-family: ${p.fontFamily}; font-size: 14px; fill: ${p.dividerText}; }
13580
- .comment-text { font-family: ${p.fontFamily}; font-size: 14px; fill: ${p.commentText}; opacity: ${p.commentOpacity}; }
13581
- .guard-keyword { font-family: ${p.fontFamily}; font-size: 12px; font-weight: 400; font-variant-caps: all-small-caps; fill: ${p.guardText}; }
13582
- .seq-number { font-family: ${p.fontFamily}; font-size: 12px; font-weight: 400; fill: ${p.numberText}; }
13583
- .fragment-number { fill: ${p.fragmentNumberText}; }
13584
- .group-outline { fill: none; stroke: ${p.groupOutline}; }
13585
- .group-title-bg { fill: ${p.frameBg}; stroke: none; }
13586
- .group-title-text { font-family: ${p.fontFamily}; font-size: 13px; font-weight: 400; fill: ${p.participantText}; }
13587
- `;
13588
- }
13589
-
13590
- const PALETTE_CSS_VARS = {
13591
- canvasBg: "--color-bg-canvas",
13592
- frameBg: "--color-bg-frame",
13593
- frameBorder: "--color-border-frame",
13594
- titleText: "--color-text-title",
13595
- participantBg: "--color-bg-participant",
13596
- participantBorder: "--color-border-participant",
13597
- participantText: "--color-text-participant",
13598
- messageArrow: "--color-message-arrow",
13599
- messageText: "--color-text-message",
13600
- lifeline: "--color-border-base",
13601
- occurrenceBg: "--color-bg-occurrence",
13602
- occurrenceBorder: "--color-border-occurrence",
13603
- fragmentBorder: "--color-border-fragment",
13604
- fragmentHeaderBg: "--color-bg-fragment-header",
13605
- fragmentHeaderText: "--color-text-fragment-header",
13606
- fragmentText: "--color-text-fragment",
13607
- fragmentSeparator: "--color-border-fragment-separator",
13608
- guardOpacity: "--opacity-guard",
13609
- guardText: "--color-text-guard",
13610
- commentText: "--color-text-comment",
13611
- commentOpacity: "--opacity-comment",
13612
- groupOutline: "--color-border-group",
13613
- dividerLine: "--color-border-divider",
13614
- dividerBg: "--color-bg-divider",
13615
- dividerText: "--color-text-divider",
13616
- numberText: "--color-text-number",
13617
- fragmentNumberText: "--color-text-fragment-number",
13618
- numberBg: "--color-bg-number"
13619
- };
13620
- function safeSvgPalette(palette) {
13621
- if (!palette) return void 0;
13622
- const safe = {};
13623
- for (const [key, value] of Object.entries(palette)) {
13624
- if (!(key in PALETTE_CSS_VARS) || typeof value !== "string") continue;
13625
- if (key === "guardOpacity" || key === "commentOpacity") {
13626
- const opacity = Number(value);
13627
- if (Number.isFinite(opacity) && opacity >= 0 && opacity <= 1)
13628
- safe[key] = value;
13629
- } else if (/^[a-zA-Z0-9#(),.%/+\-\s]+$/.test(value) && !/\b(?:url|expression|var)\s*\(/i.test(value)) {
13630
- safe[key] = value;
13631
- }
13632
- }
13633
- return safe;
13634
- }
13635
- function normaliseBackingColor(color) {
13636
- const rgb = colorString.get.rgb(color);
13637
- if (!rgb || rgb[3] !== 1) {
13638
- throw new TypeError("backingColor must be an opaque CSS colour");
13639
- }
13640
- return `rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]})`;
13641
- }
13642
-
13643
- const FRAME_VIEWPORT_HEADER_ALLOWANCE = 28;
13644
- const FRAME_BORDER_RADIUS = 4;
13645
- function renderToSvg(code, options) {
13646
- const safeOptions = options ? { ...options, palette: safeSvgPalette(options.palette) } : void 0;
13647
- const surface = {
13648
- backgroundColor: safeOptions?.palette?.canvasBg ?? "transparent"
13649
- };
13650
- const rootContext = RootContext(code);
13651
- if (!rootContext) {
13652
- return {
13653
- svg: "<svg></svg>",
13654
- surface,
13655
- innerSvg: "",
13656
- width: 0,
13657
- height: 0,
13658
- viewBox: "0 0 0 0",
13659
- geometry: void 0
13660
- };
13661
- }
13662
- const coordinates = new Coordinates(rootContext, WidthProviderOnCanvas);
13663
- const verticalCoordinates = new VerticalCoordinates(rootContext);
13664
- const titleContext = rootContext.title?.();
13665
- const rawTitle = titleContext && typeof titleContext.content === "function" ? titleContext.content() : void 0;
13666
- const title = rawTitle ? resolveEmojiInText(rawTitle) : void 0;
13667
- const geometry = buildGeometry({
13668
- rootContext,
13669
- coordinates,
13670
- verticalCoordinates,
13671
- title,
13672
- measureText: WidthProviderOnCanvas,
13673
- enableNumbering: options?.enableNumbering
13674
- });
13675
- return { ...composeSvg(geometry, safeOptions), geometry };
13676
- }
13677
- function composeSvg(g, options) {
13678
- const surface = {
13679
- backgroundColor: options?.palette?.canvasBg ?? "transparent"
13680
- };
13681
- const padding = 10;
13682
- const headerH = FRAME_VIEWPORT_HEADER_ALLOWANCE;
13683
- let contentLeftMargin = 1 + padding + g.frameBorderLeft;
13684
- let numberLeft = 0;
13685
- for (const message of [
13686
- ...g.messages,
13687
- ...g.creations.map((creation) => creation.message)
13688
- ]) {
13689
- if (!message.number) continue;
13690
- numberLeft = Math.min(
13691
- numberLeft,
13692
- Math.min(message.fromX, message.toX) + 1 - 4 - messageNumberWidth(message.number)
13693
- );
13694
- }
13695
- for (const call of g.selfCalls) {
13696
- if (call.number)
13697
- numberLeft = Math.min(
13698
- numberLeft,
13699
- call.x - 3 - messageNumberWidth(call.number)
13700
- );
13701
- }
13702
- for (const returned of g.returns) {
13703
- if (returned.number && !returned.isSelf)
13704
- numberLeft = Math.min(
13705
- numberLeft,
13706
- Math.min(returned.fromX, returned.toX) - 4 - messageNumberWidth(returned.number)
13707
- );
13708
- }
13709
- contentLeftMargin += Math.max(0, padding - contentLeftMargin - numberLeft);
13710
- const viewWidth = g.width + contentLeftMargin + padding + g.frameBorderRight + 1;
13711
- const viewHeight = g.height + padding * 2 + headerH - 1;
13712
- const parts = [];
13713
- for (const grp of g.groups) {
13714
- parts.push(renderGroup(grp));
13715
- }
13716
- for (const l of g.lifelines) {
13717
- parts.push(renderLifeline(l));
13718
- }
13719
- const creationNames = new Set(g.creations.map((c) => c.participant.name));
13720
- for (const p of g.participants) {
13721
- if (!creationNames.has(p.name)) {
13722
- parts.push(renderParticipant(p));
13723
- }
13724
- }
13725
- for (const o of g.occurrences) {
13726
- parts.push(renderOccurrence(o));
13727
- }
13728
- for (const p of g.participants) {
13729
- if (creationNames.has(p.name)) {
13730
- parts.push(renderParticipant(p));
13731
- }
13732
- }
13733
- for (const m of g.messages) {
13734
- parts.push(renderMessage(m));
13735
- }
13736
- for (const s of g.selfCalls) {
13737
- parts.push(renderSelfCall(s));
13738
- }
13739
- for (const c of g.creations) {
13740
- parts.push(renderCreation(c));
13741
- }
13742
- for (const r2 of g.returns) {
13743
- parts.push(renderReturn(r2));
13744
- }
13745
- for (const f of g.fragments) {
13746
- parts.push(renderFragment(f));
13747
- }
13748
- for (const d of g.dividers) {
13749
- parts.push(renderDivider(d));
13628
+ "theme-darcula": DARK_PALETTE,
13629
+ // src/assets/tailwind.css `.theme-neon`. The DOM theme also swaps in the
13630
+ // MS Sans Serif webfont (`.zenuml .theme-neon`); the SVG names it first and
13631
+ // keeps the Helvetica stack behind it, since a consumer embedding the SVG
13632
+ // will not have that @font-face rule.
13633
+ "theme-neon": {
13634
+ frameBorder: "#60ff33",
13635
+ frameBg: "#000000",
13636
+ titleText: "#8ffc5b",
13637
+ participantBg: "#000000",
13638
+ participantBorder: "#8ffc5b",
13639
+ lifeline: "#60ff33",
13640
+ participantText: "#8ffc5b",
13641
+ messageArrow: "#8ffc5b",
13642
+ messageText: "#8ffc5b",
13643
+ occurrenceBg: "#8ffc5b",
13644
+ occurrenceBorder: "#8ffc5b",
13645
+ fragmentBorder: "#60ff33",
13646
+ fragmentHeaderBg: "#000000",
13647
+ fragmentHeaderOpacity: "1",
13648
+ fragmentHeaderText: "#8ffc5b",
13649
+ fragmentText: "#8ffc5b",
13650
+ guardOpacity: "0.65",
13651
+ // Neither slot is set by `.theme-neon`; the DOM shows the defaults.
13652
+ fragmentSeparator: "#e5e7eb",
13653
+ commentText: "#333",
13654
+ commentOpacity: "0.5",
13655
+ // Slots every DOM theme still renders with the theme-default literals
13656
+ // (their CSS chains fall back to these values; only a theme that sets the
13657
+ // slot changes them).
13658
+ groupOutline: "#666",
13659
+ dividerLine: "#aaaa33",
13660
+ dividerBg: "#fff5ad",
13661
+ dividerText: "#333",
13662
+ numberText: "#6b7280",
13663
+ fragmentNumberText: "#6b7280",
13664
+ numberBg: "#6b7280",
13665
+ numberBgOpacity: "0.1",
13666
+ guardText: "#6b7280",
13667
+ fontFamily: `"MS Sans Serif", ${DIAGRAM_FONT_STACK}`
13750
13668
  }
13751
- for (const c of g.comments) {
13752
- parts.push(renderComment(c));
13669
+ };
13670
+ function resolvePalette(theme) {
13671
+ if (theme && theme in THEME_PALETTES) {
13672
+ return THEME_PALETTES[theme];
13753
13673
  }
13754
- const r = FRAME_BORDER_RADIUS;
13755
- const frameSvg = [
13756
- `<rect class="frame-border-outer" x="0" y="0" width="${viewWidth}" height="${viewHeight}" rx="${r}" fill="#666"/>`,
13757
- `<rect class="frame-border-inner" x="1" y="1" width="${viewWidth - 2}" height="${viewHeight - 2}" rx="${Math.max(0, r - 1)}" fill="#fff"/>`
13758
- ].join("\n");
13759
- const headerLineY = 1 + DIAGRAM_HEADER_HEIGHT;
13760
- const headerLineDrawY = headerLineY - 0.5;
13761
- const headerLineSvg = `<line class="frame-header-line" x1="1" y1="${headerLineDrawY}" x2="${viewWidth - 1}" y2="${headerLineDrawY}"/>`;
13762
- const titleSvg = g.title ? `<text x="5" y="${headerLineDrawY / 2}" dominant-baseline="central" class="frame-title">${esc(g.title)}</text>` : "";
13763
- const viewBox = `0 0 ${viewWidth} ${viewHeight}`;
13764
- const defs = `<defs>
13765
- <style>${buildThemeStyles(resolveSvgPalette(options))}</style>
13766
- </defs>`;
13767
- const frame = `${frameSvg}
13768
- ${headerLineSvg}
13769
- ${titleSvg}`;
13770
- const content = `<g transform="translate(${contentLeftMargin}, ${headerLineY})">
13771
- ${parts.join("\n")}
13772
- </g>`;
13773
- const backing = options?.backingColor !== void 0 ? `<rect class="export-backing" x="0" y="0" width="${viewWidth}" height="${viewHeight}" style="fill: ${normaliseBackingColor(options.backingColor)} !important"/>` : "";
13774
- const background = surface.backgroundColor !== "transparent" ? `<rect class="canvas-background" x="0" y="0" width="${viewWidth}" height="${viewHeight}" fill="${surface.backgroundColor}"/>` : "";
13775
- const innerSvg = `${defs}
13776
- ${backing}
13777
- ${background}
13778
- ${frame}
13779
- ${content}`;
13780
- const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${viewWidth}" height="${viewHeight}" viewBox="${viewBox}">
13781
- ${innerSvg}
13782
- </svg>`;
13783
- return {
13784
- svg,
13785
- innerSvg,
13786
- width: viewWidth,
13787
- height: viewHeight,
13788
- viewBox,
13789
- surface
13790
- };
13791
- }
13792
- function resolveSvgPalette(options) {
13793
- const theme = resolvePalette(options?.theme);
13794
- const palette = options?.palette;
13795
- if (!palette) return theme;
13796
- return {
13797
- ...theme,
13798
- ...palette,
13799
- ...palette.fragmentHeaderBg ? { fragmentHeaderOpacity: "1" } : {},
13800
- ...palette.numberBg ? { numberBgOpacity: "1" } : {}
13801
- };
13674
+ return DEFAULT_PALETTE;
13802
13675
  }
13803
-
13804
- function readVersion() {
13805
- const pkgPath = resolve(import.meta.dir, "../../package.json");
13806
- try {
13807
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
13808
- return pkg.version ?? "unknown";
13809
- } catch {
13810
- return "unknown";
13811
- }
13676
+ function buildThemeStyles(p) {
13677
+ return `
13678
+ ${IBM_PLEX_SANS_FONT_FACE_CSS}
13679
+ .frame-border-outer { fill: ${p.frameBorder}; }
13680
+ .frame-border-inner { fill: ${p.frameBg}; }
13681
+ .frame-header-bg { fill: ${p.frameBg}; }
13682
+ .frame-header-line { stroke: ${p.frameBorder}; stroke-width: 1; shape-rendering: crispEdges; }
13683
+ .frame-title { font-family: ${p.fontFamily}; font-size: 14px; font-weight: 400; fill: ${p.titleText}; }
13684
+ .participant-box { fill: ${p.participantBg}; stroke: ${p.participantBorder}; stroke-width: 1; }
13685
+ .participant-label { font-family: ${p.fontFamily}; font-size: 14px; fill: ${p.participantText}; }
13686
+ .stereotype-label { fill: ${p.participantText}; }
13687
+ .participant-icon { color: ${p.participantText}; }
13688
+ .lifeline { stroke: ${p.lifeline}; stroke-width: 1; }
13689
+ .message-line { stroke: ${p.messageArrow}; stroke-width: 1; shape-rendering: crispEdges; }
13690
+ .message-label { font-family: ${p.fontFamily}; font-size: 15px; fill: ${p.messageText}; }
13691
+ .arrow-head { fill: ${p.messageArrow}; stroke: ${p.messageArrow}; stroke-width: 1; }
13692
+ .arrow-open { fill: none; }
13693
+ .self-call-line { stroke: ${p.messageArrow}; stroke-width: 1; fill: none; }
13694
+ .occurrence { fill: ${p.occurrenceBg}; stroke: ${p.occurrenceBorder}; stroke-width: 1; shape-rendering: crispEdges; }
13695
+ .fragment-border { fill: none; stroke: ${p.fragmentBorder}; stroke-width: 1; }
13696
+ .fragment-header { fill: ${p.fragmentHeaderBg}; fill-opacity: ${p.fragmentHeaderOpacity}; stroke: none; shape-rendering: crispEdges; }
13697
+ .fragment-number-bg { fill: ${p.numberBg}; fill-opacity: ${p.numberBgOpacity}; stroke: none; }
13698
+ .message-number-bg { fill: ${p.numberBg}; fill-opacity: ${p.numberBgOpacity}; stroke: none; }
13699
+ .fragment-label { font-family: ${p.fontFamily}; font-size: 14px; font-weight: 400; font-variant-caps: all-small-caps; fill: ${p.fragmentHeaderText}; }
13700
+ .fragment-condition { font-family: ${p.fontFamily}; font-size: 14px; fill: ${p.fragmentText}; opacity: ${p.guardOpacity}; }
13701
+ .fragment-section-dim { opacity: ${p.guardOpacity}; }
13702
+ .fragment-section-bg { fill: ${p.frameBg}; }
13703
+ .fragment-icon { color: ${p.fragmentHeaderText}; }
13704
+ .fragment-separator { stroke: ${p.fragmentSeparator}; stroke-width: 1; shape-rendering: crispEdges; }
13705
+ .fragment-section-keyword { font-variant-caps: all-small-caps; }
13706
+ .fragment-section-label { font-family: ${p.fontFamily}; font-size: 14px; fill: ${p.fragmentText}; }
13707
+ .return-line { stroke: ${p.messageArrow}; stroke-width: 1; stroke-dasharray: 6,4; shape-rendering: crispEdges; }
13708
+ .return-arrow { stroke: ${p.messageArrow}; stroke-width: 1; fill: none; }
13709
+ .return-label { font-family: ${p.fontFamily}; font-size: 15px; fill: ${p.messageText}; }
13710
+ .return-icon { fill: ${p.messageText}; }
13711
+ .divider-line { stroke: ${p.dividerLine}; stroke-width: 1; }
13712
+ .divider-bg { fill: ${p.dividerBg}; stroke: ${p.dividerLine}; stroke-width: 1; }
13713
+ .divider-label { font-family: ${p.fontFamily}; font-size: 14px; fill: ${p.dividerText}; }
13714
+ .comment-text { font-family: ${p.fontFamily}; font-size: 14px; fill: ${p.commentText}; opacity: ${p.commentOpacity}; }
13715
+ .guard-keyword { font-family: ${p.fontFamily}; font-size: 12px; font-weight: 400; font-variant-caps: all-small-caps; fill: ${p.guardText}; }
13716
+ .seq-number { font-family: ${p.fontFamily}; font-size: 12px; font-weight: 400; fill: ${p.numberText}; }
13717
+ .fragment-number { fill: ${p.fragmentNumberText}; }
13718
+ .group-outline { fill: none; stroke: ${p.groupOutline}; }
13719
+ .group-title-bg { fill: ${p.frameBg}; stroke: none; }
13720
+ .group-title-text { font-family: ${p.fontFamily}; font-size: 13px; font-weight: 400; fill: ${p.participantText}; }
13721
+ `;
13812
13722
  }
13813
- function printHelp() {
13814
- const help = `
13815
- Usage: zenuml [options]
13816
-
13817
- Render ZenUML DSL text to SVG or PNG.
13818
-
13819
- Rendering:
13820
- -i, --input <file> Input file (use "-" for stdin; repeatable)
13821
- -o, --output <file> Output file (use "-" for stdout; default: <input>.svg)
13822
- -e, --outputFormat <format> Output format: "svg" (default) or "png"
13823
- -s, --scale <factor> Pixel scale factor for PNG (default: 2; ignored for SVG)
13824
- -t, --theme <name> Theme: default, mermaid, clean-light, dark, neon
13825
- (clean-dark and darcula are aliases of dark;
13826
- prefix "theme-"; unknown names use default)
13827
- -c, --configFile <file> JSON config file with { theme, scale, outputFormat }
13828
- --md Markdown mode: render zenuml code blocks and produce output Markdown
13829
-
13830
- Validation:
13831
- --check Validate syntax without rendering (exit 0 if valid, 1 if errors)
13832
- --parse Parse input and output AST as JSON (exit 0 if valid, 1 if errors)
13833
- --json Machine-readable JSON output for --check mode
13834
-
13835
- Batch & Watch:
13836
- -w, --watch Watch input files and re-render on change (incompatible with --check, --parse, stdin)
13837
-
13838
- General:
13839
- -q, --quiet Suppress non-error output
13840
- -h, --help Show this help message
13841
- -V, --version Show version number
13842
-
13843
- Config file values are overridden by CLI flags.
13844
- Rendering flags (-o, -e, -t, -s) are silently ignored in --check and --parse modes.
13845
-
13846
- Examples:
13847
- zenuml -i diagram.zenuml
13848
- zenuml -i diagram.zenuml -o output.svg
13849
- zenuml -i diagram.zenuml -o output.png
13850
- zenuml -i diagram.zenuml -e png -s 3
13851
- zenuml -i diagram.zenuml -c config.json
13852
- cat diagram.zenuml | zenuml -i - -o -
13853
- zenuml --check -i file1.zenuml -i file2.zenuml
13854
- zenuml --check --json -i file1.zenuml -i file2.zenuml
13855
- zenuml --parse -i diagram.zenuml
13856
- zenuml -i readme.md --md
13857
- zenuml -i readme.md --md -e png
13858
-
13859
- PNG output requires the optional Playwright runtime and a Chromium browser:
13860
- npm install playwright-core
13861
- npx playwright-core install chromium
13862
13723
 
13863
- To use an existing Chrome/Chromium binary:
13864
- ZENUML_CHROMIUM_PATH=/path/to/chrome zenuml -i diagram.zenuml -o output.png
13865
- `.trimStart();
13866
- process.stdout.write(help);
13867
- }
13868
- function extractZenumlBlocks(md) {
13869
- const results = [];
13870
- const fencePattern = /^(`{3,})zenuml([^\n]*)\n([\s\S]*?)\n?\1\s*$/gm;
13871
- let match;
13872
- let blockIndex = 0;
13873
- while ((match = fencePattern.exec(md)) !== null) {
13874
- const raw = match[0];
13875
- const infoExtra = match[2];
13876
- const code = match[3];
13877
- const title = infoExtra.trim();
13878
- const empty = code.trim().length === 0;
13879
- results.push({ index: blockIndex++, code, title, raw, empty });
13880
- }
13881
- return results;
13882
- }
13883
- function isGlobPattern(s) {
13884
- return /[*?[]/.test(s);
13885
- }
13886
- function expandInputs(inputs) {
13887
- const result = [];
13888
- for (const input of inputs) {
13889
- if (input === "-" || !isGlobPattern(input)) {
13890
- result.push(input);
13891
- continue;
13892
- }
13893
- const glob = new Bun.Glob(input);
13894
- const matches = [];
13895
- for (const match of glob.scanSync({
13896
- cwd: process.cwd(),
13897
- onlyFiles: true
13898
- })) {
13899
- matches.push(match);
13900
- }
13901
- if (matches.length === 0) {
13902
- throw new Error(`Glob pattern "${input}" matched no files`);
13724
+ const PALETTE_CSS_VARS = {
13725
+ canvasBg: "--color-bg-canvas",
13726
+ frameBg: "--color-bg-frame",
13727
+ frameBorder: "--color-border-frame",
13728
+ titleText: "--color-text-title",
13729
+ participantBg: "--color-bg-participant",
13730
+ participantBorder: "--color-border-participant",
13731
+ participantText: "--color-text-participant",
13732
+ messageArrow: "--color-message-arrow",
13733
+ messageText: "--color-text-message",
13734
+ lifeline: "--color-border-base",
13735
+ occurrenceBg: "--color-bg-occurrence",
13736
+ occurrenceBorder: "--color-border-occurrence",
13737
+ fragmentBorder: "--color-border-fragment",
13738
+ fragmentHeaderBg: "--color-bg-fragment-header",
13739
+ fragmentHeaderText: "--color-text-fragment-header",
13740
+ fragmentText: "--color-text-fragment",
13741
+ fragmentSeparator: "--color-border-fragment-separator",
13742
+ guardOpacity: "--opacity-guard",
13743
+ guardText: "--color-text-guard",
13744
+ commentText: "--color-text-comment",
13745
+ commentOpacity: "--opacity-comment",
13746
+ groupOutline: "--color-border-group",
13747
+ dividerLine: "--color-border-divider",
13748
+ dividerBg: "--color-bg-divider",
13749
+ dividerText: "--color-text-divider",
13750
+ numberText: "--color-text-number",
13751
+ fragmentNumberText: "--color-text-fragment-number",
13752
+ numberBg: "--color-bg-number"
13753
+ };
13754
+ function safeSvgPalette(palette) {
13755
+ if (!palette) return void 0;
13756
+ const safe = {};
13757
+ for (const [key, value] of Object.entries(palette)) {
13758
+ if (!(key in PALETTE_CSS_VARS) || typeof value !== "string") continue;
13759
+ if (key === "guardOpacity" || key === "commentOpacity") {
13760
+ const opacity = Number(value);
13761
+ if (Number.isFinite(opacity) && opacity >= 0 && opacity <= 1)
13762
+ safe[key] = value;
13763
+ } else if (/^[a-zA-Z0-9#(),.%/+\-\s]+$/.test(value) && !/\b(?:url|expression|var)\s*\(/i.test(value)) {
13764
+ safe[key] = value;
13903
13765
  }
13904
- matches.sort();
13905
- result.push(...matches);
13906
13766
  }
13907
- return result;
13767
+ return safe;
13908
13768
  }
13909
- function isDirectory(p) {
13910
- try {
13911
- return statSync(p).isDirectory();
13912
- } catch {
13913
- return false;
13769
+ function normaliseBackingColor(color) {
13770
+ const rgb = colorString.get.rgb(color);
13771
+ if (!rgb || rgb[3] !== 1) {
13772
+ throw new TypeError("backingColor must be an opaque CSS colour");
13914
13773
  }
13774
+ return `rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]})`;
13915
13775
  }
13916
- function parseArgs(argv) {
13917
- const args = {
13918
- inputs: [],
13919
- check: false,
13920
- parse: false,
13921
- json: false,
13922
- quiet: false,
13923
- help: false,
13924
- version: false,
13925
- md: false,
13926
- watch: false
13776
+
13777
+ const FRAME_VIEWPORT_HEADER_ALLOWANCE = 28;
13778
+ const FRAME_BORDER_RADIUS = 4;
13779
+ function renderToSvg(code, options) {
13780
+ const safeOptions = options ? { ...options, palette: safeSvgPalette(options.palette) } : void 0;
13781
+ const surface = {
13782
+ backgroundColor: safeOptions?.palette?.canvasBg ?? "transparent"
13927
13783
  };
13928
- let i = 0;
13929
- while (i < argv.length) {
13930
- const arg = argv[i];
13931
- switch (arg) {
13932
- case "-i":
13933
- case "--input":
13934
- i++;
13935
- args.inputs.push(argv[i]);
13936
- break;
13937
- case "-o":
13938
- case "--output":
13939
- i++;
13940
- args.output = argv[i];
13941
- break;
13942
- case "-e":
13943
- case "--outputFormat":
13944
- i++;
13945
- args.outputFormat = argv[i];
13946
- break;
13947
- case "-s":
13948
- case "--scale":
13949
- i++;
13950
- args.scale = Number(argv[i]);
13951
- break;
13952
- case "-t":
13953
- case "--theme":
13954
- i++;
13955
- args.theme = argv[i];
13956
- break;
13957
- case "-c":
13958
- case "--configFile":
13959
- i++;
13960
- args.configFile = argv[i];
13961
- break;
13962
- case "--md":
13963
- args.md = true;
13964
- break;
13965
- case "--check":
13966
- args.check = true;
13967
- break;
13968
- case "--parse":
13969
- args.parse = true;
13970
- break;
13971
- case "--json":
13972
- args.json = true;
13973
- break;
13974
- case "-q":
13975
- case "--quiet":
13976
- args.quiet = true;
13977
- break;
13978
- case "-h":
13979
- case "--help":
13980
- args.help = true;
13981
- break;
13982
- case "-V":
13983
- case "--version":
13984
- args.version = true;
13985
- break;
13986
- case "-w":
13987
- case "--watch":
13988
- args.watch = true;
13989
- break;
13990
- default:
13991
- process.stderr.write(
13992
- `Unknown option: ${arg}
13993
- Run "zenuml --help" for usage.
13994
- `
13995
- );
13996
- process.exit(1);
13997
- }
13998
- i++;
13999
- }
14000
- return args;
14001
- }
14002
- function loadConfigFile(filePath) {
14003
- const resolved = resolve(filePath);
14004
- let raw;
14005
- try {
14006
- raw = readFileSync(resolved, "utf-8");
14007
- } catch {
14008
- process.stderr.write(`Error: Cannot read config file: ${resolved}
14009
- `);
14010
- process.exit(1);
14011
- }
14012
- try {
14013
- return JSON.parse(raw);
14014
- } catch {
14015
- process.stderr.write(`Error: Invalid JSON in config file: ${resolved}
14016
- `);
14017
- process.exit(1);
13784
+ const rootContext = RootContext(code);
13785
+ if (!rootContext) {
13786
+ return {
13787
+ svg: "<svg></svg>",
13788
+ surface,
13789
+ innerSvg: "",
13790
+ width: 0,
13791
+ height: 0,
13792
+ viewBox: "0 0 0 0",
13793
+ geometry: void 0
13794
+ };
14018
13795
  }
13796
+ const coordinates = new Coordinates(rootContext, WidthProviderOnCanvas);
13797
+ const verticalCoordinates = new VerticalCoordinates(rootContext);
13798
+ const titleContext = rootContext.title?.();
13799
+ const rawTitle = titleContext && typeof titleContext.content === "function" ? titleContext.content() : void 0;
13800
+ const title = rawTitle ? resolveEmojiInText(rawTitle) : void 0;
13801
+ const geometry = buildGeometry({
13802
+ rootContext,
13803
+ coordinates,
13804
+ verticalCoordinates,
13805
+ title,
13806
+ measureText: WidthProviderOnCanvas,
13807
+ enableNumbering: options?.enableNumbering
13808
+ });
13809
+ return { ...composeSvg(geometry, safeOptions), geometry };
14019
13810
  }
14020
- let _browser = null;
14021
- function pngRuntimeHelp(detail) {
14022
- return [
14023
- detail,
14024
- "",
14025
- "PNG output requires Playwright's Chromium runtime.",
14026
- "Install it with:",
14027
- " npm install playwright-core",
14028
- " npx playwright-core install chromium",
14029
- "",
14030
- "Or point ZenUML at an existing Chrome/Chromium binary:",
14031
- " ZENUML_CHROMIUM_PATH=/path/to/chrome zenuml -i diagram.zenuml -o diagram.png"
14032
- ].join("\n");
14033
- }
14034
- async function getPlaywrightBrowser() {
14035
- if (_browser) return _browser;
14036
- let playwright;
14037
- try {
14038
- playwright = await import('playwright-core');
14039
- } catch (error) {
14040
- throw new Error(
14041
- pngRuntimeHelp(
14042
- `Cannot load optional dependency "playwright-core": ${error instanceof Error ? error.message : String(error)}`
14043
- )
14044
- );
14045
- }
14046
- const executablePath = process.env["ZENUML_CHROMIUM_PATH"];
14047
- try {
14048
- _browser = await playwright.chromium.launch(
14049
- executablePath ? { executablePath } : void 0
14050
- );
14051
- return _browser;
14052
- } catch (error) {
14053
- throw new Error(
14054
- pngRuntimeHelp(
14055
- `Cannot launch Chromium${executablePath ? ` at ${executablePath}` : ""}: ${error instanceof Error ? error.message : String(error)}`
14056
- )
13811
+ function composeSvg(g, options) {
13812
+ const surface = {
13813
+ backgroundColor: options?.palette?.canvasBg ?? "transparent"
13814
+ };
13815
+ const padding = 10;
13816
+ const headerH = FRAME_VIEWPORT_HEADER_ALLOWANCE;
13817
+ let contentLeftMargin = 1 + padding + g.frameBorderLeft;
13818
+ let numberLeft = 0;
13819
+ for (const message of [
13820
+ ...g.messages,
13821
+ ...g.creations.map((creation) => creation.message)
13822
+ ]) {
13823
+ if (!message.number) continue;
13824
+ numberLeft = Math.min(
13825
+ numberLeft,
13826
+ Math.min(message.fromX, message.toX) + 1 - 4 - messageNumberWidth(message.number)
14057
13827
  );
14058
13828
  }
14059
- }
14060
- async function closeBrowser() {
14061
- if (_browser) {
14062
- await _browser.close();
14063
- _browser = null;
13829
+ for (const call of g.selfCalls) {
13830
+ if (call.number)
13831
+ numberLeft = Math.min(
13832
+ numberLeft,
13833
+ call.x - 3 - messageNumberWidth(call.number)
13834
+ );
14064
13835
  }
14065
- }
14066
- async function rasterizeToPng(svgString, svgWidth, svgHeight, scale) {
14067
- const browser = await getPlaywrightBrowser();
14068
- const page = await browser.newPage({
14069
- viewport: {
14070
- width: Math.ceil(svgWidth),
14071
- height: Math.ceil(svgHeight)
14072
- },
14073
- deviceScaleFactor: scale
14074
- });
14075
- try {
14076
- const html = `<!DOCTYPE html>
14077
- <html><head><style>
14078
- html, body { margin: 0; padding: 0; background: white; overflow: hidden; }
14079
- svg { display: block; width: ${svgWidth}px; height: ${svgHeight}px; }
14080
- </style></head><body>${svgString}</body></html>`;
14081
- await page.setContent(html, { waitUntil: "load" });
14082
- const png = await page.screenshot({ type: "png" });
14083
- return Buffer.from(png);
14084
- } finally {
14085
- await page.close();
13836
+ for (const returned of g.returns) {
13837
+ if (returned.number && !returned.isSelf)
13838
+ numberLeft = Math.min(
13839
+ numberLeft,
13840
+ Math.min(returned.fromX, returned.toX) - 4 - messageNumberWidth(returned.number)
13841
+ );
14086
13842
  }
14087
- }
14088
- function getRuleNames(ctx) {
14089
- return ctx?.parser?.ruleNames;
14090
- }
14091
- function isFacadeNode(node) {
14092
- return !!node && node.symbol === void 0 && !node.parser && !!node._doc && typeof node.constructor?.name === "string" && node.constructor.name.endsWith("Context");
14093
- }
14094
- function facadeRuleName(className) {
14095
- const base = className.endsWith("Context") ? className.slice(0, -"Context".length) : className;
14096
- return base.charAt(0).toLowerCase() + base.slice(1);
14097
- }
14098
- function serializeFacadeNode(node) {
14099
- const result = {
14100
- type: "rule",
14101
- ruleName: facadeRuleName(node.constructor.name)
14102
- };
14103
- const ruleChildren = node.children ?? [];
14104
- const childSpans = ruleChildren.map((c) => ({
14105
- c,
14106
- start: c.start?.start ?? null,
14107
- end: c.stop?.stop ?? null
14108
- // inclusive
14109
- }));
14110
- const items = [];
14111
- for (const cs of childSpans) {
14112
- if (cs.start !== null) {
14113
- items.push({ off: cs.start, node: serializeParseTree(cs.c) });
13843
+ contentLeftMargin += Math.max(0, padding - contentLeftMargin - numberLeft);
13844
+ const viewWidth = g.width + contentLeftMargin + padding + g.frameBorderRight + 1;
13845
+ const viewHeight = g.height + padding * 2 + headerH - 1;
13846
+ const parts = [];
13847
+ for (const grp of g.groups) {
13848
+ parts.push(renderGroup(grp));
13849
+ }
13850
+ for (const l of g.lifelines) {
13851
+ parts.push(renderLifeline(l));
13852
+ }
13853
+ const creationNames = new Set(g.creations.map((c) => c.participant.name));
13854
+ for (const p of g.participants) {
13855
+ if (!creationNames.has(p.name)) {
13856
+ parts.push(renderParticipant(p));
14114
13857
  }
14115
13858
  }
14116
- const nodeStart = node.start?.start;
14117
- const nodeStop = node.stop?.stop;
14118
- if (nodeStart !== void 0 && nodeStop !== null && nodeStop !== void 0) {
14119
- for (const leaf of node._doc.leaves) {
14120
- if (leaf.offset < nodeStart) continue;
14121
- if (leaf.offset > nodeStop) break;
14122
- if (leaf.hidden) continue;
14123
- const covered = childSpans.some(
14124
- (cs) => cs.start !== null && cs.end !== null && leaf.offset >= cs.start && leaf.offset <= cs.end
14125
- );
14126
- if (covered) continue;
14127
- items.push({
14128
- off: leaf.offset,
14129
- node: { type: "terminal", text: leaf.text }
14130
- });
13859
+ for (const o of g.occurrences) {
13860
+ parts.push(renderOccurrence(o));
13861
+ }
13862
+ for (const p of g.participants) {
13863
+ if (creationNames.has(p.name)) {
13864
+ parts.push(renderParticipant(p));
14131
13865
  }
14132
13866
  }
14133
- items.sort((a, b) => a.off - b.off);
14134
- if (items.length > 0) {
14135
- result.children = items.map((it) => it.node);
13867
+ for (const m of g.messages) {
13868
+ parts.push(renderMessage(m));
14136
13869
  }
14137
- return result;
14138
- }
14139
- function serializeParseTree(node) {
14140
- if (!node) return { type: "null" };
14141
- if (node.symbol !== void 0) {
14142
- return {
14143
- type: "terminal",
14144
- text: node.getText()
14145
- };
13870
+ for (const s of g.selfCalls) {
13871
+ parts.push(renderSelfCall(s));
14146
13872
  }
14147
- if (isFacadeNode(node)) {
14148
- return serializeFacadeNode(node);
13873
+ for (const c of g.creations) {
13874
+ parts.push(renderCreation(c));
14149
13875
  }
14150
- const ruleNames = getRuleNames(node);
14151
- const ruleName = ruleNames && node.ruleIndex !== void 0 ? ruleNames[node.ruleIndex] : void 0;
14152
- const result = {
14153
- type: "rule"
14154
- };
14155
- if (ruleName) {
14156
- result.ruleName = ruleName;
13876
+ for (const r2 of g.returns) {
13877
+ parts.push(renderReturn(r2));
14157
13878
  }
14158
- const children = node.children;
14159
- if (children && children.length > 0) {
14160
- result.children = children.map((child) => serializeParseTree(child));
13879
+ for (const f of g.fragments) {
13880
+ parts.push(renderFragment(f));
14161
13881
  }
14162
- return result;
13882
+ for (const d of g.dividers) {
13883
+ parts.push(renderDivider(d));
13884
+ }
13885
+ for (const c of g.comments) {
13886
+ parts.push(renderComment(c));
13887
+ }
13888
+ const r = FRAME_BORDER_RADIUS;
13889
+ const frameSvg = [
13890
+ `<rect class="frame-border-outer" x="0" y="0" width="${viewWidth}" height="${viewHeight}" rx="${r}" fill="#666"/>`,
13891
+ `<rect class="frame-border-inner" x="1" y="1" width="${viewWidth - 2}" height="${viewHeight - 2}" rx="${Math.max(0, r - 1)}" fill="#fff"/>`
13892
+ ].join("\n");
13893
+ const headerLineY = 1 + DIAGRAM_HEADER_HEIGHT;
13894
+ const headerLineDrawY = headerLineY - 0.5;
13895
+ const headerLineSvg = `<line class="frame-header-line" x1="1" y1="${headerLineDrawY}" x2="${viewWidth - 1}" y2="${headerLineDrawY}"/>`;
13896
+ const titleSvg = g.title ? `<text x="5" y="${headerLineDrawY / 2}" dominant-baseline="central" class="frame-title">${esc(g.title)}</text>` : "";
13897
+ const viewBox = `0 0 ${viewWidth} ${viewHeight}`;
13898
+ const defs = `<defs>
13899
+ <style>${buildThemeStyles(resolveSvgPalette(options))}</style>
13900
+ </defs>`;
13901
+ const frame = `${frameSvg}
13902
+ ${headerLineSvg}
13903
+ ${titleSvg}`;
13904
+ const content = `<g transform="translate(${contentLeftMargin}, ${headerLineY})">
13905
+ ${parts.join("\n")}
13906
+ </g>`;
13907
+ const backing = options?.backingColor !== void 0 ? `<rect class="export-backing" x="0" y="0" width="${viewWidth}" height="${viewHeight}" style="fill: ${normaliseBackingColor(options.backingColor)} !important"/>` : "";
13908
+ const background = surface.backgroundColor !== "transparent" ? `<rect class="canvas-background" x="0" y="0" width="${viewWidth}" height="${viewHeight}" fill="${surface.backgroundColor}"/>` : "";
13909
+ const innerSvg = `${defs}
13910
+ ${backing}
13911
+ ${background}
13912
+ ${frame}
13913
+ ${content}`;
13914
+ const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${viewWidth}" height="${viewHeight}" viewBox="${viewBox}">
13915
+ ${innerSvg}
13916
+ </svg>`;
13917
+ return {
13918
+ svg,
13919
+ innerSvg,
13920
+ width: viewWidth,
13921
+ height: viewHeight,
13922
+ viewBox,
13923
+ surface
13924
+ };
14163
13925
  }
14164
- async function readCode(input) {
14165
- if (input === "-") {
14166
- return readStdin();
13926
+ function resolveSvgPalette(options) {
13927
+ const theme = resolvePalette(options?.theme);
13928
+ const palette = options?.palette;
13929
+ if (!palette) return theme;
13930
+ return {
13931
+ ...theme,
13932
+ ...palette,
13933
+ ...palette.fragmentHeaderBg ? { fragmentHeaderOpacity: "1" } : {},
13934
+ ...palette.numberBg ? { numberBgOpacity: "1" } : {}
13935
+ };
13936
+ }
13937
+
13938
+ function resolveRenderSettings(args, config, outputPath) {
13939
+ const autoFormatFromExt = outputPath !== void 0 && outputPath !== "-" && extname(outputPath).toLowerCase() === ".png" ? "png" : void 0;
13940
+ const format = args.outputFormat ?? config.configOutputFormat ?? autoFormatFromExt ?? "svg";
13941
+ if (format !== "svg" && format !== "png") {
13942
+ throw new Error(
13943
+ `Unsupported output format: "${format}". Use "svg" or "png".`
13944
+ );
14167
13945
  }
14168
- const inputPath = resolve(input);
14169
- try {
14170
- return readFileSync(inputPath, "utf-8");
14171
- } catch {
14172
- throw new Error(`Cannot read input file: ${inputPath}`);
13946
+ const renderOptions = {};
13947
+ const theme = args.theme ?? config.configTheme;
13948
+ if (theme) {
13949
+ renderOptions.theme = theme;
14173
13950
  }
13951
+ return {
13952
+ format,
13953
+ scale: args.scale ?? config.configScale ?? 2,
13954
+ renderOptions
13955
+ };
14174
13956
  }
14175
- async function checkOne(input) {
14176
- const fileName = input === "-" ? "<stdin>" : input;
14177
- let code;
13957
+ async function renderDiagram(code, settings, label, beforeEncode) {
13958
+ let result;
14178
13959
  try {
14179
- code = await readCode(input);
13960
+ await ensureDiagramIconsLoaded(code);
13961
+ result = renderToSvg(code, settings.renderOptions);
14180
13962
  } catch (err) {
14181
- return {
14182
- file: fileName,
14183
- pass: false,
14184
- errors: [{ line: 0, column: 0, msg: err.message }]
14185
- };
13963
+ throw new Error(`Failed to render ${label}: ${err.message}`);
14186
13964
  }
14187
- Parser.ErrorDetails.length = 0;
14188
- Parser.RootContext(code);
14189
- const errors = Parser.ErrorDetails.map((e) => ({
14190
- line: e.line,
14191
- column: e.column,
14192
- msg: e.msg
14193
- }));
14194
- return {
14195
- file: fileName,
14196
- pass: errors.length === 0,
14197
- errors
14198
- };
13965
+ beforeEncode?.();
13966
+ const bytes = settings.format === "png" ? await rasterizeToPng(
13967
+ result.svg,
13968
+ result.width,
13969
+ result.height,
13970
+ settings.scale
13971
+ ) : result.svg;
13972
+ return { bytes, width: result.width, height: result.height };
14199
13973
  }
14200
13974
  async function renderMarkdownFile(inputArg, args, config) {
14201
13975
  const mdContent = await readCode(inputArg);
14202
- const effectiveFormat = args.outputFormat ?? config.configOutputFormat ?? "svg";
14203
- if (effectiveFormat !== "svg" && effectiveFormat !== "png") {
14204
- throw new Error(
14205
- `Unsupported output format: "${effectiveFormat}". Use "svg" or "png".`
14206
- );
14207
- }
13976
+ const settings = resolveRenderSettings(args, config);
14208
13977
  const inputPath = inputArg === "-" ? void 0 : resolve(inputArg);
14209
13978
  const outputPath = args.output === "-" ? "-" : args.output ? resolve(args.output) : inputPath ? join(
14210
13979
  dirname(inputPath),
@@ -14212,55 +13981,198 @@ async function renderMarkdownFile(inputArg, args, config) {
14212
13981
  ) : "-";
14213
13982
  const imageDir = outputPath !== "-" ? dirname(outputPath) : inputPath ? dirname(inputPath) : process.cwd();
14214
13983
  const imageStem = inputPath ? basename(inputArg, extname(inputArg)) : outputPath !== "-" ? basename(outputPath, extname(outputPath)) : "diagram";
14215
- const renderOptions = {};
14216
- const effectiveTheme = args.theme ?? config.configTheme;
14217
- if (effectiveTheme) {
14218
- renderOptions.theme = effectiveTheme;
13984
+ const blocks = extractZenumlBlocks(mdContent);
13985
+ const imageFiles = /* @__PURE__ */ new Map();
13986
+ for (const block of blocks) {
13987
+ if (block.empty) continue;
13988
+ const imageFilename = `${imageStem}-zenuml-${block.index}.${settings.format}`;
13989
+ const imageFilePath = join(imageDir, imageFilename);
13990
+ const { bytes: image } = await renderDiagram(
13991
+ block.code,
13992
+ settings,
13993
+ `zenuml block ${block.index}`,
13994
+ () => mkdirSync(imageDir, { recursive: true })
13995
+ );
13996
+ writeFileSync(imageFilePath, image);
13997
+ imageFiles.set(block.index, imageFilename);
13998
+ if (!args.quiet && !args.watch) {
13999
+ process.stderr.write(`Wrote ${imageFilePath}
14000
+ `);
14001
+ }
14002
+ }
14003
+ const outputMd = [...blocks].reverse().reduce((markdown, block) => {
14004
+ const replacement = block.empty ? "" : `![${block.title || `diagram ${block.index + 1}`}](${imageFiles.get(block.index)})`;
14005
+ return markdown.replace(block.raw, replacement);
14006
+ }, mdContent);
14007
+ if (outputPath === "-") {
14008
+ process.stdout.write(outputMd);
14009
+ return;
14010
+ }
14011
+ mkdirSync(dirname(outputPath), { recursive: true });
14012
+ writeFileSync(outputPath, outputMd, "utf-8");
14013
+ if (!args.quiet && !args.watch) {
14014
+ process.stderr.write(`Wrote ${outputPath}
14015
+ `);
14016
+ }
14017
+ }
14018
+ async function renderOneFile(inputArg, args, config) {
14019
+ const outputPath = resolveOutput(inputArg, args.output, ".svg");
14020
+ const settings = resolveRenderSettings(args, config, outputPath);
14021
+ const code = await readCode(inputArg);
14022
+ let finalOutputPath = outputPath;
14023
+ if (settings.format === "png" && finalOutputPath !== "-") {
14024
+ if (!args.output || isDirectory(resolve(args.output))) {
14025
+ const ext = extname(finalOutputPath);
14026
+ finalOutputPath = finalOutputPath.slice(0, -ext.length) + ".png";
14027
+ }
14028
+ }
14029
+ const { bytes } = await renderDiagram(code, settings, "diagram", () => {
14030
+ if (finalOutputPath !== "-") {
14031
+ mkdirSync(dirname(finalOutputPath), { recursive: true });
14032
+ }
14033
+ });
14034
+ if (finalOutputPath === "-") {
14035
+ process.stdout.write(bytes);
14036
+ } else {
14037
+ try {
14038
+ writeFileSync(finalOutputPath, bytes);
14039
+ if (!args.quiet) {
14040
+ process.stderr.write(`Wrote ${finalOutputPath}
14041
+ `);
14042
+ }
14043
+ } catch {
14044
+ throw new Error(`Cannot write output file: ${finalOutputPath}`);
14045
+ }
14046
+ }
14047
+ }
14048
+
14049
+ function watchTimestamp() {
14050
+ const now = /* @__PURE__ */ new Date();
14051
+ const hh = String(now.getHours()).padStart(2, "0");
14052
+ const mm = String(now.getMinutes()).padStart(2, "0");
14053
+ const ss = String(now.getSeconds()).padStart(2, "0");
14054
+ return `[${hh}:${mm}:${ss}]`;
14055
+ }
14056
+ async function startWatchMode(inputs, renderFn, watchFn, log, delayMs, renderMdFn) {
14057
+ const logFn = log ?? ((msg) => process.stderr.write(msg + "\n"));
14058
+ const delay = delayMs ?? 100;
14059
+ const watchFactory = watchFn ?? ((path, handler) => {
14060
+ const watcher = watch(path, () => handler());
14061
+ return { close: () => watcher.close() };
14062
+ });
14063
+ function pickRender(p) {
14064
+ if (renderMdFn && /\.(?:md|markdown)$/i.test(p)) {
14065
+ return renderMdFn;
14066
+ }
14067
+ return renderFn;
14219
14068
  }
14220
- const blocks = extractZenumlBlocks(mdContent);
14221
- const imageFiles = /* @__PURE__ */ new Map();
14222
- for (const block of blocks) {
14223
- if (block.empty) continue;
14224
- const imageFilename = `${imageStem}-zenuml-${block.index}.${effectiveFormat}`;
14225
- const imageFilePath = join(imageDir, imageFilename);
14226
- let result;
14069
+ for (const input of inputs) {
14070
+ const rf = pickRender(input);
14071
+ const ts = watchTimestamp();
14227
14072
  try {
14228
- await ensureDiagramIconsLoaded(block.code);
14229
- result = renderToSvg(block.code, renderOptions);
14073
+ await rf(input);
14074
+ logFn(`${ts} Rendered ${input} -> done`);
14230
14075
  } catch (err) {
14231
- throw new Error(
14232
- `Failed to render zenuml block ${block.index}: ${err.message}`
14233
- );
14234
- }
14235
- mkdirSync(imageDir, { recursive: true });
14236
- const image = effectiveFormat === "png" ? await rasterizeToPng(
14237
- result.svg,
14238
- result.width,
14239
- result.height,
14240
- args.scale ?? config.configScale ?? 2
14241
- ) : result.svg;
14242
- writeFileSync(imageFilePath, image);
14243
- imageFiles.set(block.index, imageFilename);
14244
- if (!args.quiet && !args.watch) {
14245
- process.stderr.write(`Wrote ${imageFilePath}
14246
- `);
14076
+ logFn(`${ts} Error: ${input}: ${err.message}`);
14247
14077
  }
14248
14078
  }
14249
- const outputMd = [...blocks].reverse().reduce((markdown, block) => {
14250
- const replacement = block.empty ? "" : `![${block.title || `diagram ${block.index + 1}`}](${imageFiles.get(block.index)})`;
14251
- return markdown.replace(block.raw, replacement);
14252
- }, mdContent);
14253
- if (outputPath === "-") {
14254
- process.stdout.write(outputMd);
14255
- return;
14079
+ const handles = [];
14080
+ const timers = /* @__PURE__ */ new Map();
14081
+ for (const input of inputs) {
14082
+ const rf = pickRender(input);
14083
+ const handle = watchFactory(input, () => {
14084
+ const existing = timers.get(input);
14085
+ if (existing !== void 0) clearTimeout(existing);
14086
+ const t = setTimeout(async () => {
14087
+ timers.delete(input);
14088
+ const ts = watchTimestamp();
14089
+ try {
14090
+ await rf(input);
14091
+ logFn(`${ts} Rendered ${input} -> done`);
14092
+ } catch (err) {
14093
+ logFn(`${ts} Error: ${input}: ${err.message}`);
14094
+ }
14095
+ }, delay);
14096
+ timers.set(input, t);
14097
+ });
14098
+ handles.push(handle);
14256
14099
  }
14257
- mkdirSync(dirname(outputPath), { recursive: true });
14258
- writeFileSync(outputPath, outputMd, "utf-8");
14259
- if (!args.quiet && !args.watch) {
14260
- process.stderr.write(`Wrote ${outputPath}
14261
- `);
14100
+ function shutdown() {
14101
+ for (const t of timers.values()) {
14102
+ clearTimeout(t);
14103
+ }
14104
+ timers.clear();
14105
+ for (const h of handles) {
14106
+ h.close();
14107
+ }
14108
+ }
14109
+ return { shutdown };
14110
+ }
14111
+
14112
+ function readVersion() {
14113
+ const pkgPath = resolve(import.meta.dir, "../../package.json");
14114
+ try {
14115
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
14116
+ return pkg.version ?? "unknown";
14117
+ } catch {
14118
+ return "unknown";
14262
14119
  }
14263
14120
  }
14121
+ function printHelp() {
14122
+ const help = `
14123
+ Usage: zenuml [options]
14124
+
14125
+ Render ZenUML DSL text to SVG or PNG.
14126
+
14127
+ Rendering:
14128
+ -i, --input <file> Input file (use "-" for stdin; repeatable)
14129
+ -o, --output <file> Output file (use "-" for stdout; default: <input>.svg)
14130
+ -e, --outputFormat <format> Output format: "svg" (default) or "png"
14131
+ -s, --scale <factor> Pixel scale factor for PNG (default: 2; ignored for SVG)
14132
+ -t, --theme <name> Theme: default, mermaid, clean-light, dark, neon
14133
+ (clean-dark and darcula are aliases of dark;
14134
+ prefix "theme-"; unknown names use default)
14135
+ -c, --configFile <file> JSON config file with { theme, scale, outputFormat }
14136
+ --md Markdown mode: render zenuml code blocks and produce output Markdown
14137
+
14138
+ Validation:
14139
+ --check Validate syntax without rendering (exit 0 if valid, 1 if errors)
14140
+ --parse Parse input and output AST as JSON (exit 0 if valid, 1 if errors)
14141
+ --json Machine-readable JSON output for --check mode
14142
+
14143
+ Batch & Watch:
14144
+ -w, --watch Watch input files and re-render on change (incompatible with --check, --parse, stdin)
14145
+
14146
+ General:
14147
+ -q, --quiet Suppress non-error output
14148
+ -h, --help Show this help message
14149
+ -V, --version Show version number
14150
+
14151
+ Config file values are overridden by CLI flags.
14152
+ Rendering flags (-o, -e, -t, -s) are silently ignored in --check and --parse modes.
14153
+
14154
+ Examples:
14155
+ zenuml -i diagram.zenuml
14156
+ zenuml -i diagram.zenuml -o output.svg
14157
+ zenuml -i diagram.zenuml -o output.png
14158
+ zenuml -i diagram.zenuml -e png -s 3
14159
+ zenuml -i diagram.zenuml -c config.json
14160
+ cat diagram.zenuml | zenuml -i - -o -
14161
+ zenuml --check -i file1.zenuml -i file2.zenuml
14162
+ zenuml --check --json -i file1.zenuml -i file2.zenuml
14163
+ zenuml --parse -i diagram.zenuml
14164
+ zenuml -i readme.md --md
14165
+ zenuml -i readme.md --md -e png
14166
+
14167
+ PNG output requires the optional Playwright runtime and a Chromium browser:
14168
+ npm install playwright-core
14169
+ npx playwright-core install chromium
14170
+
14171
+ To use an existing Chrome/Chromium binary:
14172
+ ZENUML_CHROMIUM_PATH=/path/to/chrome zenuml -i diagram.zenuml -o output.png
14173
+ `.trimStart();
14174
+ process.stdout.write(help);
14175
+ }
14264
14176
  async function main() {
14265
14177
  if (!globalThis.OffscreenCanvas && typeof document === "undefined") {
14266
14178
  try {
@@ -14456,178 +14368,6 @@ async function main() {
14456
14368
  process.exit(1);
14457
14369
  }
14458
14370
  }
14459
- async function renderOneFile(inputArg, args, config) {
14460
- const outputPath = resolveOutput(inputArg, args.output, ".svg");
14461
- const autoFormatFromExt = outputPath !== "-" && extname(outputPath).toLowerCase() === ".png" ? "png" : void 0;
14462
- const effectiveFormat = args.outputFormat ?? config.configOutputFormat ?? autoFormatFromExt ?? "svg";
14463
- if (effectiveFormat !== "svg" && effectiveFormat !== "png") {
14464
- throw new Error(
14465
- `Unsupported output format: "${effectiveFormat}". Use "svg" or "png".`
14466
- );
14467
- }
14468
- const effectiveScale = args.scale ?? config.configScale ?? 2;
14469
- const effectiveTheme = args.theme ?? config.configTheme;
14470
- let code;
14471
- if (inputArg === "-") {
14472
- code = await readStdin();
14473
- } else {
14474
- const inputPath = resolve(inputArg);
14475
- try {
14476
- code = readFileSync(inputPath, "utf-8");
14477
- } catch {
14478
- throw new Error(`Cannot read input file: ${inputPath}`);
14479
- }
14480
- }
14481
- const renderOptions = {};
14482
- if (effectiveTheme) {
14483
- renderOptions.theme = effectiveTheme;
14484
- }
14485
- let svg;
14486
- let svgWidth;
14487
- let svgHeight;
14488
- try {
14489
- await ensureDiagramIconsLoaded(code);
14490
- const result = renderToSvg(code, renderOptions);
14491
- svg = result.svg;
14492
- svgWidth = result.width;
14493
- svgHeight = result.height;
14494
- } catch (err) {
14495
- throw new Error(`Failed to render diagram: ${err.message}`);
14496
- }
14497
- let finalOutputPath = outputPath;
14498
- if (effectiveFormat === "png" && finalOutputPath !== "-") {
14499
- if (!args.output || isDirectory(resolve(args.output))) {
14500
- const ext = extname(finalOutputPath);
14501
- finalOutputPath = finalOutputPath.slice(0, -ext.length) + ".png";
14502
- }
14503
- }
14504
- if (finalOutputPath !== "-") {
14505
- const dir = dirname(finalOutputPath);
14506
- mkdirSync(dir, { recursive: true });
14507
- }
14508
- if (effectiveFormat === "png") {
14509
- const pngBuffer = await rasterizeToPng(
14510
- svg,
14511
- svgWidth,
14512
- svgHeight,
14513
- effectiveScale
14514
- );
14515
- if (finalOutputPath === "-") {
14516
- process.stdout.write(pngBuffer);
14517
- } else {
14518
- try {
14519
- writeFileSync(finalOutputPath, pngBuffer);
14520
- if (!args.quiet) {
14521
- process.stderr.write(`Wrote ${finalOutputPath}
14522
- `);
14523
- }
14524
- } catch {
14525
- throw new Error(`Cannot write output file: ${finalOutputPath}`);
14526
- }
14527
- }
14528
- } else {
14529
- if (finalOutputPath === "-") {
14530
- process.stdout.write(svg);
14531
- } else {
14532
- try {
14533
- writeFileSync(finalOutputPath, svg, "utf-8");
14534
- if (!args.quiet) {
14535
- process.stderr.write(`Wrote ${finalOutputPath}
14536
- `);
14537
- }
14538
- } catch {
14539
- throw new Error(`Cannot write output file: ${finalOutputPath}`);
14540
- }
14541
- }
14542
- }
14543
- }
14544
- function resolveOutput(input, output, defaultExt = ".svg") {
14545
- if (output !== void 0) {
14546
- if (output === "-") return "-";
14547
- const resolvedOutput = resolve(output);
14548
- if (isDirectory(resolvedOutput)) {
14549
- if (input === "-") return "-";
14550
- const ext2 = extname(input);
14551
- const base2 = basename(input, ext2);
14552
- return join(resolvedOutput, `${base2}${defaultExt}`);
14553
- }
14554
- return resolvedOutput;
14555
- }
14556
- if (input === "-") return "-";
14557
- const ext = extname(input);
14558
- const base = basename(input, ext);
14559
- const dir = dirname(resolve(input));
14560
- return join(dir, `${base}${defaultExt}`);
14561
- }
14562
- async function readStdin() {
14563
- const chunks = [];
14564
- for await (const chunk of Bun.stdin.stream()) {
14565
- chunks.push(chunk);
14566
- }
14567
- return Buffer.concat(chunks).toString("utf-8");
14568
- }
14569
- function watchTimestamp() {
14570
- const now = /* @__PURE__ */ new Date();
14571
- const hh = String(now.getHours()).padStart(2, "0");
14572
- const mm = String(now.getMinutes()).padStart(2, "0");
14573
- const ss = String(now.getSeconds()).padStart(2, "0");
14574
- return `[${hh}:${mm}:${ss}]`;
14575
- }
14576
- async function startWatchMode(inputs, renderFn, watchFn, log, delayMs, renderMdFn) {
14577
- const logFn = log ?? ((msg) => process.stderr.write(msg + "\n"));
14578
- const delay = delayMs ?? 100;
14579
- const watchFactory = watchFn ?? ((path, handler) => {
14580
- const watcher = watch(path, () => handler());
14581
- return { close: () => watcher.close() };
14582
- });
14583
- function pickRender(p) {
14584
- if (renderMdFn && /\.(?:md|markdown)$/i.test(p)) {
14585
- return renderMdFn;
14586
- }
14587
- return renderFn;
14588
- }
14589
- for (const input of inputs) {
14590
- const rf = pickRender(input);
14591
- const ts = watchTimestamp();
14592
- try {
14593
- await rf(input);
14594
- logFn(`${ts} Rendered ${input} -> done`);
14595
- } catch (err) {
14596
- logFn(`${ts} Error: ${input}: ${err.message}`);
14597
- }
14598
- }
14599
- const handles = [];
14600
- const timers = /* @__PURE__ */ new Map();
14601
- for (const input of inputs) {
14602
- const rf = pickRender(input);
14603
- const handle = watchFactory(input, () => {
14604
- const existing = timers.get(input);
14605
- if (existing !== void 0) clearTimeout(existing);
14606
- const t = setTimeout(async () => {
14607
- timers.delete(input);
14608
- const ts = watchTimestamp();
14609
- try {
14610
- await rf(input);
14611
- logFn(`${ts} Rendered ${input} -> done`);
14612
- } catch (err) {
14613
- logFn(`${ts} Error: ${input}: ${err.message}`);
14614
- }
14615
- }, delay);
14616
- timers.set(input, t);
14617
- });
14618
- handles.push(handle);
14619
- }
14620
- function shutdown() {
14621
- for (const t of timers.values()) {
14622
- clearTimeout(t);
14623
- }
14624
- timers.clear();
14625
- for (const h of handles) {
14626
- h.close();
14627
- }
14628
- }
14629
- return { shutdown };
14630
- }
14631
14371
  if (import.meta.main) {
14632
14372
  main().finally(() => closeBrowser());
14633
14373
  }