@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.
- package/dist/cli/assets/{CloudIcons-De45wK6e.mjs → CloudIcons-BXI_VQtG.mjs} +3 -3
- package/dist/cli/zenuml.mjs +1692 -1952
- package/dist/parser/index.cjs +2 -2
- package/dist/parser/index.mjs +421 -414
- package/dist/zenuml.esm.mjs +12587 -12512
- package/dist/zenuml.js +556 -556
- package/package.json +1 -3
package/dist/cli/zenuml.mjs
CHANGED
|
@@ -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
|
-
|
|
6
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
9026
|
-
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
|
-
|
|
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
|
|
9061
|
-
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
|
-
|
|
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
|
|
9223
|
+
if (returnFrom) participants.Add(returnFrom);
|
|
9112
9224
|
const returnTo = ctx.ReturnTo();
|
|
9113
|
-
returnTo
|
|
9225
|
+
if (returnTo) participants.Add(returnTo);
|
|
9114
9226
|
};
|
|
9115
|
-
|
|
9116
9227
|
const walker$1 = antlr4.tree.ParseTreeWalker.DEFAULT;
|
|
9117
|
-
|
|
9118
|
-
|
|
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
|
|
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
|
|
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 ===
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
9339
|
-
|
|
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$
|
|
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
|
-
|
|
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
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
9676
|
+
const channel = sequenceLexer.channelNames.indexOf("COMMENT_CHANNEL");
|
|
9680
9677
|
if (this.constructor.name === "BraceBlockContext") {
|
|
9681
9678
|
tokenIndex = this.stop.tokenIndex;
|
|
9682
9679
|
}
|
|
9683
|
-
|
|
9684
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
9755
|
-
const
|
|
9756
|
-
|
|
9757
|
-
|
|
9758
|
-
|
|
9759
|
-
|
|
9760
|
-
|
|
9761
|
-
|
|
9762
|
-
|
|
9763
|
-
|
|
9764
|
-
|
|
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
|
-
|
|
9815
|
-
|
|
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
|
-
|
|
9818
|
-
|
|
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
|
-
|
|
9821
|
-
return
|
|
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
|
-
|
|
9838
|
-
|
|
9839
|
-
|
|
9840
|
-
|
|
9841
|
-
|
|
9842
|
-
|
|
9843
|
-
|
|
9844
|
-
|
|
9845
|
-
|
|
9846
|
-
|
|
9847
|
-
|
|
9848
|
-
|
|
9849
|
-
|
|
9850
|
-
|
|
9851
|
-
|
|
9852
|
-
|
|
9853
|
-
|
|
9854
|
-
|
|
9855
|
-
|
|
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
|
-
|
|
9858
|
-
|
|
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
|
-
|
|
9861
|
-
|
|
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
|
-
|
|
9865
|
-
|
|
9866
|
-
if (
|
|
9867
|
-
|
|
9868
|
-
|
|
9869
|
-
|
|
9870
|
-
|
|
9871
|
-
|
|
9872
|
-
|
|
9873
|
-
|
|
9874
|
-
|
|
9875
|
-
|
|
9876
|
-
|
|
9877
|
-
|
|
9878
|
-
|
|
9879
|
-
|
|
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
|
|
9900
|
-
return
|
|
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
|
|
9929
|
-
const
|
|
9930
|
-
for (
|
|
9931
|
-
|
|
9932
|
-
|
|
9933
|
-
|
|
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
|
-
|
|
9939
|
-
|
|
9940
|
-
|
|
9941
|
-
|
|
9942
|
-
|
|
9943
|
-
|
|
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
|
-
|
|
9950
|
-
|
|
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
|
-
|
|
9929
|
+
matches.sort();
|
|
9930
|
+
result.push(...matches);
|
|
9957
9931
|
}
|
|
9958
|
-
return
|
|
9932
|
+
return result;
|
|
9959
9933
|
}
|
|
9960
|
-
function
|
|
9961
|
-
|
|
9962
|
-
|
|
9963
|
-
|
|
9964
|
-
|
|
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
|
|
9973
|
-
|
|
9974
|
-
|
|
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
|
|
9978
|
-
|
|
9979
|
-
|
|
9980
|
-
|
|
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
|
|
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
|
|
9985
|
-
const
|
|
9986
|
-
const
|
|
9987
|
-
|
|
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
|
-
|
|
9992
|
-
|
|
9993
|
-
|
|
9994
|
-
|
|
9995
|
-
|
|
9996
|
-
|
|
9997
|
-
|
|
9998
|
-
|
|
9999
|
-
|
|
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
|
-
|
|
10005
|
-
|
|
10006
|
-
|
|
10007
|
-
|
|
10008
|
-
|
|
10009
|
-
|
|
10010
|
-
|
|
10011
|
-
|
|
10012
|
-
|
|
10013
|
-
|
|
10014
|
-
|
|
10015
|
-
|
|
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
|
-
|
|
10025
|
-
|
|
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
|
-
|
|
10028
|
-
|
|
10029
|
-
|
|
10030
|
-
|
|
10031
|
-
|
|
10032
|
-
|
|
10033
|
-
|
|
10034
|
-
|
|
10035
|
-
|
|
10036
|
-
|
|
10037
|
-
|
|
10038
|
-
|
|
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
|
-
|
|
10042
|
-
|
|
10043
|
-
|
|
10044
|
-
|
|
10045
|
-
|
|
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
|
-
|
|
10061
|
-
|
|
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
|
-
|
|
10064
|
-
|
|
10065
|
-
|
|
10066
|
-
|
|
10067
|
-
|
|
10068
|
-
|
|
10069
|
-
|
|
10070
|
-
|
|
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
|
-
|
|
10073
|
-
}
|
|
10074
|
-
|
|
10075
|
-
|
|
10076
|
-
|
|
10077
|
-
|
|
10078
|
-
|
|
10079
|
-
|
|
10080
|
-
|
|
10081
|
-
|
|
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
|
-
|
|
10093
|
-
|
|
10094
|
-
|
|
10095
|
-
|
|
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
|
-
|
|
10100
|
-
|
|
10101
|
-
}
|
|
10102
|
-
getParticipantModel(name) {
|
|
10103
|
-
return this.participantModelsByName.get(name);
|
|
10146
|
+
exitParameters() {
|
|
10147
|
+
this.isBlind = false;
|
|
10104
10148
|
}
|
|
10105
|
-
|
|
10106
|
-
|
|
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
|
|
10124
|
-
|
|
10125
|
-
|
|
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
|
-
|
|
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
|
-
|
|
10136
|
-
|
|
10137
|
-
|
|
10138
|
-
|
|
10139
|
-
|
|
10140
|
-
|
|
10141
|
-
|
|
10142
|
-
|
|
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
|
-
|
|
10148
|
-
|
|
10149
|
-
|
|
10150
|
-
|
|
10151
|
-
|
|
10152
|
-
|
|
10153
|
-
|
|
10154
|
-
|
|
10155
|
-
|
|
10156
|
-
|
|
10157
|
-
|
|
10158
|
-
|
|
10159
|
-
|
|
10160
|
-
|
|
10161
|
-
|
|
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 =
|
|
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
|
-
|
|
10903
|
-
|
|
10904
|
-
|
|
10905
|
-
|
|
10906
|
-
|
|
10907
|
-
|
|
10908
|
-
|
|
10909
|
-
|
|
10910
|
-
|
|
10911
|
-
|
|
10912
|
-
|
|
10913
|
-
|
|
10914
|
-
|
|
10915
|
-
|
|
10916
|
-
|
|
10917
|
-
|
|
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
|
|
11031
|
-
}
|
|
11032
|
-
|
|
11033
|
-
|
|
11034
|
-
|
|
11035
|
-
|
|
11036
|
-
|
|
11037
|
-
|
|
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
|
-
|
|
11040
|
-
|
|
11041
|
-
const
|
|
11042
|
-
|
|
11043
|
-
)
|
|
11044
|
-
|
|
11045
|
-
|
|
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
|
-
|
|
11074
|
-
|
|
11075
|
-
|
|
11076
|
-
|
|
11077
|
-
|
|
11078
|
-
|
|
11079
|
-
|
|
11080
|
-
|
|
11081
|
-
|
|
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
|
-
|
|
11084
|
-
|
|
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
|
-
|
|
11091
|
-
|
|
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
|
-
|
|
11098
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
11815
|
-
|
|
11816
|
-
|
|
11817
|
-
|
|
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:
|
|
11821
|
-
|
|
11822
|
-
|
|
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
|
-
|
|
11829
|
-
|
|
11830
|
-
|
|
11831
|
-
|
|
11832
|
-
|
|
11833
|
-
|
|
11834
|
-
|
|
11835
|
-
|
|
11836
|
-
|
|
11837
|
-
|
|
11838
|
-
|
|
11839
|
-
|
|
11840
|
-
|
|
11841
|
-
|
|
11842
|
-
|
|
11843
|
-
|
|
11844
|
-
|
|
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
|
-
|
|
11880
|
-
|
|
11881
|
-
|
|
11882
|
-
|
|
11883
|
-
|
|
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
|
-
|
|
11902
|
-
|
|
11903
|
-
|
|
11904
|
-
|
|
11905
|
-
|
|
11906
|
-
|
|
11907
|
-
|
|
11908
|
-
|
|
11909
|
-
|
|
11910
|
-
|
|
11911
|
-
|
|
11912
|
-
|
|
11913
|
-
|
|
11914
|
-
|
|
11915
|
-
|
|
11916
|
-
|
|
11917
|
-
|
|
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
|
-
|
|
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
|
-
|
|
12642
|
-
|
|
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
|
-
|
|
12649
|
-
|
|
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
|
-
|
|
12656
|
-
|
|
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
|
-
|
|
12663
|
-
|
|
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
|
-
|
|
12670
|
-
|
|
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
|
-
|
|
12677
|
-
|
|
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-
|
|
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 =
|
|
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(
|
|
13446
|
+
pushFragment(
|
|
13447
|
+
`<tspan font-weight="bold">${collectLines(token.tokens || []).join("")}</tspan>`
|
|
13448
|
+
);
|
|
13317
13449
|
return;
|
|
13318
13450
|
case "em":
|
|
13319
|
-
pushFragment(
|
|
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
|
-
|
|
13752
|
-
|
|
13669
|
+
};
|
|
13670
|
+
function resolvePalette(theme) {
|
|
13671
|
+
if (theme && theme in THEME_PALETTES) {
|
|
13672
|
+
return THEME_PALETTES[theme];
|
|
13753
13673
|
}
|
|
13754
|
-
|
|
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
|
-
|
|
13805
|
-
|
|
13806
|
-
|
|
13807
|
-
|
|
13808
|
-
|
|
13809
|
-
}
|
|
13810
|
-
|
|
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
|
-
|
|
13864
|
-
|
|
13865
|
-
|
|
13866
|
-
|
|
13867
|
-
|
|
13868
|
-
|
|
13869
|
-
|
|
13870
|
-
|
|
13871
|
-
|
|
13872
|
-
|
|
13873
|
-
|
|
13874
|
-
|
|
13875
|
-
|
|
13876
|
-
|
|
13877
|
-
|
|
13878
|
-
|
|
13879
|
-
|
|
13880
|
-
|
|
13881
|
-
|
|
13882
|
-
|
|
13883
|
-
|
|
13884
|
-
|
|
13885
|
-
|
|
13886
|
-
|
|
13887
|
-
|
|
13888
|
-
|
|
13889
|
-
|
|
13890
|
-
|
|
13891
|
-
|
|
13892
|
-
|
|
13893
|
-
|
|
13894
|
-
|
|
13895
|
-
|
|
13896
|
-
|
|
13897
|
-
|
|
13898
|
-
|
|
13899
|
-
|
|
13900
|
-
|
|
13901
|
-
|
|
13902
|
-
|
|
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
|
|
13767
|
+
return safe;
|
|
13908
13768
|
}
|
|
13909
|
-
function
|
|
13910
|
-
|
|
13911
|
-
|
|
13912
|
-
|
|
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
|
-
|
|
13917
|
-
|
|
13918
|
-
|
|
13919
|
-
|
|
13920
|
-
|
|
13921
|
-
|
|
13922
|
-
|
|
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
|
-
|
|
13929
|
-
|
|
13930
|
-
|
|
13931
|
-
|
|
13932
|
-
|
|
13933
|
-
|
|
13934
|
-
|
|
13935
|
-
|
|
13936
|
-
|
|
13937
|
-
|
|
13938
|
-
|
|
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
|
-
|
|
14021
|
-
|
|
14022
|
-
|
|
14023
|
-
|
|
14024
|
-
|
|
14025
|
-
|
|
14026
|
-
|
|
14027
|
-
|
|
14028
|
-
|
|
14029
|
-
|
|
14030
|
-
|
|
14031
|
-
|
|
14032
|
-
|
|
14033
|
-
|
|
14034
|
-
|
|
14035
|
-
|
|
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
|
-
|
|
14061
|
-
|
|
14062
|
-
|
|
14063
|
-
|
|
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
|
-
|
|
14067
|
-
|
|
14068
|
-
|
|
14069
|
-
|
|
14070
|
-
|
|
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
|
-
|
|
14089
|
-
|
|
14090
|
-
|
|
14091
|
-
|
|
14092
|
-
|
|
14093
|
-
}
|
|
14094
|
-
|
|
14095
|
-
|
|
14096
|
-
|
|
14097
|
-
|
|
14098
|
-
|
|
14099
|
-
|
|
14100
|
-
|
|
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
|
|
14117
|
-
|
|
14118
|
-
|
|
14119
|
-
|
|
14120
|
-
|
|
14121
|
-
|
|
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
|
-
|
|
14134
|
-
|
|
14135
|
-
result.children = items.map((it) => it.node);
|
|
13867
|
+
for (const m of g.messages) {
|
|
13868
|
+
parts.push(renderMessage(m));
|
|
14136
13869
|
}
|
|
14137
|
-
|
|
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
|
-
|
|
14148
|
-
|
|
13873
|
+
for (const c of g.creations) {
|
|
13874
|
+
parts.push(renderCreation(c));
|
|
14149
13875
|
}
|
|
14150
|
-
const
|
|
14151
|
-
|
|
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
|
|
14159
|
-
|
|
14160
|
-
result.children = children.map((child) => serializeParseTree(child));
|
|
13879
|
+
for (const f of g.fragments) {
|
|
13880
|
+
parts.push(renderFragment(f));
|
|
14161
13881
|
}
|
|
14162
|
-
|
|
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
|
-
|
|
14165
|
-
|
|
14166
|
-
|
|
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
|
|
14169
|
-
|
|
14170
|
-
|
|
14171
|
-
|
|
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
|
|
14176
|
-
|
|
14177
|
-
let code;
|
|
13957
|
+
async function renderDiagram(code, settings, label, beforeEncode) {
|
|
13958
|
+
let result;
|
|
14178
13959
|
try {
|
|
14179
|
-
|
|
13960
|
+
await ensureDiagramIconsLoaded(code);
|
|
13961
|
+
result = renderToSvg(code, settings.renderOptions);
|
|
14180
13962
|
} catch (err) {
|
|
14181
|
-
|
|
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
|
-
|
|
14188
|
-
|
|
14189
|
-
|
|
14190
|
-
|
|
14191
|
-
|
|
14192
|
-
|
|
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
|
|
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
|
|
14216
|
-
const
|
|
14217
|
-
|
|
14218
|
-
|
|
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 ? "" : `})`;
|
|
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
|
|
14221
|
-
|
|
14222
|
-
|
|
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
|
|
14229
|
-
|
|
14073
|
+
await rf(input);
|
|
14074
|
+
logFn(`${ts} Rendered ${input} -> done`);
|
|
14230
14075
|
} catch (err) {
|
|
14231
|
-
|
|
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
|
|
14250
|
-
|
|
14251
|
-
|
|
14252
|
-
|
|
14253
|
-
|
|
14254
|
-
|
|
14255
|
-
|
|
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
|
-
|
|
14258
|
-
|
|
14259
|
-
|
|
14260
|
-
|
|
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
|
}
|