@zenuml/core 4.2.1 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/zenuml.mjs +594 -485
- package/dist/parser/index.cjs +2 -2
- package/dist/parser/index.mjs +1181 -1255
- package/dist/zenuml.esm.mjs +17916 -20381
- package/dist/zenuml.js +628 -756
- package/package.json +1 -13
- package/types/index.d.ts +24 -5
- package/types/svg.d.ts +0 -4
package/dist/cli/zenuml.mjs
CHANGED
|
@@ -9075,7 +9075,7 @@ ToCollector.enterRet = function (ctx) {
|
|
|
9075
9075
|
returnTo && participants.Add(returnTo);
|
|
9076
9076
|
};
|
|
9077
9077
|
|
|
9078
|
-
const walker$
|
|
9078
|
+
const walker$1 = antlr4.tree.ParseTreeWalker.DEFAULT;
|
|
9079
9079
|
|
|
9080
9080
|
// The walk is a pure function of the (immutable) parse tree and consumers only
|
|
9081
9081
|
// read the returned Participants, so results are cached per context node.
|
|
@@ -9086,80 +9086,11 @@ ToCollector.getParticipants = function (context) {
|
|
|
9086
9086
|
const cached = participantsCache.get(context);
|
|
9087
9087
|
if (cached) return cached;
|
|
9088
9088
|
participants = new Participants$1();
|
|
9089
|
-
walker$
|
|
9089
|
+
walker$1.walk(this, context);
|
|
9090
9090
|
participantsCache.set(context, participants);
|
|
9091
9091
|
return participants;
|
|
9092
9092
|
};
|
|
9093
9093
|
|
|
9094
|
-
const walker$1 = antlr4.tree.ParseTreeWalker.DEFAULT;
|
|
9095
|
-
|
|
9096
|
-
let ChildFragmentDetector = new sequenceParserListener();
|
|
9097
|
-
|
|
9098
|
-
let cursor = 0;
|
|
9099
|
-
let max = 0;
|
|
9100
|
-
|
|
9101
|
-
ChildFragmentDetector.enterTcf = function () {
|
|
9102
|
-
cursor++;
|
|
9103
|
-
};
|
|
9104
|
-
ChildFragmentDetector.enterOpt = function () {
|
|
9105
|
-
cursor++;
|
|
9106
|
-
};
|
|
9107
|
-
ChildFragmentDetector.enterPar = function () {
|
|
9108
|
-
cursor++;
|
|
9109
|
-
};
|
|
9110
|
-
ChildFragmentDetector.enterAlt = function () {
|
|
9111
|
-
cursor++;
|
|
9112
|
-
};
|
|
9113
|
-
ChildFragmentDetector.enterLoop = function () {
|
|
9114
|
-
cursor++;
|
|
9115
|
-
};
|
|
9116
|
-
ChildFragmentDetector.enterSection = function () {
|
|
9117
|
-
cursor++;
|
|
9118
|
-
};
|
|
9119
|
-
ChildFragmentDetector.enterCritical = function () {
|
|
9120
|
-
cursor++;
|
|
9121
|
-
};
|
|
9122
|
-
|
|
9123
|
-
ChildFragmentDetector.exitTcf = function () {
|
|
9124
|
-
max = Math.max(max, cursor);
|
|
9125
|
-
cursor--;
|
|
9126
|
-
};
|
|
9127
|
-
ChildFragmentDetector.exitOpt = function () {
|
|
9128
|
-
max = Math.max(max, cursor);
|
|
9129
|
-
cursor--;
|
|
9130
|
-
};
|
|
9131
|
-
ChildFragmentDetector.exitPar = function () {
|
|
9132
|
-
max = Math.max(max, cursor);
|
|
9133
|
-
cursor--;
|
|
9134
|
-
};
|
|
9135
|
-
ChildFragmentDetector.exitAlt = function () {
|
|
9136
|
-
max = Math.max(max, cursor);
|
|
9137
|
-
cursor--;
|
|
9138
|
-
};
|
|
9139
|
-
ChildFragmentDetector.exitLoop = function () {
|
|
9140
|
-
max = Math.max(max, cursor);
|
|
9141
|
-
cursor--;
|
|
9142
|
-
};
|
|
9143
|
-
ChildFragmentDetector.exitSection = function () {
|
|
9144
|
-
max = Math.max(max, cursor);
|
|
9145
|
-
cursor--;
|
|
9146
|
-
};
|
|
9147
|
-
ChildFragmentDetector.exitCritical = function () {
|
|
9148
|
-
max = Math.max(max, cursor);
|
|
9149
|
-
cursor--;
|
|
9150
|
-
};
|
|
9151
|
-
|
|
9152
|
-
ChildFragmentDetector.depth = function (me) {
|
|
9153
|
-
return function (context) {
|
|
9154
|
-
cursor = 0;
|
|
9155
|
-
max = 0;
|
|
9156
|
-
context.children.map(function (child) {
|
|
9157
|
-
walker$1.walk(me, child);
|
|
9158
|
-
});
|
|
9159
|
-
return max;
|
|
9160
|
-
};
|
|
9161
|
-
};
|
|
9162
|
-
|
|
9163
9094
|
const seqParser$9 = sequenceParser;
|
|
9164
9095
|
const TitleContext = seqParser$9.TitleContext;
|
|
9165
9096
|
TitleContext.prototype.content = function () {
|
|
@@ -9227,10 +9158,6 @@ CreationContext$6.prototype.Constructor = function () {
|
|
|
9227
9158
|
return this.creationBody()?.construct()?.getFormattedText();
|
|
9228
9159
|
};
|
|
9229
9160
|
|
|
9230
|
-
CreationContext$6.prototype.To = function () {
|
|
9231
|
-
return this.Constructor();
|
|
9232
|
-
};
|
|
9233
|
-
|
|
9234
9161
|
CreationContext$6.prototype.Owner = function () {
|
|
9235
9162
|
if (!this.Constructor()) {
|
|
9236
9163
|
return "Missing Constructor";
|
|
@@ -9245,10 +9172,6 @@ MessageContext$6.prototype.To = function () {
|
|
|
9245
9172
|
return toCtx?.name?.()?.getFormattedText() || toCtx?.getFormattedText();
|
|
9246
9173
|
};
|
|
9247
9174
|
|
|
9248
|
-
MessageContext$6.prototype.Owner = function () {
|
|
9249
|
-
return this.To() || getOwnerFromAncestor(this.parentCtx);
|
|
9250
|
-
};
|
|
9251
|
-
|
|
9252
9175
|
function getOwnerFromAncestor(ctx) {
|
|
9253
9176
|
while (ctx) {
|
|
9254
9177
|
if (ctx instanceof CreationContext$6 || ctx instanceof MessageContext$6) {
|
|
@@ -9259,32 +9182,39 @@ function getOwnerFromAncestor(ctx) {
|
|
|
9259
9182
|
return undefined;
|
|
9260
9183
|
}
|
|
9261
9184
|
|
|
9262
|
-
|
|
9263
|
-
|
|
9264
|
-
|
|
9265
|
-
|
|
9266
|
-
|
|
9267
|
-
|
|
9185
|
+
// MessageContext, AsyncMessageContext, ReturnAsyncMessageContext and
|
|
9186
|
+
// RetContext all resolve Owner the same way: prefer their own To(), else
|
|
9187
|
+
// look up the nearest CreationContext/MessageContext ancestor. Assigning
|
|
9188
|
+
// the same function to each prototype keeps the body single-sourced while
|
|
9189
|
+
// each context class still gets its own Owner property.
|
|
9190
|
+
function ownerFromToOrAncestor() {
|
|
9268
9191
|
return this.To() || getOwnerFromAncestor(this.parentCtx);
|
|
9269
|
-
}
|
|
9192
|
+
}
|
|
9193
|
+
|
|
9194
|
+
[
|
|
9195
|
+
MessageContext$6,
|
|
9196
|
+
AsyncMessageContext$2,
|
|
9197
|
+
ReturnAsyncMessageContext$2,
|
|
9198
|
+
RetMessageContext,
|
|
9199
|
+
].forEach((ContextClass) => {
|
|
9200
|
+
ContextClass.prototype.Owner = ownerFromToOrAncestor;
|
|
9201
|
+
});
|
|
9270
9202
|
|
|
9271
|
-
ReturnAsyncMessageContext
|
|
9203
|
+
// AsyncMessageContext and ReturnAsyncMessageContext resolve To() identically
|
|
9204
|
+
// (unlike MessageContext, which reaches its `to` node through
|
|
9205
|
+
// messageBody()?.fromTo(), and RetContext, which delegates to ReturnTo()).
|
|
9206
|
+
function toFromDirectTo() {
|
|
9272
9207
|
const toCtx = this.to();
|
|
9273
9208
|
return toCtx?.name?.()?.getFormattedText() || toCtx?.getFormattedText();
|
|
9274
|
-
}
|
|
9209
|
+
}
|
|
9275
9210
|
|
|
9276
|
-
|
|
9277
|
-
|
|
9278
|
-
};
|
|
9211
|
+
AsyncMessageContext$2.prototype.To = toFromDirectTo;
|
|
9212
|
+
ReturnAsyncMessageContext$2.prototype.To = toFromDirectTo;
|
|
9279
9213
|
|
|
9280
9214
|
RetMessageContext.prototype.To = function () {
|
|
9281
9215
|
return this.ReturnTo();
|
|
9282
9216
|
};
|
|
9283
9217
|
|
|
9284
|
-
RetMessageContext.prototype.Owner = function () {
|
|
9285
|
-
return this.To() || getOwnerFromAncestor(this.parentCtx);
|
|
9286
|
-
};
|
|
9287
|
-
|
|
9288
9218
|
const ProgContext$2 = sequenceParser.ProgContext;
|
|
9289
9219
|
|
|
9290
9220
|
/**
|
|
@@ -9397,11 +9327,7 @@ const MessageContext$4 = sequenceParser.MessageContext;
|
|
|
9397
9327
|
const CreationContext$4 = sequenceParser.CreationContext;
|
|
9398
9328
|
|
|
9399
9329
|
ParserRuleContext$1.prototype.Origin = function () {
|
|
9400
|
-
|
|
9401
|
-
while (ctx && !(ctx instanceof StatContext$2 || ctx instanceof ProgContext)) {
|
|
9402
|
-
ctx = this.parentCtx;
|
|
9403
|
-
}
|
|
9404
|
-
return ctx.Origin();
|
|
9330
|
+
return this.ClosestAncestorStat()?.Origin();
|
|
9405
9331
|
};
|
|
9406
9332
|
// Origin is essentially the 'from' of a message.
|
|
9407
9333
|
// For example, in `S -> A.m1 {B.m2 {C.m3}}`,
|
|
@@ -9482,9 +9408,6 @@ CreationContext$3.prototype.SignatureText = function() {
|
|
|
9482
9408
|
const text = this.ParametersText() || "create";
|
|
9483
9409
|
return `«${text}»`;
|
|
9484
9410
|
};
|
|
9485
|
-
CreationContext$3.prototype.isParamValid = function() {
|
|
9486
|
-
return (this.creationBody().parameters()?.parameter()?.length ?? 0) > 0;
|
|
9487
|
-
};
|
|
9488
9411
|
RetContext$1.prototype.SignatureText = function() {
|
|
9489
9412
|
return this.asyncMessage()?.content()?.getFormattedText() ?? this.returnAsyncMessage()?.content()?.getFormattedText() ?? this.expr()?.getFormattedText() ?? "";
|
|
9490
9413
|
};
|
|
@@ -9575,27 +9498,22 @@ CreationContext.prototype.From = function() {
|
|
|
9575
9498
|
}
|
|
9576
9499
|
return void 0;
|
|
9577
9500
|
};
|
|
9501
|
+
function fromProvidedOrOrigin() {
|
|
9502
|
+
return this.ProvidedFrom() || this.ClosestAncestorStat()?.Origin();
|
|
9503
|
+
}
|
|
9578
9504
|
MessageContext.prototype.ProvidedFrom = function() {
|
|
9579
9505
|
const fromCtx = this.messageBody()?.fromTo?.()?.from?.();
|
|
9580
9506
|
return fromCtx?.name?.()?.getFormattedText?.() || fromCtx?.getFormattedText?.();
|
|
9581
9507
|
};
|
|
9582
|
-
MessageContext.prototype.From =
|
|
9583
|
-
|
|
9584
|
-
};
|
|
9585
|
-
AsyncMessageContext.prototype.ProvidedFrom = function() {
|
|
9508
|
+
MessageContext.prototype.From = fromProvidedOrOrigin;
|
|
9509
|
+
function providedFromDirectFrom() {
|
|
9586
9510
|
const fromCtx = this.from();
|
|
9587
9511
|
return fromCtx?.name?.()?.getFormattedText?.() || fromCtx?.getFormattedText?.();
|
|
9588
|
-
}
|
|
9589
|
-
AsyncMessageContext.prototype.
|
|
9590
|
-
|
|
9591
|
-
|
|
9592
|
-
ReturnAsyncMessageContext.prototype.
|
|
9593
|
-
const fromCtx = this.from();
|
|
9594
|
-
return fromCtx?.name?.()?.getFormattedText?.() || fromCtx?.getFormattedText?.();
|
|
9595
|
-
};
|
|
9596
|
-
ReturnAsyncMessageContext.prototype.From = function() {
|
|
9597
|
-
return this.ProvidedFrom() || this.ClosestAncestorStat()?.Origin();
|
|
9598
|
-
};
|
|
9512
|
+
}
|
|
9513
|
+
AsyncMessageContext.prototype.ProvidedFrom = providedFromDirectFrom;
|
|
9514
|
+
AsyncMessageContext.prototype.From = fromProvidedOrOrigin;
|
|
9515
|
+
ReturnAsyncMessageContext.prototype.ProvidedFrom = providedFromDirectFrom;
|
|
9516
|
+
ReturnAsyncMessageContext.prototype.From = fromProvidedOrOrigin;
|
|
9599
9517
|
RetContext.prototype.From = function() {
|
|
9600
9518
|
return this.asyncMessage()?.From?.() || this.returnAsyncMessage()?.From?.() || this.ClosestAncestorStat()?.Origin();
|
|
9601
9519
|
};
|
|
@@ -9616,14 +9534,6 @@ ParserRuleContext.prototype.ClosestAncestorStat = function() {
|
|
|
9616
9534
|
}
|
|
9617
9535
|
return void 0;
|
|
9618
9536
|
};
|
|
9619
|
-
ParserRuleContext.prototype.ClosestAncestorBlock = function() {
|
|
9620
|
-
const parentCtx = this.ClosestAncestorStat()?.parentCtx;
|
|
9621
|
-
if (parentCtx instanceof seqParser.BlockContext) {
|
|
9622
|
-
return parentCtx;
|
|
9623
|
-
}
|
|
9624
|
-
console.warn("Cannot find closest ancestor block for context:", this);
|
|
9625
|
-
return void 0;
|
|
9626
|
-
};
|
|
9627
9537
|
|
|
9628
9538
|
antlr4.ParserRuleContext.prototype.getAncestors = function(predicate) {
|
|
9629
9539
|
const ancestors = [];
|
|
@@ -9642,11 +9552,9 @@ antlr4.ParserRuleContext.prototype.getAncestors = function(predicate) {
|
|
|
9642
9552
|
|
|
9643
9553
|
const formatText = (text) => text.replace(/[\n\r]/g, " ").replace(/\s+/g, " ").replace(/\s*([,;.])\s*/g, "$1").replace(/\s*(\()\s*|\s*(\))/g, "$1$2").replace(/\s+$/g, "").replace(/^"(.*)"$/, "$1");
|
|
9644
9554
|
|
|
9645
|
-
const errors = [];
|
|
9646
9555
|
const errorDetails = [];
|
|
9647
9556
|
class SeqErrorListener extends antlr4.error.ErrorListener {
|
|
9648
9557
|
syntaxError(recognizer, offendingSymbol, line, column, msg) {
|
|
9649
|
-
errors.push(`${offendingSymbol} line ${line}, col ${column}: ${msg}`);
|
|
9650
9558
|
errorDetails.push({
|
|
9651
9559
|
line,
|
|
9652
9560
|
column,
|
|
@@ -9656,7 +9564,7 @@ class SeqErrorListener extends antlr4.error.ErrorListener {
|
|
|
9656
9564
|
}
|
|
9657
9565
|
|
|
9658
9566
|
// Reentrant error listener: collects syntax errors into its OWN instance array
|
|
9659
|
-
// instead of the shared module-level `
|
|
9567
|
+
// instead of the shared module-level `errorDetails`. This is what lets
|
|
9660
9568
|
// validate()/parse() below run repeatedly or concurrently (e.g. server-side)
|
|
9661
9569
|
// without the clear-before/clear-after dance the legacy globals require.
|
|
9662
9570
|
class CollectingErrorListener extends antlr4.error.ErrorListener {
|
|
@@ -9716,7 +9624,7 @@ function rootContext(code) {
|
|
|
9716
9624
|
|
|
9717
9625
|
const parser = createParser(code);
|
|
9718
9626
|
parser.addErrorListener(new SeqErrorListener());
|
|
9719
|
-
return parser.
|
|
9627
|
+
return parser.prog();
|
|
9720
9628
|
}
|
|
9721
9629
|
|
|
9722
9630
|
antlr4.ParserRuleContext.prototype.getFormattedText = function () {
|
|
@@ -9747,7 +9655,7 @@ antlr4.ParserRuleContext.prototype.getComment = function () {
|
|
|
9747
9655
|
/**
|
|
9748
9656
|
* Parse ZenUML DSL with a per-call (reentrant) error listener and return both
|
|
9749
9657
|
* the error-recovered parse tree and a structured error list. Safe to call
|
|
9750
|
-
* repeatedly/concurrently — it does not touch the module-level
|
|
9658
|
+
* repeatedly/concurrently — it does not touch the module-level ErrorDetails.
|
|
9751
9659
|
*
|
|
9752
9660
|
* @param {string} code ZenUML DSL source
|
|
9753
9661
|
* @returns {{ rootContext: object, pass: boolean, errorDetails: { line: number, column: number, msg: string }[] }}
|
|
@@ -9801,15 +9709,7 @@ const Parser = {
|
|
|
9801
9709
|
},
|
|
9802
9710
|
parse,
|
|
9803
9711
|
validate,
|
|
9804
|
-
Errors: errors,
|
|
9805
9712
|
ErrorDetails: errorDetails,
|
|
9806
|
-
/**
|
|
9807
|
-
* @return {number} how many levels of embedded fragments
|
|
9808
|
-
*/
|
|
9809
|
-
Depth: function (ctx) {
|
|
9810
|
-
const childFragmentDetector = ChildFragmentDetector;
|
|
9811
|
-
return childFragmentDetector.depth(childFragmentDetector)(ctx);
|
|
9812
|
-
},
|
|
9813
9713
|
};
|
|
9814
9714
|
|
|
9815
9715
|
const FRAGMENT_PADDING_X = 10;
|
|
@@ -9956,39 +9856,6 @@ function OrderedParticipants(rootContext) {
|
|
|
9956
9856
|
return result;
|
|
9957
9857
|
}
|
|
9958
9858
|
|
|
9959
|
-
const LEVELS = ["log", "trace", "debug", "info", "warn", "error"];
|
|
9960
|
-
const LEVEL_WEIGHT = {
|
|
9961
|
-
trace: 10,
|
|
9962
|
-
debug: 20,
|
|
9963
|
-
log: 30,
|
|
9964
|
-
info: 30,
|
|
9965
|
-
warn: 40,
|
|
9966
|
-
error: 50
|
|
9967
|
-
};
|
|
9968
|
-
const THRESHOLD = LEVEL_WEIGHT.warn;
|
|
9969
|
-
function consoleFn(level) {
|
|
9970
|
-
const fn = console[level];
|
|
9971
|
-
return typeof fn === "function" ? fn.bind(console) : console.log.bind(console);
|
|
9972
|
-
}
|
|
9973
|
-
function createLogger(prefix) {
|
|
9974
|
-
const logger = {};
|
|
9975
|
-
for (const level of LEVELS) {
|
|
9976
|
-
const fn = consoleFn(level);
|
|
9977
|
-
logger[level] = (...args) => {
|
|
9978
|
-
if (LEVEL_WEIGHT[level] >= THRESHOLD) {
|
|
9979
|
-
if (prefix) {
|
|
9980
|
-
fn(prefix[0], prefix[1], ...args);
|
|
9981
|
-
} else {
|
|
9982
|
-
fn(...args);
|
|
9983
|
-
}
|
|
9984
|
-
}
|
|
9985
|
-
};
|
|
9986
|
-
}
|
|
9987
|
-
logger.child = (opts) => createLogger(["%c" + (opts.name || ""), "color: #00f"]);
|
|
9988
|
-
return logger;
|
|
9989
|
-
}
|
|
9990
|
-
const rootLogger = createLogger();
|
|
9991
|
-
|
|
9992
9859
|
function Dual(p, v) {
|
|
9993
9860
|
return { position: p, velocity: v };
|
|
9994
9861
|
}
|
|
@@ -10129,7 +9996,6 @@ class Coordinates {
|
|
|
10129
9996
|
}
|
|
10130
9997
|
const leftGap = this.getParticipantGap(this.participantModels[0]);
|
|
10131
9998
|
const position = leftGap + this.positionsCache[pIndex];
|
|
10132
|
-
rootLogger.debug(`Position of ${participantName} is ${position}`);
|
|
10133
9999
|
return position;
|
|
10134
10000
|
}
|
|
10135
10001
|
walkThrough() {
|
|
@@ -10176,17 +10042,11 @@ class Coordinates {
|
|
|
10176
10042
|
}
|
|
10177
10043
|
const leftIndex = Math.min(indexFrom, indexTo);
|
|
10178
10044
|
const rightIndex = Math.max(indexFrom, indexTo);
|
|
10179
|
-
|
|
10180
|
-
|
|
10181
|
-
|
|
10182
|
-
|
|
10183
|
-
|
|
10184
|
-
);
|
|
10185
|
-
} catch {
|
|
10186
|
-
console.warn(
|
|
10187
|
-
`Could not set message gap between ${from} and ${message.to}`
|
|
10188
|
-
);
|
|
10189
|
-
}
|
|
10045
|
+
const messageWidth = this.getMessageWidth(message);
|
|
10046
|
+
this.m[leftIndex][rightIndex] = Math.max(
|
|
10047
|
+
messageWidth + ARROW_HEAD_WIDTH + OCCURRENCE_WIDTH,
|
|
10048
|
+
this.m[leftIndex][rightIndex]
|
|
10049
|
+
);
|
|
10190
10050
|
}
|
|
10191
10051
|
}
|
|
10192
10052
|
withParticipantGaps(participantModels) {
|
|
@@ -10216,9 +10076,6 @@ class Coordinates {
|
|
|
10216
10076
|
);
|
|
10217
10077
|
const participantWidth = Math.max(labelWidth + iconWidth + emojiWidth, MIN_PARTICIPANT_WIDTH) + MARGIN;
|
|
10218
10078
|
this.participantWidthCache.set(participant.name, participantWidth);
|
|
10219
|
-
rootLogger.debug(
|
|
10220
|
-
`Width of ${participant.name} is ${participantWidth}; labelWidth: ${labelWidth}`
|
|
10221
|
-
);
|
|
10222
10079
|
return participantWidth;
|
|
10223
10080
|
}
|
|
10224
10081
|
}
|
|
@@ -10247,6 +10104,23 @@ class NodeVM {
|
|
|
10247
10104
|
}
|
|
10248
10105
|
}
|
|
10249
10106
|
|
|
10107
|
+
const SPACING_UNIT = 4;
|
|
10108
|
+
const tw = (value) => value * SPACING_UNIT;
|
|
10109
|
+
const DEFAULT_LAYOUT_METRICS = {
|
|
10110
|
+
statementMarginY: tw(4),
|
|
10111
|
+
// .statement-container .my-4
|
|
10112
|
+
fragmentHeaderHeight: 25,
|
|
10113
|
+
// .fragment .leading-4 => line-height: 1rem
|
|
10114
|
+
fragmentPaddingBottom: 10
|
|
10115
|
+
// .zenuml .fragment =>padding-bottom: 10px
|
|
10116
|
+
};
|
|
10117
|
+
const MESSAGE_HEIGHT = 16;
|
|
10118
|
+
const SELF_MESSAGE_HEIGHT = 30;
|
|
10119
|
+
const ASYNC_SELF_MESSAGE_HEIGHT = 44;
|
|
10120
|
+
const CREATION_MESSAGE_HEIGHT = 40;
|
|
10121
|
+
const COMMENT_LINE_HEIGHT = tw(5);
|
|
10122
|
+
const FRAGMENT_BORDER_WIDTH = 1;
|
|
10123
|
+
|
|
10250
10124
|
function getLocalParticipantNames(ctx) {
|
|
10251
10125
|
if (!ctx) return [];
|
|
10252
10126
|
return [ctx.Origin() || _STARTER_, ...Participants(ctx).Names()];
|
|
@@ -10677,7 +10551,7 @@ class MarkdownMeasurer {
|
|
|
10677
10551
|
return 0;
|
|
10678
10552
|
}
|
|
10679
10553
|
const lines = _text.trim().split("\n");
|
|
10680
|
-
return lines.length *
|
|
10554
|
+
return lines.length * COMMENT_LINE_HEIGHT;
|
|
10681
10555
|
}
|
|
10682
10556
|
}
|
|
10683
10557
|
|
|
@@ -10689,57 +10563,12 @@ class StatementVM extends NodeVM {
|
|
|
10689
10563
|
if (!context?.getComment || !context.getComment()) return 0;
|
|
10690
10564
|
return new MarkdownMeasurer().measure(context.getComment());
|
|
10691
10565
|
}
|
|
10692
|
-
resolveFragmentOrigin(fallbackOrigin) {
|
|
10693
|
-
try {
|
|
10694
|
-
const participants = getLocalParticipantNames(this.context) || [];
|
|
10695
|
-
return participants[0] || fallbackOrigin;
|
|
10696
|
-
} catch (error) {
|
|
10697
|
-
console.warn("Failed to resolve fragment origin", error);
|
|
10698
|
-
return fallbackOrigin;
|
|
10699
|
-
}
|
|
10700
|
-
}
|
|
10701
10566
|
findLeftParticipant(ctx, fallbackOrigin) {
|
|
10702
10567
|
if (!ctx) return void 0;
|
|
10703
10568
|
const local = getLocalParticipantNames(ctx) || [];
|
|
10704
10569
|
const ordered = this.runtime.participants;
|
|
10705
10570
|
return ordered.find((name) => local.includes(name)) || local[0] || fallbackOrigin || void 0;
|
|
10706
10571
|
}
|
|
10707
|
-
measureOccurrence(context, top, participant, minHeight = 24, contentInset = 1) {
|
|
10708
|
-
const block = context?.braceBlock?.()?.block?.();
|
|
10709
|
-
if (!block) {
|
|
10710
|
-
return minHeight;
|
|
10711
|
-
}
|
|
10712
|
-
const offset = this.metrics.statementMarginY - contentInset;
|
|
10713
|
-
const blockStart = top - offset;
|
|
10714
|
-
const blockEnd = this.layoutBlock(
|
|
10715
|
-
block,
|
|
10716
|
-
participant || this.runtime.originParticipant,
|
|
10717
|
-
blockStart
|
|
10718
|
-
);
|
|
10719
|
-
const height = blockEnd - blockStart - offset;
|
|
10720
|
-
return Math.max(minHeight, height);
|
|
10721
|
-
}
|
|
10722
|
-
isRootLevelStatement(statCtx) {
|
|
10723
|
-
const block = statCtx?.parentCtx;
|
|
10724
|
-
return block === this.runtime.rootBlock;
|
|
10725
|
-
}
|
|
10726
|
-
isFirstStatement(statCtx) {
|
|
10727
|
-
const block = statCtx?.parentCtx;
|
|
10728
|
-
const statements = block?.stat?.() || [];
|
|
10729
|
-
return statements.length > 0 && statements[0] === statCtx;
|
|
10730
|
-
}
|
|
10731
|
-
altHasMultipleBranches(ctx) {
|
|
10732
|
-
if (typeof ctx?.alt !== "function") {
|
|
10733
|
-
return false;
|
|
10734
|
-
}
|
|
10735
|
-
const altContext = ctx.alt();
|
|
10736
|
-
if (!altContext) {
|
|
10737
|
-
return false;
|
|
10738
|
-
}
|
|
10739
|
-
const elseIfBlocks = altContext?.elseIfBlock?.() || [];
|
|
10740
|
-
const hasElse = Boolean(altContext?.elseBlock?.());
|
|
10741
|
-
return elseIfBlocks.length > 0 || hasElse;
|
|
10742
|
-
}
|
|
10743
10572
|
}
|
|
10744
10573
|
|
|
10745
10574
|
class AsyncMessageStatementVM extends StatementVM {
|
|
@@ -10754,7 +10583,7 @@ class AsyncMessageStatementVM extends StatementVM {
|
|
|
10754
10583
|
const source = asyncContext?.From?.() || asyncContext?.ProvidedFrom?.() || asyncContext?.Origin?.() || origin;
|
|
10755
10584
|
const target = asyncContext?.Owner?.() || asyncContext?.to?.()?.getFormattedText?.() || source;
|
|
10756
10585
|
const isSelf = source === target;
|
|
10757
|
-
const messageHeight = isSelf ?
|
|
10586
|
+
const messageHeight = isSelf ? ASYNC_SELF_MESSAGE_HEIGHT : MESSAGE_HEIGHT;
|
|
10758
10587
|
return {
|
|
10759
10588
|
top,
|
|
10760
10589
|
height: commentHeight + messageHeight,
|
|
@@ -10763,7 +10592,6 @@ class AsyncMessageStatementVM extends StatementVM {
|
|
|
10763
10592
|
}
|
|
10764
10593
|
}
|
|
10765
10594
|
|
|
10766
|
-
const CREATION_MESSAGE_HEIGHT = 40;
|
|
10767
10595
|
class CreationStatementVM extends StatementVM {
|
|
10768
10596
|
constructor(statement, creation, runtime) {
|
|
10769
10597
|
super(statement, runtime);
|
|
@@ -10787,7 +10615,6 @@ class CreationStatementVM extends StatementVM {
|
|
|
10787
10615
|
}
|
|
10788
10616
|
const assignment = this.creation?.Assignment?.();
|
|
10789
10617
|
if (assignment) {
|
|
10790
|
-
rootLogger.info(`creation::assignment::${participant}`);
|
|
10791
10618
|
cursor += 12;
|
|
10792
10619
|
}
|
|
10793
10620
|
const height = cursor - top;
|
|
@@ -10813,26 +10640,7 @@ class EmptyStatementVM extends StatementVM {
|
|
|
10813
10640
|
}
|
|
10814
10641
|
}
|
|
10815
10642
|
|
|
10816
|
-
class
|
|
10817
|
-
beginFragment(context, top) {
|
|
10818
|
-
const commentHeight = this.measureComment(context);
|
|
10819
|
-
const headerHeight = this.metrics.fragmentHeaderHeight;
|
|
10820
|
-
return {
|
|
10821
|
-
cursor: top + commentHeight + headerHeight,
|
|
10822
|
-
commentHeight,
|
|
10823
|
-
headerHeight
|
|
10824
|
-
};
|
|
10825
|
-
}
|
|
10826
|
-
finalizeFragment(top, cursor) {
|
|
10827
|
-
cursor += this.metrics.fragmentPaddingBottom;
|
|
10828
|
-
return {
|
|
10829
|
-
top,
|
|
10830
|
-
height: cursor - top
|
|
10831
|
-
};
|
|
10832
|
-
}
|
|
10833
|
-
}
|
|
10834
|
-
|
|
10835
|
-
class FragmentAltVM extends FragmentVM {
|
|
10643
|
+
class FragmentAltVM extends StatementVM {
|
|
10836
10644
|
constructor(statement, alt, runtime) {
|
|
10837
10645
|
super(statement, runtime);
|
|
10838
10646
|
this.alt = alt;
|
|
@@ -10877,7 +10685,7 @@ class FragmentAltVM extends FragmentVM {
|
|
|
10877
10685
|
}
|
|
10878
10686
|
}
|
|
10879
10687
|
|
|
10880
|
-
class FragmentRefVM extends
|
|
10688
|
+
class FragmentRefVM extends StatementVM {
|
|
10881
10689
|
kind = "ref";
|
|
10882
10690
|
measure(top) {
|
|
10883
10691
|
const context = this.context?.ref?.() || this.context;
|
|
@@ -10888,7 +10696,7 @@ class FragmentRefVM extends FragmentVM {
|
|
|
10888
10696
|
}
|
|
10889
10697
|
}
|
|
10890
10698
|
|
|
10891
|
-
class FragmentSingleBlockVM extends
|
|
10699
|
+
class FragmentSingleBlockVM extends StatementVM {
|
|
10892
10700
|
constructor(statement, fragment, runtime, kind) {
|
|
10893
10701
|
super(statement, runtime);
|
|
10894
10702
|
this.fragment = fragment;
|
|
@@ -10896,7 +10704,7 @@ class FragmentSingleBlockVM extends FragmentVM {
|
|
|
10896
10704
|
}
|
|
10897
10705
|
measure(top, origin) {
|
|
10898
10706
|
const commentHeight = this.measureComment(this.fragment);
|
|
10899
|
-
let cursor = top +
|
|
10707
|
+
let cursor = top + FRAGMENT_BORDER_WIDTH + this.metrics.fragmentHeaderHeight + commentHeight;
|
|
10900
10708
|
const hasCondition = Boolean(this.fragment?.parExpr?.()?.condition?.());
|
|
10901
10709
|
if (hasCondition) cursor += 20;
|
|
10902
10710
|
const block = this.fragment?.braceBlock?.()?.block?.();
|
|
@@ -10904,7 +10712,7 @@ class FragmentSingleBlockVM extends FragmentVM {
|
|
|
10904
10712
|
const fragmentOrigin = this.findLeftParticipant(this.fragment, origin) || origin;
|
|
10905
10713
|
cursor = this.layoutBlock(block, fragmentOrigin, cursor, this.kind);
|
|
10906
10714
|
}
|
|
10907
|
-
cursor += this.metrics.fragmentPaddingBottom +
|
|
10715
|
+
cursor += this.metrics.fragmentPaddingBottom + FRAGMENT_BORDER_WIDTH;
|
|
10908
10716
|
return {
|
|
10909
10717
|
top,
|
|
10910
10718
|
height: cursor - top,
|
|
@@ -10913,7 +10721,7 @@ class FragmentSingleBlockVM extends FragmentVM {
|
|
|
10913
10721
|
}
|
|
10914
10722
|
}
|
|
10915
10723
|
|
|
10916
|
-
class FragmentTryCatchVM extends
|
|
10724
|
+
class FragmentTryCatchVM extends StatementVM {
|
|
10917
10725
|
constructor(statement, tcf, runtime) {
|
|
10918
10726
|
super(statement, runtime);
|
|
10919
10727
|
this.tcf = tcf;
|
|
@@ -10992,6 +10800,14 @@ class ReturnStatementVM extends StatementVM {
|
|
|
10992
10800
|
}
|
|
10993
10801
|
}
|
|
10994
10802
|
|
|
10803
|
+
const SINGLE_BLOCK_FRAGMENT_KINDS = [
|
|
10804
|
+
"loop",
|
|
10805
|
+
"opt",
|
|
10806
|
+
"par",
|
|
10807
|
+
"section",
|
|
10808
|
+
"critical"
|
|
10809
|
+
];
|
|
10810
|
+
|
|
10995
10811
|
class SyncMessageStatementVM extends StatementVM {
|
|
10996
10812
|
constructor(statement, message, runtime) {
|
|
10997
10813
|
super(statement, runtime);
|
|
@@ -11006,7 +10822,7 @@ class SyncMessageStatementVM extends StatementVM {
|
|
|
11006
10822
|
const block = this.message.braceBlock?.()?.block?.();
|
|
11007
10823
|
const assignee = this.message.Assignment?.();
|
|
11008
10824
|
const isSelf = source === target;
|
|
11009
|
-
const messageHeight = isSelf ?
|
|
10825
|
+
const messageHeight = isSelf ? SELF_MESSAGE_HEIGHT : MESSAGE_HEIGHT;
|
|
11010
10826
|
cursor += messageHeight;
|
|
11011
10827
|
if (block) {
|
|
11012
10828
|
const fragmentOrigin = this.findLeftParticipant(this.message, origin) || origin;
|
|
@@ -11042,7 +10858,7 @@ const createStatementVM = (statement, runtime) => {
|
|
|
11042
10858
|
if (statement.divider?.()) {
|
|
11043
10859
|
return new DividerStatementVM(statement, runtime);
|
|
11044
10860
|
}
|
|
11045
|
-
for (const kind of
|
|
10861
|
+
for (const kind of SINGLE_BLOCK_FRAGMENT_KINDS) {
|
|
11046
10862
|
const fragment = statement[kind]?.();
|
|
11047
10863
|
if (fragment) {
|
|
11048
10864
|
return new FragmentSingleBlockVM(statement, fragment, runtime, kind);
|
|
@@ -11083,17 +10899,6 @@ class BlockVM extends NodeVM {
|
|
|
11083
10899
|
}
|
|
11084
10900
|
}
|
|
11085
10901
|
|
|
11086
|
-
const SPACING_UNIT = 4;
|
|
11087
|
-
const tw = (value) => value * SPACING_UNIT;
|
|
11088
|
-
const DEFAULT_LAYOUT_METRICS = {
|
|
11089
|
-
statementMarginY: tw(4),
|
|
11090
|
-
// .statement-container .my-4
|
|
11091
|
-
fragmentHeaderHeight: 25,
|
|
11092
|
-
// .fragment .leading-4 => line-height: 1rem
|
|
11093
|
-
fragmentPaddingBottom: 10
|
|
11094
|
-
// .zenuml .fragment =>padding-bottom: 10px
|
|
11095
|
-
};
|
|
11096
|
-
|
|
11097
10902
|
class VerticalCoordinates {
|
|
11098
10903
|
statementMap = /* @__PURE__ */ new Map();
|
|
11099
10904
|
creationTops = /* @__PURE__ */ new Map();
|
|
@@ -11105,16 +10910,13 @@ class VerticalCoordinates {
|
|
|
11105
10910
|
const originParticipant = messages.length === 0 ? _STARTER_ : messages[0].from || _STARTER_;
|
|
11106
10911
|
const runtime = {
|
|
11107
10912
|
metrics: DEFAULT_LAYOUT_METRICS,
|
|
11108
|
-
rootBlock,
|
|
11109
10913
|
participants,
|
|
11110
|
-
originParticipant,
|
|
11111
10914
|
recordCoordinate: (statement, coordinate) => {
|
|
11112
10915
|
const key = createStatementKey(statement);
|
|
11113
10916
|
this.statementMap.set(key, coordinate);
|
|
11114
10917
|
},
|
|
11115
10918
|
updateCreationTop: (participant, top) => {
|
|
11116
10919
|
const paddingTop = top - 8;
|
|
11117
|
-
rootLogger.info(`[VerticalCoordinates] updateCreationTop participant="${participant}" raw=${top} paddingTop=${paddingTop}`);
|
|
11118
10920
|
this.creationTops.set(participant, paddingTop);
|
|
11119
10921
|
}
|
|
11120
10922
|
};
|
|
@@ -11127,19 +10929,13 @@ class VerticalCoordinates {
|
|
|
11127
10929
|
getStatementCoordinate(key) {
|
|
11128
10930
|
return this.statementMap.get(key);
|
|
11129
10931
|
}
|
|
11130
|
-
getStatementCoordinateFor(statement) {
|
|
11131
|
-
return this.statementMap.get(createStatementKey(statement));
|
|
11132
|
-
}
|
|
11133
|
-
entries() {
|
|
11134
|
-
return Array.from(this.statementMap.entries());
|
|
11135
|
-
}
|
|
11136
10932
|
getTotalHeight() {
|
|
11137
10933
|
return this.totalHeight;
|
|
11138
10934
|
}
|
|
11139
10935
|
}
|
|
11140
10936
|
|
|
11141
10937
|
let dic = {};
|
|
11142
|
-
|
|
10938
|
+
let persistDic = {};
|
|
11143
10939
|
const getCache = (key) => {
|
|
11144
10940
|
if (key != null) {
|
|
11145
10941
|
const cacheValue = dic[key] ?? persistDic[key];
|
|
@@ -11153,6 +10949,10 @@ const setCache = (key, value, persist = false) => {
|
|
|
11153
10949
|
persistDic[key] = value;
|
|
11154
10950
|
}
|
|
11155
10951
|
};
|
|
10952
|
+
const clearPersistentCache = () => {
|
|
10953
|
+
persistDic = {};
|
|
10954
|
+
dic = {};
|
|
10955
|
+
};
|
|
11156
10956
|
|
|
11157
10957
|
const FONT_FAMILY = "Helvetica, Verdana, serif";
|
|
11158
10958
|
const FONT_SIZE_PARTICIPANT = "16px";
|
|
@@ -11162,28 +10962,25 @@ function getFontSpec() {
|
|
|
11162
10962
|
}
|
|
11163
10963
|
let canvasCtx = null;
|
|
11164
10964
|
function setCanvasContext(ctx) {
|
|
10965
|
+
if (ctx === canvasCtx) return;
|
|
11165
10966
|
canvasCtx = ctx;
|
|
10967
|
+
clearPersistentCache();
|
|
11166
10968
|
}
|
|
11167
10969
|
function getCanvasContext() {
|
|
11168
10970
|
if (canvasCtx) return canvasCtx;
|
|
11169
10971
|
try {
|
|
11170
10972
|
if (typeof OffscreenCanvas !== "undefined") {
|
|
11171
10973
|
canvasCtx = new OffscreenCanvas(1, 1).getContext("2d");
|
|
11172
|
-
rootLogger.debug("[ZenUML] WidthProviderOnCanvas: using OffscreenCanvas");
|
|
11173
10974
|
} else if (typeof document !== "undefined") {
|
|
11174
10975
|
canvasCtx = document.createElement("canvas").getContext("2d");
|
|
11175
|
-
rootLogger.debug("[ZenUML] WidthProviderOnCanvas: using <canvas> element");
|
|
11176
|
-
} else {
|
|
11177
|
-
rootLogger.debug("[ZenUML] WidthProviderOnCanvas: no canvas available, using character estimate fallback");
|
|
11178
10976
|
}
|
|
11179
10977
|
} catch {
|
|
11180
|
-
rootLogger.debug("[ZenUML] WidthProviderOnCanvas: canvas creation failed, using character estimate fallback");
|
|
11181
10978
|
}
|
|
11182
10979
|
return canvasCtx;
|
|
11183
10980
|
}
|
|
11184
10981
|
function WidthProviderOnCanvas(text, type) {
|
|
11185
10982
|
const measured = text.trim();
|
|
11186
|
-
const cacheKey = `WidthProviderOnCanvas_${measured}_${type}`;
|
|
10983
|
+
const cacheKey = `WidthProviderOnCanvas_${getFontSpec()}_${measured}_${type}`;
|
|
11187
10984
|
const cacheValue = getCache(cacheKey);
|
|
11188
10985
|
if (cacheValue != null) {
|
|
11189
10986
|
return cacheValue;
|
|
@@ -11191,7 +10988,7 @@ function WidthProviderOnCanvas(text, type) {
|
|
|
11191
10988
|
const ctx = getCanvasContext();
|
|
11192
10989
|
if (!ctx) {
|
|
11193
10990
|
const width2 = Math.ceil(measured.length * 16 * 0.6);
|
|
11194
|
-
setCache(cacheKey, width2
|
|
10991
|
+
setCache(cacheKey, width2);
|
|
11195
10992
|
return width2;
|
|
11196
10993
|
}
|
|
11197
10994
|
ctx.font = getFontSpec();
|
|
@@ -11199,7 +10996,10 @@ function WidthProviderOnCanvas(text, type) {
|
|
|
11199
10996
|
setCache(cacheKey, width, true);
|
|
11200
10997
|
return width;
|
|
11201
10998
|
}
|
|
11202
|
-
const EMOJI_PATTERN =
|
|
10999
|
+
const EMOJI_PATTERN = (
|
|
11000
|
+
// eslint-disable-next-line no-misleading-character-class
|
|
11001
|
+
/[\u{1F300}-\u{1FAFF}\u{2600}-\u{27BF}\u{FE00}-\u{FE0F}\u{200D}]/u
|
|
11002
|
+
);
|
|
11203
11003
|
function measureWithSvg(text, fontSize) {
|
|
11204
11004
|
if (typeof document === "undefined") return null;
|
|
11205
11005
|
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
@@ -11218,7 +11018,8 @@ function measureTextWithFont(text, fontSize) {
|
|
|
11218
11018
|
const measured = text.trim();
|
|
11219
11019
|
if (!measured) return 0;
|
|
11220
11020
|
const hasEmoji = EMOJI_PATTERN.test(measured);
|
|
11221
|
-
const
|
|
11021
|
+
const font = `${fontSize} ${FONT_FAMILY}`;
|
|
11022
|
+
const cacheKey = hasEmoji ? `measureTextWithFont_svg_${font}_${measured}` : `measureTextWithFont_${font}_${measured}`;
|
|
11222
11023
|
const cacheValue = getCache(cacheKey);
|
|
11223
11024
|
if (cacheValue != null) {
|
|
11224
11025
|
return cacheValue;
|
|
@@ -11234,10 +11035,10 @@ function measureTextWithFont(text, fontSize) {
|
|
|
11234
11035
|
if (!ctx) {
|
|
11235
11036
|
const px = Number.parseFloat(fontSize) || 14;
|
|
11236
11037
|
const width2 = Math.ceil(measured.length * px * 0.6);
|
|
11237
|
-
setCache(cacheKey, width2
|
|
11038
|
+
setCache(cacheKey, width2);
|
|
11238
11039
|
return width2;
|
|
11239
11040
|
}
|
|
11240
|
-
ctx.font =
|
|
11041
|
+
ctx.font = font;
|
|
11241
11042
|
const width = ctx.measureText(measured).width;
|
|
11242
11043
|
setCache(cacheKey, width, true);
|
|
11243
11044
|
return width;
|
|
@@ -11358,22 +11159,42 @@ function FrameBorder(frame) {
|
|
|
11358
11159
|
return { left: 0, right: 0 };
|
|
11359
11160
|
}
|
|
11360
11161
|
return {
|
|
11361
|
-
type: frame.type,
|
|
11362
11162
|
left: FRAGMENT_PADDING_X * longestPath(frame, "LEFT" /* LEFT */),
|
|
11363
11163
|
right: FRAGMENT_PADDING_X * longestPath(frame, "RIGHT" /* RIGHT */)
|
|
11364
11164
|
};
|
|
11365
11165
|
}
|
|
11366
11166
|
|
|
11167
|
+
function TotalWidth(ctx, coordinates) {
|
|
11168
|
+
const allParticipants = coordinates.orderedParticipantNames();
|
|
11169
|
+
if (!ctx || allParticipants.length === 0) return 0;
|
|
11170
|
+
const localParticipants = getLocalParticipantNames(ctx);
|
|
11171
|
+
const leftParticipant = allParticipants.find((p) => localParticipants.includes(p)) || "";
|
|
11172
|
+
const rightParticipant = allParticipants.slice().reverse().find((p) => localParticipants.includes(p)) || "";
|
|
11173
|
+
const frameBuilder = new FrameBuilder(allParticipants);
|
|
11174
|
+
const frame = frameBuilder.getFrame(ctx);
|
|
11175
|
+
const border = FrameBorder(frame);
|
|
11176
|
+
const extraWidth = extraWidthDueToSelfMessage(
|
|
11177
|
+
ctx,
|
|
11178
|
+
rightParticipant,
|
|
11179
|
+
coordinates
|
|
11180
|
+
);
|
|
11181
|
+
const participantWidth = coordinates.distance(leftParticipant, rightParticipant) + coordinates.half(leftParticipant) + coordinates.half(rightParticipant);
|
|
11182
|
+
return Math.max(participantWidth, FRAGMENT_MIN_WIDTH) + border.left + border.right + extraWidth;
|
|
11183
|
+
}
|
|
11184
|
+
function extraWidthDueToSelfMessage(ctx, rightParticipant, coordinates) {
|
|
11185
|
+
const allMessages = AllMessages(ctx);
|
|
11186
|
+
const widths = allMessages.filter((m) => m.from === m.to).map(
|
|
11187
|
+
(m) => coordinates.getMessageWidth(m) - coordinates.distance(m.from || _STARTER_, rightParticipant) - coordinates.half(rightParticipant)
|
|
11188
|
+
);
|
|
11189
|
+
return Math.max.apply(null, [0, ...widths]);
|
|
11190
|
+
}
|
|
11191
|
+
|
|
11367
11192
|
const PARTICIPANT_TOP_SPACE = PARTICIPANT_TOP_SPACE_FOR_GROUP + 8;
|
|
11368
11193
|
const PARTICIPANT_BOX_PADDING = 16;
|
|
11369
|
-
const PARTICIPANT_BOX_PADDING_ASSIGNEE = 16;
|
|
11370
11194
|
const PARTICIPANT_ICON_ROW_WIDTH = 28;
|
|
11371
11195
|
const PARTICIPANT_EMOJI_WIDTH = 20;
|
|
11372
11196
|
const PARTICIPANT_VISUAL_HEIGHT = 40;
|
|
11373
11197
|
const PARTICIPANT_MAX_WIDTH = 250;
|
|
11374
|
-
function snapX$1(x) {
|
|
11375
|
-
return x;
|
|
11376
|
-
}
|
|
11377
11198
|
function cssToSvgStyle(css) {
|
|
11378
11199
|
const result = {};
|
|
11379
11200
|
let hasKeys = false;
|
|
@@ -11392,24 +11213,32 @@ function cssToSvgStyle(css) {
|
|
|
11392
11213
|
|
|
11393
11214
|
function buildParticipants(models, coordinates, verticalCoordinates, measureText) {
|
|
11394
11215
|
return models.map((m) => {
|
|
11395
|
-
const centerX =
|
|
11216
|
+
const centerX = coordinates.getPosition(m.name);
|
|
11396
11217
|
const halfWidth = coordinates.half(m.name);
|
|
11397
|
-
const isAssignee = m.name.includes(":") && m.getDisplayName() === m.name;
|
|
11398
11218
|
let width;
|
|
11399
11219
|
let measuredTextWidth;
|
|
11400
11220
|
let measuredStereotypeWidth;
|
|
11401
11221
|
if (measureText && m.name !== _STARTER_) {
|
|
11402
11222
|
const textWidth = measureSvgParticipantLabelWidth(m.getDisplayName());
|
|
11403
11223
|
measuredTextWidth = textWidth;
|
|
11404
|
-
const padding =
|
|
11224
|
+
const padding = PARTICIPANT_BOX_PADDING;
|
|
11405
11225
|
const iconWidth = m.hasIcon() ? PARTICIPANT_ICON_ROW_WIDTH : 0;
|
|
11406
11226
|
const emojiWidth = m.emoji ? PARTICIPANT_EMOJI_WIDTH : 0;
|
|
11407
11227
|
const STEREOTYPE_BOX_OVERHEAD = 8;
|
|
11408
11228
|
if (m.stereotype) {
|
|
11409
|
-
measuredStereotypeWidth = measureSvgParticipantLabelWidth(
|
|
11229
|
+
measuredStereotypeWidth = measureSvgParticipantLabelWidth(
|
|
11230
|
+
`«${m.stereotype}»`
|
|
11231
|
+
);
|
|
11410
11232
|
}
|
|
11411
11233
|
const stereotypeBoxWidth = measuredStereotypeWidth != null ? measuredStereotypeWidth + STEREOTYPE_BOX_OVERHEAD : 0;
|
|
11412
|
-
width = Math.min(
|
|
11234
|
+
width = Math.min(
|
|
11235
|
+
Math.max(
|
|
11236
|
+
textWidth + padding + iconWidth + emojiWidth,
|
|
11237
|
+
stereotypeBoxWidth,
|
|
11238
|
+
MIN_PARTICIPANT_WIDTH
|
|
11239
|
+
),
|
|
11240
|
+
PARTICIPANT_MAX_WIDTH
|
|
11241
|
+
);
|
|
11413
11242
|
} else {
|
|
11414
11243
|
width = Math.min(halfWidth * 2 - MARGIN, PARTICIPANT_MAX_WIDTH);
|
|
11415
11244
|
}
|
|
@@ -11488,39 +11317,49 @@ function buildGroups(participants, diagramHeight) {
|
|
|
11488
11317
|
return groups;
|
|
11489
11318
|
}
|
|
11490
11319
|
|
|
11491
|
-
|
|
11492
|
-
|
|
11320
|
+
class Anchor2 {
|
|
11321
|
+
constructor(position, layers) {
|
|
11322
|
+
this.position = position;
|
|
11323
|
+
this.layers = layers;
|
|
11324
|
+
}
|
|
11325
|
+
/**
|
|
11326
|
+
* centerToEdge is used for translateX calculations.
|
|
11327
|
+
*/
|
|
11328
|
+
centerToEdge(other) {
|
|
11329
|
+
return other.rightEdgeOfRightWall() - this.centerOfRightWall();
|
|
11330
|
+
}
|
|
11331
|
+
centerToCenter(other) {
|
|
11332
|
+
return other.centerOfRightWall() - this.centerOfRightWall();
|
|
11333
|
+
}
|
|
11334
|
+
/**
|
|
11335
|
+
* edgeOffset is used for interactionWidth calculations.
|
|
11336
|
+
*/
|
|
11337
|
+
edgeOffset(other) {
|
|
11338
|
+
const isRightToLeft = other.position < this.position;
|
|
11339
|
+
const rightEdgeOfLeftAnchor = isRightToLeft ? other.rightEdgeOfRightWall() : this.rightEdgeOfRightWall();
|
|
11340
|
+
const leftEdgeOfRightAnchor = isRightToLeft ? this.leftEdgeOfRightWall() : other.leftEdgeOfRightWall();
|
|
11341
|
+
const distance = leftEdgeOfRightAnchor - rightEdgeOfLeftAnchor - LIFELINE_WIDTH;
|
|
11342
|
+
return isRightToLeft ? distance * -1 : distance;
|
|
11343
|
+
}
|
|
11344
|
+
centerOfRightWall() {
|
|
11345
|
+
return this.layers <= 1 ? this.position : this.position + OCCURRENCE_BAR_SIDE_WIDTH * (this.layers - 1);
|
|
11346
|
+
}
|
|
11347
|
+
rightEdgeOfRightWall() {
|
|
11348
|
+
return this.position + OCCURRENCE_BAR_SIDE_WIDTH * this.layers;
|
|
11349
|
+
}
|
|
11350
|
+
leftEdgeOfRightWall() {
|
|
11351
|
+
return this.layers === 0 ? this.position : this.centerOfRightWall() - OCCURRENCE_BAR_SIDE_WIDTH;
|
|
11352
|
+
}
|
|
11493
11353
|
}
|
|
11354
|
+
|
|
11494
11355
|
const COMMENT_FONT_ASCENT = 15;
|
|
11495
11356
|
function buildFragmentGeometry(info, coord, coordinates, verticalCoordinates, allParticipants, _measureText, commentHeight = 0, commentText, commentStyle, commentYBase) {
|
|
11496
11357
|
const statNode = info.statNode;
|
|
11497
|
-
if (!statNode) return null;
|
|
11498
11358
|
const fragmentCtx = findFragmentContext(statNode);
|
|
11499
|
-
|
|
11500
|
-
|
|
11501
|
-
|
|
11502
|
-
|
|
11503
|
-
label: info.fragmentLabel || "",
|
|
11504
|
-
labelWidth: info.fragmentLabel ? measureSvgFragmentLabelWidth(resolveEmojiInText(info.fragmentLabel)) : void 0,
|
|
11505
|
-
x: 0,
|
|
11506
|
-
y: coord.top,
|
|
11507
|
-
width: coordinates.getWidth(),
|
|
11508
|
-
height: coord.height,
|
|
11509
|
-
headerY: coord.top + 1 + commentHeight,
|
|
11510
|
-
sections: [],
|
|
11511
|
-
number: info.number,
|
|
11512
|
-
depth: info.depth
|
|
11513
|
-
},
|
|
11514
|
-
comment: commentText && commentYBase != null ? {
|
|
11515
|
-
x: 1,
|
|
11516
|
-
y: commentYBase + 1 + COMMENT_FONT_ASCENT,
|
|
11517
|
-
text: commentText,
|
|
11518
|
-
style: commentStyle,
|
|
11519
|
-
fragmentComment: true
|
|
11520
|
-
} : void 0
|
|
11521
|
-
};
|
|
11522
|
-
}
|
|
11523
|
-
const localNames = getDeepParticipantNames(fragmentCtx, info.fragmentSections);
|
|
11359
|
+
const localNames = getDeepParticipantNames(
|
|
11360
|
+
fragmentCtx,
|
|
11361
|
+
info.fragmentSections
|
|
11362
|
+
);
|
|
11524
11363
|
const leftParticipant = allParticipants.find((p) => localNames.includes(p)) || "";
|
|
11525
11364
|
const rightParticipant = allParticipants.slice().reverse().find((p) => localNames.includes(p)) || "";
|
|
11526
11365
|
const frameBuilder = new FrameBuilder(allParticipants);
|
|
@@ -11529,14 +11368,8 @@ function buildFragmentGeometry(info, coord, coordinates, verticalCoordinates, al
|
|
|
11529
11368
|
let fragWidth;
|
|
11530
11369
|
let fragX;
|
|
11531
11370
|
if (leftParticipant && rightParticipant) {
|
|
11532
|
-
|
|
11533
|
-
|
|
11534
|
-
const extraWidths = selfMessages.map(
|
|
11535
|
-
(m) => coordinates.getMessageWidth(m) - coordinates.distance(m.from || _STARTER_, rightParticipant) - coordinates.half(rightParticipant)
|
|
11536
|
-
);
|
|
11537
|
-
const extraWidth = Math.max(0, ...extraWidths);
|
|
11538
|
-
fragWidth = Math.max(participantWidth, FRAGMENT_MIN_WIDTH) + fragBorder.left + fragBorder.right + extraWidth;
|
|
11539
|
-
fragX = snapX(coordinates.getPosition(leftParticipant)) - coordinates.half(leftParticipant);
|
|
11371
|
+
fragWidth = TotalWidth(statNode, coordinates);
|
|
11372
|
+
fragX = coordinates.getPosition(leftParticipant) - coordinates.half(leftParticipant);
|
|
11540
11373
|
} else {
|
|
11541
11374
|
fragWidth = Math.max(FRAGMENT_MIN_WIDTH, coordinates.getWidth());
|
|
11542
11375
|
fragX = 0;
|
|
@@ -11551,7 +11384,7 @@ function buildFragmentGeometry(info, coord, coordinates, verticalCoordinates, al
|
|
|
11551
11384
|
if (sectionBlock) {
|
|
11552
11385
|
const innerStats = sectionBlock.stat?.() || [];
|
|
11553
11386
|
if (innerStats.length > 0) {
|
|
11554
|
-
const firstStatKey =
|
|
11387
|
+
const firstStatKey = createStatementKey(innerStats[0]);
|
|
11555
11388
|
if (firstStatKey) {
|
|
11556
11389
|
const innerCoord = verticalCoordinates.getStatementCoordinate(firstStatKey);
|
|
11557
11390
|
if (innerCoord) {
|
|
@@ -11568,7 +11401,9 @@ function buildFragmentGeometry(info, coord, coordinates, verticalCoordinates, al
|
|
|
11568
11401
|
height: sectionHeight,
|
|
11569
11402
|
labelWidth: section.label ? measureSvgFragmentLabelWidth(resolveEmojiInText(section.label)) : void 0,
|
|
11570
11403
|
innerLabel: /^\[\s*.*\s*\]$/.test(section.label) ? section.label.slice(1, -1).trim() : void 0,
|
|
11571
|
-
innerLabelWidth: /^\[\s*.*\s*\]$/.test(section.label) ? measureSvgFragmentLabelWidth(
|
|
11404
|
+
innerLabelWidth: /^\[\s*.*\s*\]$/.test(section.label) ? measureSvgFragmentLabelWidth(
|
|
11405
|
+
resolveEmojiInText(section.label.slice(1, -1).trim())
|
|
11406
|
+
) : void 0,
|
|
11572
11407
|
keyword: (() => {
|
|
11573
11408
|
const spaceIdx = section.label.indexOf(" ");
|
|
11574
11409
|
if (spaceIdx > 0 && !section.label.startsWith("finally") && !section.label.startsWith("[")) {
|
|
@@ -11579,7 +11414,9 @@ function buildFragmentGeometry(info, coord, coordinates, verticalCoordinates, al
|
|
|
11579
11414
|
keywordWidth: (() => {
|
|
11580
11415
|
const spaceIdx = section.label.indexOf(" ");
|
|
11581
11416
|
if (spaceIdx > 0 && !section.label.startsWith("finally") && !section.label.startsWith("[")) {
|
|
11582
|
-
return measureSvgFragmentLabelWidth(
|
|
11417
|
+
return measureSvgFragmentLabelWidth(
|
|
11418
|
+
section.label.substring(0, spaceIdx)
|
|
11419
|
+
);
|
|
11583
11420
|
}
|
|
11584
11421
|
return void 0;
|
|
11585
11422
|
})(),
|
|
@@ -11593,7 +11430,9 @@ function buildFragmentGeometry(info, coord, coordinates, verticalCoordinates, al
|
|
|
11593
11430
|
detailWidth: (() => {
|
|
11594
11431
|
const spaceIdx = section.label.indexOf(" ");
|
|
11595
11432
|
if (spaceIdx > 0 && !section.label.startsWith("finally") && !section.label.startsWith("[")) {
|
|
11596
|
-
return measureSvgFragmentLabelWidth(
|
|
11433
|
+
return measureSvgFragmentLabelWidth(
|
|
11434
|
+
section.label.substring(spaceIdx + 1)
|
|
11435
|
+
);
|
|
11597
11436
|
}
|
|
11598
11437
|
return void 0;
|
|
11599
11438
|
})()
|
|
@@ -11606,7 +11445,7 @@ function buildFragmentGeometry(info, coord, coordinates, verticalCoordinates, al
|
|
|
11606
11445
|
if (innerStats.length > 1) {
|
|
11607
11446
|
sections.push({ label: "", y: coord.top, height: 0 });
|
|
11608
11447
|
for (let i = 1; i < innerStats.length; i++) {
|
|
11609
|
-
const statKey =
|
|
11448
|
+
const statKey = createStatementKey(innerStats[i]);
|
|
11610
11449
|
if (!statKey) continue;
|
|
11611
11450
|
const innerCoord = verticalCoordinates.getStatementCoordinate(statKey);
|
|
11612
11451
|
if (!innerCoord) continue;
|
|
@@ -11639,7 +11478,9 @@ function buildFragmentGeometry(info, coord, coordinates, verticalCoordinates, al
|
|
|
11639
11478
|
y: coord.top,
|
|
11640
11479
|
width: fragWidth,
|
|
11641
11480
|
height: coord.height,
|
|
11642
|
-
|
|
11481
|
+
// The header sits just inside the fragment's 1px top border, below any
|
|
11482
|
+
// inline comment — the same offset FragmentSingleBlockVM.measure() applies.
|
|
11483
|
+
headerY: coord.top + FRAGMENT_BORDER_WIDTH + commentHeight,
|
|
11643
11484
|
sections,
|
|
11644
11485
|
number: info.number,
|
|
11645
11486
|
depth: info.depth
|
|
@@ -11648,7 +11489,7 @@ function buildFragmentGeometry(info, coord, coordinates, verticalCoordinates, al
|
|
|
11648
11489
|
};
|
|
11649
11490
|
}
|
|
11650
11491
|
function findFragmentContext(stat) {
|
|
11651
|
-
for (const kind of
|
|
11492
|
+
for (const kind of SINGLE_BLOCK_FRAGMENT_KINDS) {
|
|
11652
11493
|
const frag = stat[kind]?.();
|
|
11653
11494
|
if (frag) return frag;
|
|
11654
11495
|
}
|
|
@@ -11660,10 +11501,6 @@ function findFragmentContext(stat) {
|
|
|
11660
11501
|
if (ref) return ref;
|
|
11661
11502
|
return null;
|
|
11662
11503
|
}
|
|
11663
|
-
function createStatementKeyFromStat(statement) {
|
|
11664
|
-
if (!statement?.start || !statement?.stop) return "";
|
|
11665
|
-
return `${statement.start.start}-${statement.stop.stop}`;
|
|
11666
|
-
}
|
|
11667
11504
|
function getDeepParticipantNames(fragmentCtx, sections) {
|
|
11668
11505
|
const names = new Set(getLocalParticipantNames(fragmentCtx));
|
|
11669
11506
|
if (sections) {
|
|
@@ -11701,11 +11538,37 @@ function walkBlock(block, currentOrigin, activeOccurrences, parentNumber, depth,
|
|
|
11701
11538
|
const to = message.Owner?.() || _STARTER_;
|
|
11702
11539
|
const label = normalizeLabel(message.SignatureText?.() || "");
|
|
11703
11540
|
const nestedBlock = message.braceBlock?.()?.block?.();
|
|
11704
|
-
results.push({
|
|
11541
|
+
results.push({
|
|
11542
|
+
key,
|
|
11543
|
+
kind: "sync",
|
|
11544
|
+
from,
|
|
11545
|
+
to,
|
|
11546
|
+
label,
|
|
11547
|
+
isSelf: from === to,
|
|
11548
|
+
hasBlock: !!nestedBlock,
|
|
11549
|
+
comment,
|
|
11550
|
+
statNode: stat,
|
|
11551
|
+
senderOccurrenceDepth: activeOccurrences.get(from) || 0,
|
|
11552
|
+
targetHasOccurrence: activeOccurrences.has(to),
|
|
11553
|
+
targetOccurrenceDepth: activeOccurrences.get(to) || 0,
|
|
11554
|
+
number,
|
|
11555
|
+
depth,
|
|
11556
|
+
parentBlockKind
|
|
11557
|
+
});
|
|
11705
11558
|
if (nestedBlock) {
|
|
11706
11559
|
const innerOccs = new Map(activeOccurrences);
|
|
11707
11560
|
innerOccs.set(to, (innerOccs.get(to) || 0) + 1);
|
|
11708
|
-
results.push(
|
|
11561
|
+
results.push(
|
|
11562
|
+
...walkBlock(
|
|
11563
|
+
nestedBlock,
|
|
11564
|
+
to,
|
|
11565
|
+
innerOccs,
|
|
11566
|
+
number,
|
|
11567
|
+
depth + 1,
|
|
11568
|
+
"sync",
|
|
11569
|
+
0
|
|
11570
|
+
)
|
|
11571
|
+
);
|
|
11709
11572
|
}
|
|
11710
11573
|
continue;
|
|
11711
11574
|
}
|
|
@@ -11713,8 +11576,23 @@ function walkBlock(block, currentOrigin, activeOccurrences, parentNumber, depth,
|
|
|
11713
11576
|
if (asyncMsg) {
|
|
11714
11577
|
const from = asyncMsg.From?.() || asyncMsg.ProvidedFrom?.() || asyncMsg.Origin?.() || currentOrigin;
|
|
11715
11578
|
const to = asyncMsg.Owner?.() || asyncMsg.to?.()?.getFormattedText?.() || from;
|
|
11716
|
-
const label = normalizeLabel(
|
|
11717
|
-
|
|
11579
|
+
const label = normalizeLabel(
|
|
11580
|
+
asyncMsg.content?.()?.getText?.() || asyncMsg.SignatureText?.() || ""
|
|
11581
|
+
);
|
|
11582
|
+
results.push({
|
|
11583
|
+
key,
|
|
11584
|
+
kind: "async",
|
|
11585
|
+
from,
|
|
11586
|
+
to,
|
|
11587
|
+
label,
|
|
11588
|
+
isSelf: from === to,
|
|
11589
|
+
hasBlock: false,
|
|
11590
|
+
comment,
|
|
11591
|
+
senderOccurrenceDepth: activeOccurrences.get(from) || 0,
|
|
11592
|
+
targetHasOccurrence: activeOccurrences.has(to),
|
|
11593
|
+
number,
|
|
11594
|
+
depth
|
|
11595
|
+
});
|
|
11718
11596
|
continue;
|
|
11719
11597
|
}
|
|
11720
11598
|
const creation = stat.creation?.();
|
|
@@ -11723,11 +11601,36 @@ function walkBlock(block, currentOrigin, activeOccurrences, parentNumber, depth,
|
|
|
11723
11601
|
const to = creation.Owner?.() || "";
|
|
11724
11602
|
const label = normalizeLabel(creation.SignatureText?.() || "«create»");
|
|
11725
11603
|
const creationBlock = creation.braceBlock?.()?.block?.();
|
|
11726
|
-
results.push({
|
|
11604
|
+
results.push({
|
|
11605
|
+
key,
|
|
11606
|
+
kind: "creation",
|
|
11607
|
+
from,
|
|
11608
|
+
to,
|
|
11609
|
+
label,
|
|
11610
|
+
isSelf: false,
|
|
11611
|
+
hasBlock: !!creationBlock,
|
|
11612
|
+
comment,
|
|
11613
|
+
statNode: stat,
|
|
11614
|
+
senderOccurrenceDepth: activeOccurrences.get(from) || 0,
|
|
11615
|
+
targetHasOccurrence: activeOccurrences.has(to),
|
|
11616
|
+
number,
|
|
11617
|
+
depth,
|
|
11618
|
+
parentBlockKind
|
|
11619
|
+
});
|
|
11727
11620
|
if (creationBlock) {
|
|
11728
11621
|
const innerOccs = new Map(activeOccurrences);
|
|
11729
11622
|
innerOccs.set(to, (innerOccs.get(to) || 0) + 1);
|
|
11730
|
-
results.push(
|
|
11623
|
+
results.push(
|
|
11624
|
+
...walkBlock(
|
|
11625
|
+
creationBlock,
|
|
11626
|
+
to || currentOrigin,
|
|
11627
|
+
innerOccs,
|
|
11628
|
+
number,
|
|
11629
|
+
depth + 1,
|
|
11630
|
+
"creation",
|
|
11631
|
+
0
|
|
11632
|
+
)
|
|
11633
|
+
);
|
|
11731
11634
|
}
|
|
11732
11635
|
continue;
|
|
11733
11636
|
}
|
|
@@ -11737,13 +11640,40 @@ function walkBlock(block, currentOrigin, activeOccurrences, parentNumber, depth,
|
|
|
11737
11640
|
const asyncMessage = ret?.asyncMessage?.();
|
|
11738
11641
|
const from = asyncMessage?.From?.() || ret?.From?.() || currentOrigin;
|
|
11739
11642
|
const to = asyncMessage?.to?.()?.getFormattedText?.() || ret?.ReturnTo?.() || _STARTER_;
|
|
11740
|
-
results.push({
|
|
11643
|
+
results.push({
|
|
11644
|
+
key,
|
|
11645
|
+
kind: "return",
|
|
11646
|
+
from,
|
|
11647
|
+
to,
|
|
11648
|
+
label,
|
|
11649
|
+
isSelf: from === to,
|
|
11650
|
+
hasBlock: false,
|
|
11651
|
+
comment,
|
|
11652
|
+
senderOccurrenceDepth: activeOccurrences.get(from) || 0,
|
|
11653
|
+
targetOccurrenceDepth: activeOccurrences.get(to) || 0,
|
|
11654
|
+
number,
|
|
11655
|
+
depth,
|
|
11656
|
+
parentBlockKind
|
|
11657
|
+
});
|
|
11741
11658
|
continue;
|
|
11742
11659
|
}
|
|
11743
11660
|
const divider = stat.divider?.();
|
|
11744
11661
|
if (divider) {
|
|
11745
|
-
const label = normalizeLabel(
|
|
11746
|
-
|
|
11662
|
+
const label = normalizeLabel(
|
|
11663
|
+
divider.getFormattedText?.() || divider.getText?.() || ""
|
|
11664
|
+
);
|
|
11665
|
+
results.push({
|
|
11666
|
+
key,
|
|
11667
|
+
kind: "divider",
|
|
11668
|
+
from: "",
|
|
11669
|
+
to: "",
|
|
11670
|
+
label,
|
|
11671
|
+
isSelf: false,
|
|
11672
|
+
hasBlock: false,
|
|
11673
|
+
senderOccurrenceDepth: 0,
|
|
11674
|
+
number,
|
|
11675
|
+
depth
|
|
11676
|
+
});
|
|
11747
11677
|
continue;
|
|
11748
11678
|
}
|
|
11749
11679
|
const fragmentInfo = extractFragmentInfo(stat);
|
|
@@ -11765,12 +11695,19 @@ function walkBlock(block, currentOrigin, activeOccurrences, parentNumber, depth,
|
|
|
11765
11695
|
number,
|
|
11766
11696
|
depth
|
|
11767
11697
|
});
|
|
11768
|
-
walkFragmentBlocks(
|
|
11698
|
+
walkFragmentBlocks(
|
|
11699
|
+
stat,
|
|
11700
|
+
currentOrigin,
|
|
11701
|
+
results,
|
|
11702
|
+
activeOccurrences,
|
|
11703
|
+
number,
|
|
11704
|
+
depth
|
|
11705
|
+
);
|
|
11769
11706
|
}
|
|
11770
11707
|
return results;
|
|
11771
11708
|
}
|
|
11772
11709
|
function extractFragmentInfo(stat) {
|
|
11773
|
-
for (const kind of
|
|
11710
|
+
for (const kind of SINGLE_BLOCK_FRAGMENT_KINDS) {
|
|
11774
11711
|
const frag = stat[kind]?.();
|
|
11775
11712
|
if (frag) {
|
|
11776
11713
|
const condition = frag.parExpr?.()?.condition?.();
|
|
@@ -11787,16 +11724,25 @@ function extractFragmentInfo(stat) {
|
|
|
11787
11724
|
const sections = [];
|
|
11788
11725
|
const ifBlock = alt.ifBlock?.();
|
|
11789
11726
|
if (ifBlock) {
|
|
11790
|
-
sections.push({
|
|
11727
|
+
sections.push({
|
|
11728
|
+
label: "Alt",
|
|
11729
|
+
blockNode: ifBlock.braceBlock?.()?.block?.()
|
|
11730
|
+
});
|
|
11791
11731
|
}
|
|
11792
11732
|
for (const elseIf of alt.elseIfBlock?.() || []) {
|
|
11793
11733
|
const condition = elseIf.parExpr?.()?.condition?.();
|
|
11794
11734
|
const label = condition?.getFormattedText?.() || "";
|
|
11795
|
-
sections.push({
|
|
11735
|
+
sections.push({
|
|
11736
|
+
label: `[ ${label} ]`,
|
|
11737
|
+
blockNode: elseIf.braceBlock?.()?.block?.()
|
|
11738
|
+
});
|
|
11796
11739
|
}
|
|
11797
11740
|
const elseBlock = alt.elseBlock?.();
|
|
11798
11741
|
if (elseBlock) {
|
|
11799
|
-
sections.push({
|
|
11742
|
+
sections.push({
|
|
11743
|
+
label: "[else]",
|
|
11744
|
+
blockNode: elseBlock.braceBlock?.()?.block?.()
|
|
11745
|
+
});
|
|
11800
11746
|
}
|
|
11801
11747
|
const ifCondition = alt.ifBlock?.()?.parExpr?.()?.condition?.();
|
|
11802
11748
|
const firstLabel = ifCondition?.getFormattedText?.() || "";
|
|
@@ -11807,15 +11753,24 @@ function extractFragmentInfo(stat) {
|
|
|
11807
11753
|
const sections = [];
|
|
11808
11754
|
const tryBlock = tcf.tryBlock?.();
|
|
11809
11755
|
if (tryBlock) {
|
|
11810
|
-
sections.push({
|
|
11756
|
+
sections.push({
|
|
11757
|
+
label: "Try",
|
|
11758
|
+
blockNode: tryBlock.braceBlock?.()?.block?.()
|
|
11759
|
+
});
|
|
11811
11760
|
}
|
|
11812
11761
|
for (const catchBlock of tcf.catchBlock?.() || []) {
|
|
11813
11762
|
const exception = catchBlock.invocation?.()?.parameters?.()?.getFormattedText?.() || "";
|
|
11814
|
-
sections.push({
|
|
11763
|
+
sections.push({
|
|
11764
|
+
label: `catch ${exception}`,
|
|
11765
|
+
blockNode: catchBlock.braceBlock?.()?.block?.()
|
|
11766
|
+
});
|
|
11815
11767
|
}
|
|
11816
11768
|
const finallyBlock = tcf.finallyBlock?.();
|
|
11817
11769
|
if (finallyBlock) {
|
|
11818
|
-
sections.push({
|
|
11770
|
+
sections.push({
|
|
11771
|
+
label: "finally",
|
|
11772
|
+
blockNode: finallyBlock.braceBlock?.()?.block?.()
|
|
11773
|
+
});
|
|
11819
11774
|
}
|
|
11820
11775
|
return { fragmentKind: "tcf", label: "", sections };
|
|
11821
11776
|
}
|
|
@@ -11827,14 +11782,27 @@ function extractFragmentInfo(stat) {
|
|
|
11827
11782
|
return null;
|
|
11828
11783
|
}
|
|
11829
11784
|
function blockLength(block) {
|
|
11830
|
-
return (block?.stat?.() || []).filter(
|
|
11785
|
+
return (block?.stat?.() || []).filter(
|
|
11786
|
+
(stat) => !!createStatementKey(stat)
|
|
11787
|
+
).length;
|
|
11831
11788
|
}
|
|
11832
11789
|
function walkFragmentBlocks(stat, origin, results, activeOccurrences, parentNumber, depth) {
|
|
11833
|
-
for (const kind of
|
|
11790
|
+
for (const kind of SINGLE_BLOCK_FRAGMENT_KINDS) {
|
|
11834
11791
|
const frag = stat[kind]?.();
|
|
11835
11792
|
if (frag) {
|
|
11836
11793
|
const block = frag.braceBlock?.()?.block?.();
|
|
11837
|
-
if (block)
|
|
11794
|
+
if (block)
|
|
11795
|
+
results.push(
|
|
11796
|
+
...walkBlock(
|
|
11797
|
+
block,
|
|
11798
|
+
origin,
|
|
11799
|
+
activeOccurrences,
|
|
11800
|
+
parentNumber,
|
|
11801
|
+
depth + 1,
|
|
11802
|
+
null,
|
|
11803
|
+
0
|
|
11804
|
+
)
|
|
11805
|
+
);
|
|
11838
11806
|
return;
|
|
11839
11807
|
}
|
|
11840
11808
|
}
|
|
@@ -11845,14 +11813,32 @@ function walkFragmentBlocks(stat, origin, results, activeOccurrences, parentNumb
|
|
|
11845
11813
|
if (ifBlock) {
|
|
11846
11814
|
const block = ifBlock.braceBlock?.()?.block?.();
|
|
11847
11815
|
if (block) {
|
|
11848
|
-
results.push(
|
|
11816
|
+
results.push(
|
|
11817
|
+
...walkBlock(
|
|
11818
|
+
block,
|
|
11819
|
+
origin,
|
|
11820
|
+
activeOccurrences,
|
|
11821
|
+
parentNumber,
|
|
11822
|
+
depth + 1,
|
|
11823
|
+
null,
|
|
11824
|
+
sectionOffset
|
|
11825
|
+
)
|
|
11826
|
+
);
|
|
11849
11827
|
sectionOffset += blockLength(block);
|
|
11850
11828
|
}
|
|
11851
11829
|
}
|
|
11852
11830
|
for (const elseIf of alt.elseIfBlock?.() || []) {
|
|
11853
11831
|
const block = elseIf.braceBlock?.()?.block?.();
|
|
11854
11832
|
if (block) {
|
|
11855
|
-
const sectionStmts = walkBlock(
|
|
11833
|
+
const sectionStmts = walkBlock(
|
|
11834
|
+
block,
|
|
11835
|
+
origin,
|
|
11836
|
+
activeOccurrences,
|
|
11837
|
+
parentNumber,
|
|
11838
|
+
depth + 1,
|
|
11839
|
+
null,
|
|
11840
|
+
sectionOffset
|
|
11841
|
+
);
|
|
11856
11842
|
if (sectionStmts.length > 0) sectionStmts[0].sectionReset = true;
|
|
11857
11843
|
results.push(...sectionStmts);
|
|
11858
11844
|
sectionOffset += blockLength(block);
|
|
@@ -11862,7 +11848,15 @@ function walkFragmentBlocks(stat, origin, results, activeOccurrences, parentNumb
|
|
|
11862
11848
|
if (elseBlock) {
|
|
11863
11849
|
const block = elseBlock.braceBlock?.()?.block?.();
|
|
11864
11850
|
if (block) {
|
|
11865
|
-
const sectionStmts = walkBlock(
|
|
11851
|
+
const sectionStmts = walkBlock(
|
|
11852
|
+
block,
|
|
11853
|
+
origin,
|
|
11854
|
+
activeOccurrences,
|
|
11855
|
+
parentNumber,
|
|
11856
|
+
depth + 1,
|
|
11857
|
+
null,
|
|
11858
|
+
sectionOffset
|
|
11859
|
+
);
|
|
11866
11860
|
if (sectionStmts.length > 0) sectionStmts[0].sectionReset = true;
|
|
11867
11861
|
results.push(...sectionStmts);
|
|
11868
11862
|
}
|
|
@@ -11876,14 +11870,32 @@ function walkFragmentBlocks(stat, origin, results, activeOccurrences, parentNumb
|
|
|
11876
11870
|
if (tryBlock) {
|
|
11877
11871
|
const block = tryBlock.braceBlock?.()?.block?.();
|
|
11878
11872
|
if (block) {
|
|
11879
|
-
results.push(
|
|
11873
|
+
results.push(
|
|
11874
|
+
...walkBlock(
|
|
11875
|
+
block,
|
|
11876
|
+
origin,
|
|
11877
|
+
activeOccurrences,
|
|
11878
|
+
parentNumber,
|
|
11879
|
+
depth + 1,
|
|
11880
|
+
null,
|
|
11881
|
+
sectionOffset
|
|
11882
|
+
)
|
|
11883
|
+
);
|
|
11880
11884
|
sectionOffset += blockLength(block);
|
|
11881
11885
|
}
|
|
11882
11886
|
}
|
|
11883
11887
|
for (const catchBlock of tcf.catchBlock?.() || []) {
|
|
11884
11888
|
const block = catchBlock.braceBlock?.()?.block?.();
|
|
11885
11889
|
if (block) {
|
|
11886
|
-
const sectionStmts = walkBlock(
|
|
11890
|
+
const sectionStmts = walkBlock(
|
|
11891
|
+
block,
|
|
11892
|
+
origin,
|
|
11893
|
+
activeOccurrences,
|
|
11894
|
+
parentNumber,
|
|
11895
|
+
depth + 1,
|
|
11896
|
+
null,
|
|
11897
|
+
sectionOffset
|
|
11898
|
+
);
|
|
11887
11899
|
if (sectionStmts.length > 0) sectionStmts[0].sectionReset = true;
|
|
11888
11900
|
results.push(...sectionStmts);
|
|
11889
11901
|
sectionOffset += blockLength(block);
|
|
@@ -11893,7 +11905,15 @@ function walkFragmentBlocks(stat, origin, results, activeOccurrences, parentNumb
|
|
|
11893
11905
|
if (finallyBlock) {
|
|
11894
11906
|
const block = finallyBlock.braceBlock?.()?.block?.();
|
|
11895
11907
|
if (block) {
|
|
11896
|
-
const sectionStmts = walkBlock(
|
|
11908
|
+
const sectionStmts = walkBlock(
|
|
11909
|
+
block,
|
|
11910
|
+
origin,
|
|
11911
|
+
activeOccurrences,
|
|
11912
|
+
parentNumber,
|
|
11913
|
+
depth + 1,
|
|
11914
|
+
null,
|
|
11915
|
+
sectionOffset
|
|
11916
|
+
);
|
|
11897
11917
|
if (sectionStmts.length > 0) sectionStmts[0].sectionReset = true;
|
|
11898
11918
|
results.push(...sectionStmts);
|
|
11899
11919
|
}
|
|
@@ -11925,10 +11945,6 @@ function computeReturnDebt(statements, verticalCoordinates, returnHeight) {
|
|
|
11925
11945
|
if (ownerKey && occInnerDebt > 0) {
|
|
11926
11946
|
result.set(`inner:${ownerKey}`, occInnerDebt);
|
|
11927
11947
|
}
|
|
11928
|
-
const hasMixed = hasNonReturnChild[maxDepth] || false;
|
|
11929
|
-
if (ownerKey && hasMixed) {
|
|
11930
|
-
result.set(`mixed:${ownerKey}`, 1);
|
|
11931
|
-
}
|
|
11932
11948
|
const hasAssign = blockHasAssignment[maxDepth] || false;
|
|
11933
11949
|
debtByDepth.pop();
|
|
11934
11950
|
directDebtByDepth.pop();
|
|
@@ -12012,10 +12028,6 @@ function computeReturnDebt(statements, verticalCoordinates, returnHeight) {
|
|
|
12012
12028
|
if (ownerKey && occInnerDebtEnd > 0) {
|
|
12013
12029
|
result.set(`inner:${ownerKey}`, occInnerDebtEnd);
|
|
12014
12030
|
}
|
|
12015
|
-
const hasMixedEnd = hasNonReturnChild[maxDepth] || false;
|
|
12016
|
-
if (ownerKey && hasMixedEnd) {
|
|
12017
|
-
result.set(`mixed:${ownerKey}`, 1);
|
|
12018
|
-
}
|
|
12019
12031
|
const hasAssignEnd = blockHasAssignment[maxDepth] || false;
|
|
12020
12032
|
debtByDepth.pop();
|
|
12021
12033
|
directDebtByDepth.pop();
|
|
@@ -12031,7 +12043,6 @@ function computeReturnDebt(statements, verticalCoordinates, returnHeight) {
|
|
|
12031
12043
|
}
|
|
12032
12044
|
}
|
|
12033
12045
|
}
|
|
12034
|
-
result.set("__totalDebt__", debtByDepth[0] || 0);
|
|
12035
12046
|
return result;
|
|
12036
12047
|
}
|
|
12037
12048
|
|
|
@@ -12059,7 +12070,11 @@ function buildMessages(rootContext, coordinates, verticalCoordinates, participan
|
|
|
12059
12070
|
}
|
|
12060
12071
|
}
|
|
12061
12072
|
const RETURN_VISUAL_HEIGHT = 16;
|
|
12062
|
-
const adjustMap = computeReturnDebt(
|
|
12073
|
+
const adjustMap = computeReturnDebt(
|
|
12074
|
+
statements,
|
|
12075
|
+
verticalCoordinates,
|
|
12076
|
+
RETURN_VISUAL_HEIGHT
|
|
12077
|
+
);
|
|
12063
12078
|
for (const info of statements) {
|
|
12064
12079
|
const coord = verticalCoordinates.getStatementCoordinate(info.key);
|
|
12065
12080
|
if (!coord) continue;
|
|
@@ -12075,7 +12090,7 @@ function buildMessages(rootContext, coordinates, verticalCoordinates, participan
|
|
|
12075
12090
|
const tX = coordinates.getPosition(info.to);
|
|
12076
12091
|
if (fX > tX) commentParticipant = info.to;
|
|
12077
12092
|
}
|
|
12078
|
-
const commentX = commentParticipant ?
|
|
12093
|
+
const commentX = commentParticipant ? coordinates.getPosition(commentParticipant) : 10;
|
|
12079
12094
|
const COMMENT_FONT_ASCENT = 15;
|
|
12080
12095
|
const commentXOffset = info.senderOccurrenceDepth >= 1 ? OCCURRENCE_BAR_SIDE_WIDTH + 1 : 1;
|
|
12081
12096
|
const codeSpanPadding = commentObj.text.trimStart().startsWith("`") ? 2 : 0;
|
|
@@ -12088,30 +12103,31 @@ function buildMessages(rootContext, coordinates, verticalCoordinates, participan
|
|
|
12088
12103
|
}
|
|
12089
12104
|
const messageStyle = commentObj ? cssToSvgStyle(commentObj.messageStyle) : void 0;
|
|
12090
12105
|
if (info.kind === "sync" || info.kind === "async") {
|
|
12091
|
-
let fromX =
|
|
12092
|
-
const toX =
|
|
12093
|
-
const
|
|
12094
|
-
const
|
|
12106
|
+
let fromX = coordinates.getPosition(info.from);
|
|
12107
|
+
const toX = coordinates.getPosition(info.to);
|
|
12108
|
+
const isAsync = info.kind === "async";
|
|
12109
|
+
const messageHeight = !info.isSelf ? MESSAGE_HEIGHT : isAsync ? ASYNC_SELF_MESSAGE_HEIGHT : SELF_MESSAGE_HEIGHT;
|
|
12110
|
+
const msgCommentHeight = commentObj?.text ? (info.comment?.trim().split("\n").length || 0) * COMMENT_LINE_HEIGHT : 0;
|
|
12095
12111
|
const messageY = coord.top + adjust + msgCommentHeight + messageHeight - 0.5;
|
|
12096
12112
|
if (info.senderOccurrenceDepth >= 1 && !info.isSelf) {
|
|
12097
|
-
const
|
|
12098
|
-
const occOffset = depth * OCCURRENCE_BAR_SIDE_WIDTH;
|
|
12113
|
+
const senderAnchor = new Anchor2(fromX, info.senderOccurrenceDepth);
|
|
12099
12114
|
const isLTR = fromX < toX;
|
|
12100
|
-
fromX = isLTR ?
|
|
12115
|
+
fromX = isLTR ? senderAnchor.rightEdgeOfRightWall() : senderAnchor.leftEdgeOfRightWall();
|
|
12101
12116
|
}
|
|
12102
12117
|
const targetDepth = info.targetOccurrenceDepth || (info.targetHasOccurrence ? 1 : 0);
|
|
12103
12118
|
const nestingOffset = targetDepth * OCCURRENCE_BAR_SIDE_WIDTH;
|
|
12104
12119
|
if (info.isSelf) {
|
|
12105
|
-
const isAsync = info.kind === "async";
|
|
12106
12120
|
const selfYOffset = 0;
|
|
12107
12121
|
const selfWidth = isAsync ? 28 : OCCURRENCE_WIDTH;
|
|
12108
|
-
const
|
|
12109
|
-
|
|
12122
|
+
const selfX = new Anchor2(
|
|
12123
|
+
fromX,
|
|
12124
|
+
info.senderOccurrenceDepth
|
|
12125
|
+
).rightEdgeOfRightWall();
|
|
12110
12126
|
selfCalls.push({
|
|
12111
12127
|
x: selfX,
|
|
12112
12128
|
y: coord.top + selfYOffset + msgCommentHeight,
|
|
12113
12129
|
width: selfWidth,
|
|
12114
|
-
height:
|
|
12130
|
+
height: messageHeight,
|
|
12115
12131
|
label: info.label,
|
|
12116
12132
|
arrowStyle: isAsync ? "open" : "solid",
|
|
12117
12133
|
number: info.number,
|
|
@@ -12183,16 +12199,15 @@ function buildMessages(rootContext, coordinates, verticalCoordinates, participan
|
|
|
12183
12199
|
continue;
|
|
12184
12200
|
}
|
|
12185
12201
|
if (info.kind === "creation") {
|
|
12186
|
-
|
|
12187
|
-
|
|
12188
|
-
const toX = snapX$1(coordinates.getPosition(info.to));
|
|
12202
|
+
let fromX = coordinates.getPosition(info.from);
|
|
12203
|
+
const toX = coordinates.getPosition(info.to);
|
|
12189
12204
|
if (info.senderOccurrenceDepth >= 1) {
|
|
12190
12205
|
const occOffset = OCCURRENCE_BAR_SIDE_WIDTH + (info.senderOccurrenceDepth - 1) * OCCURRENCE_BAR_SIDE_WIDTH;
|
|
12191
12206
|
const isLTR = fromX < toX;
|
|
12192
12207
|
fromX = isLTR ? fromX + occOffset : fromX - occOffset;
|
|
12193
12208
|
}
|
|
12194
12209
|
const targetParticipant = participants.find((p) => p.name === info.to);
|
|
12195
|
-
const messageY = targetParticipant ? targetParticipant.y + PARTICIPANT_VISUAL_HEIGHT / 2 : coord.top +
|
|
12210
|
+
const messageY = targetParticipant ? targetParticipant.y + PARTICIPANT_VISUAL_HEIGHT / 2 : coord.top + CREATION_MESSAGE_HEIGHT / 2;
|
|
12196
12211
|
if (targetParticipant) {
|
|
12197
12212
|
creations.push({
|
|
12198
12213
|
participant: targetParticipant,
|
|
@@ -12211,7 +12226,7 @@ function buildMessages(rootContext, coordinates, verticalCoordinates, participan
|
|
|
12211
12226
|
});
|
|
12212
12227
|
}
|
|
12213
12228
|
const occX = toX - OCCURRENCE_BAR_SIDE_WIDTH;
|
|
12214
|
-
const occY = targetParticipant ? targetParticipant.y + PARTICIPANT_VISUAL_HEIGHT - 2 : coord.top +
|
|
12229
|
+
const occY = targetParticipant ? targetParticipant.y + PARTICIPANT_VISUAL_HEIGHT - 2 : coord.top + CREATION_MESSAGE_HEIGHT - 2;
|
|
12215
12230
|
const occHeight = Math.max(
|
|
12216
12231
|
coord.top + coord.height - occY,
|
|
12217
12232
|
OCCURRENCE_EMPTY_HEIGHT
|
|
@@ -12228,7 +12243,7 @@ function buildMessages(rootContext, coordinates, verticalCoordinates, participan
|
|
|
12228
12243
|
const creationAssign = creationCtx?.Assignment?.();
|
|
12229
12244
|
if (creationAssign?.assignee) {
|
|
12230
12245
|
const occBottom = occY + occHeight - 2;
|
|
12231
|
-
const rawFromX =
|
|
12246
|
+
const rawFromX = coordinates.getPosition(info.from);
|
|
12232
12247
|
const isLTR = rawFromX < toX;
|
|
12233
12248
|
const occHalf = OCCURRENCE_BAR_SIDE_WIDTH;
|
|
12234
12249
|
const senderNest = Math.max(info.senderOccurrenceDepth - 1, 0) * OCCURRENCE_BAR_SIDE_WIDTH;
|
|
@@ -12250,7 +12265,7 @@ function buildMessages(rootContext, coordinates, verticalCoordinates, participan
|
|
|
12250
12265
|
}
|
|
12251
12266
|
if (info.kind === "fragment" && info.fragmentKind) {
|
|
12252
12267
|
const adjustedCoord = { top: coord.top + adjust, height: coord.height };
|
|
12253
|
-
const fragmentCommentHeight = commentObj?.text ? (info.comment?.trim().split("\n").length || 0) *
|
|
12268
|
+
const fragmentCommentHeight = commentObj?.text ? (info.comment?.trim().split("\n").length || 0) * COMMENT_LINE_HEIGHT : 0;
|
|
12254
12269
|
const fragmentResult = buildFragmentGeometry(
|
|
12255
12270
|
info,
|
|
12256
12271
|
adjustedCoord,
|
|
@@ -12272,26 +12287,14 @@ function buildMessages(rootContext, coordinates, verticalCoordinates, participan
|
|
|
12272
12287
|
continue;
|
|
12273
12288
|
}
|
|
12274
12289
|
if (info.kind === "return") {
|
|
12275
|
-
const rawFromX =
|
|
12276
|
-
const rawToX =
|
|
12290
|
+
const rawFromX = coordinates.getPosition(info.from);
|
|
12291
|
+
const rawToX = coordinates.getPosition(info.to);
|
|
12277
12292
|
const isReverse = rawToX < rawFromX;
|
|
12278
|
-
const
|
|
12279
|
-
|
|
12280
|
-
|
|
12281
|
-
|
|
12282
|
-
|
|
12283
|
-
fromX = rawFromX + OCCURRENCE_BAR_SIDE_WIDTH * fromLayers + 1;
|
|
12284
|
-
}
|
|
12285
|
-
const toLayers = info.targetOccurrenceDepth || 0;
|
|
12286
|
-
let toX;
|
|
12287
|
-
if (isReverse) {
|
|
12288
|
-
toX = rawToX + OCCURRENCE_BAR_SIDE_WIDTH * toLayers;
|
|
12289
|
-
} else {
|
|
12290
|
-
toX = toLayers === 0 ? rawToX : (toLayers <= 1 ? rawToX : rawToX + OCCURRENCE_BAR_SIDE_WIDTH * (toLayers - 1)) - OCCURRENCE_BAR_SIDE_WIDTH;
|
|
12291
|
-
}
|
|
12292
|
-
if (isReverse) {
|
|
12293
|
-
toX += LIFELINE_WIDTH;
|
|
12294
|
-
}
|
|
12293
|
+
const fromAnchor = new Anchor2(rawFromX, info.senderOccurrenceDepth);
|
|
12294
|
+
const toAnchor = new Anchor2(rawToX, info.targetOccurrenceDepth || 0);
|
|
12295
|
+
const RETURN_STROKE_OFFSET = 1;
|
|
12296
|
+
const fromX = isReverse ? fromAnchor.leftEdgeOfRightWall() : fromAnchor.rightEdgeOfRightWall() + RETURN_STROKE_OFFSET;
|
|
12297
|
+
const toX = isReverse ? toAnchor.rightEdgeOfRightWall() + LIFELINE_WIDTH : toAnchor.leftEdgeOfRightWall();
|
|
12295
12298
|
const returnOffset = coord.height === 0 ? 16.5 : 15.5;
|
|
12296
12299
|
const returnY = coord.top + adjust + returnOffset;
|
|
12297
12300
|
returns.push({
|
|
@@ -12313,7 +12316,9 @@ function buildMessages(rootContext, coordinates, verticalCoordinates, participan
|
|
|
12313
12316
|
y: coord.top + adjust + coord.height / 2,
|
|
12314
12317
|
width: diagramWidth,
|
|
12315
12318
|
label: info.label,
|
|
12316
|
-
labelWidth: measureSvgFragmentLabelWidth(
|
|
12319
|
+
labelWidth: measureSvgFragmentLabelWidth(
|
|
12320
|
+
resolveEmojiInText(cleanLabel)
|
|
12321
|
+
)
|
|
12317
12322
|
});
|
|
12318
12323
|
continue;
|
|
12319
12324
|
}
|
|
@@ -12336,11 +12341,23 @@ function buildMessages(rootContext, coordinates, verticalCoordinates, participan
|
|
|
12336
12341
|
}
|
|
12337
12342
|
}
|
|
12338
12343
|
if (depth > 0) {
|
|
12339
|
-
occurrences[i] = {
|
|
12344
|
+
occurrences[i] = {
|
|
12345
|
+
...inner,
|
|
12346
|
+
x: inner.x + depth * OCCURRENCE_BAR_SIDE_WIDTH
|
|
12347
|
+
};
|
|
12340
12348
|
}
|
|
12341
12349
|
}
|
|
12342
|
-
|
|
12343
|
-
|
|
12350
|
+
return {
|
|
12351
|
+
messages,
|
|
12352
|
+
selfCalls,
|
|
12353
|
+
occurrences,
|
|
12354
|
+
creations,
|
|
12355
|
+
fragments,
|
|
12356
|
+
returns,
|
|
12357
|
+
dividers,
|
|
12358
|
+
comments,
|
|
12359
|
+
maxReturnBottom
|
|
12360
|
+
};
|
|
12344
12361
|
}
|
|
12345
12362
|
|
|
12346
12363
|
function buildGeometry(input) {
|
|
@@ -12384,17 +12401,7 @@ function buildGeometry(input) {
|
|
|
12384
12401
|
participants,
|
|
12385
12402
|
lifelineBottom
|
|
12386
12403
|
);
|
|
12387
|
-
|
|
12388
|
-
const orderedNames = coordinates.orderedParticipantNames();
|
|
12389
|
-
const leftParticipant = orderedNames.find((p) => localParticipants.includes(p)) || "";
|
|
12390
|
-
const rightParticipant = orderedNames.slice().reverse().find((p) => localParticipants.includes(p)) || "";
|
|
12391
|
-
const participantWidth = coordinates.distance(leftParticipant, rightParticipant) + coordinates.half(leftParticipant) + coordinates.half(rightParticipant);
|
|
12392
|
-
const selfMessages = AllMessages(rootContext).filter((m) => m.from === m.to);
|
|
12393
|
-
const extraWidths = selfMessages.map(
|
|
12394
|
-
(m) => coordinates.getMessageWidth(m) - coordinates.distance(m.from || _STARTER_, rightParticipant) - coordinates.half(rightParticipant)
|
|
12395
|
-
);
|
|
12396
|
-
const extraWidthDueToSelfMessage = Math.max(0, ...extraWidths);
|
|
12397
|
-
let diagramWidth = Math.max(participantWidth, FRAGMENT_MIN_WIDTH) + extraWidthDueToSelfMessage;
|
|
12404
|
+
let diagramWidth = TotalWidth(rootContext, coordinates) - frameBorder.left - frameBorder.right;
|
|
12398
12405
|
if (measureText) {
|
|
12399
12406
|
const LABEL_PAD = 10;
|
|
12400
12407
|
for (const msg of messages) {
|
|
@@ -12732,7 +12739,7 @@ function renderOccurrence(o) {
|
|
|
12732
12739
|
return `<rect x="${rx}" y="${o.y + strokeHalf}" width="${o.width - strokeHalf * 2}" height="${o.height - strokeHalf * 2}" rx="1" class="occurrence" data-participant="${esc(o.participantName)}"/>`;
|
|
12733
12740
|
}
|
|
12734
12741
|
|
|
12735
|
-
const HEADER_HEIGHT =
|
|
12742
|
+
const HEADER_HEIGHT = DEFAULT_LAYOUT_METRICS.fragmentHeaderHeight;
|
|
12736
12743
|
const BRACKET_WIDTH = 3.89;
|
|
12737
12744
|
const TEXT_PAD_X = 4;
|
|
12738
12745
|
const STROKE_WIDTH = 1;
|
|
@@ -13093,47 +13100,153 @@ function renderGroup(g) {
|
|
|
13093
13100
|
</g>`;
|
|
13094
13101
|
}
|
|
13095
13102
|
|
|
13096
|
-
const
|
|
13097
|
-
const
|
|
13098
|
-
|
|
13099
|
-
|
|
13100
|
-
|
|
13101
|
-
|
|
13102
|
-
|
|
13103
|
-
|
|
13104
|
-
|
|
13105
|
-
|
|
13106
|
-
|
|
13107
|
-
|
|
13108
|
-
|
|
13109
|
-
|
|
13110
|
-
|
|
13111
|
-
|
|
13103
|
+
const HELVETICA = "Helvetica, Verdana, serif";
|
|
13104
|
+
const DEFAULT_PALETTE = {
|
|
13105
|
+
frameBorder: "#666",
|
|
13106
|
+
frameBg: "#ffffff",
|
|
13107
|
+
titleText: "#222",
|
|
13108
|
+
participantBg: "#ffffff",
|
|
13109
|
+
participantBorder: "#666",
|
|
13110
|
+
participantText: "#222",
|
|
13111
|
+
messageArrow: "#000",
|
|
13112
|
+
messageText: "#222",
|
|
13113
|
+
occurrenceBg: "#dedede",
|
|
13114
|
+
occurrenceBorder: "#666",
|
|
13115
|
+
fragmentBorder: "#666",
|
|
13116
|
+
fragmentHeaderBg: "#dedede",
|
|
13117
|
+
fragmentHeaderOpacity: "0.498",
|
|
13118
|
+
fragmentText: "#000",
|
|
13119
|
+
fragmentSeparator: "#e5e7eb",
|
|
13120
|
+
commentText: "#333",
|
|
13121
|
+
fontFamily: HELVETICA
|
|
13122
|
+
};
|
|
13123
|
+
const THEME_PALETTES = {
|
|
13124
|
+
"theme-default": DEFAULT_PALETTE,
|
|
13125
|
+
// `.theme-mermaid` sets only base/text/border/occurrence, and hides the
|
|
13126
|
+
// footer — chrome the SVG output does not draw. Every slot it leaves unset
|
|
13127
|
+
// matches theme-default, so the two render identically.
|
|
13128
|
+
"theme-mermaid": DEFAULT_PALETTE,
|
|
13129
|
+
// src/assets/tailwind.css `.theme-clean-light`.
|
|
13130
|
+
"theme-clean-light": {
|
|
13131
|
+
frameBorder: "#e5e9f0",
|
|
13132
|
+
frameBg: "#ffffff",
|
|
13133
|
+
titleText: "#353748",
|
|
13134
|
+
participantBg: "#edf4fe",
|
|
13135
|
+
participantBorder: "#368eff",
|
|
13136
|
+
participantText: "#368eff",
|
|
13137
|
+
messageArrow: "#368eff",
|
|
13138
|
+
messageText: "#368eff",
|
|
13139
|
+
occurrenceBg: "#ffffff",
|
|
13140
|
+
occurrenceBorder: "#368eff",
|
|
13141
|
+
fragmentBorder: "#c8c9c9",
|
|
13142
|
+
fragmentHeaderBg: "#edf4fe",
|
|
13143
|
+
fragmentHeaderOpacity: "1",
|
|
13144
|
+
fragmentText: "#368eff",
|
|
13145
|
+
fragmentSeparator: "#e5e9f0",
|
|
13146
|
+
commentText: "#353748",
|
|
13147
|
+
fontFamily: HELVETICA
|
|
13148
|
+
},
|
|
13149
|
+
// src/assets/tailwind.css `.theme-clean-dark`.
|
|
13150
|
+
"theme-clean-dark": {
|
|
13151
|
+
frameBorder: "#cecfd2",
|
|
13152
|
+
frameBg: "#111628",
|
|
13153
|
+
titleText: "#cecfd2",
|
|
13154
|
+
participantBg: "#5964f2",
|
|
13155
|
+
participantBorder: "#cecfd2",
|
|
13156
|
+
participantText: "#536fff",
|
|
13157
|
+
messageArrow: "#536fff",
|
|
13158
|
+
messageText: "#cecfd2",
|
|
13159
|
+
occurrenceBg: "#5964f2",
|
|
13160
|
+
occurrenceBorder: "#cecfd2",
|
|
13161
|
+
fragmentBorder: "#cecfd2",
|
|
13162
|
+
fragmentHeaderBg: "#5964f2",
|
|
13163
|
+
fragmentHeaderOpacity: "1",
|
|
13164
|
+
fragmentText: "#cecfd2",
|
|
13165
|
+
fragmentSeparator: "#cecfd2",
|
|
13166
|
+
commentText: "#cecfd2",
|
|
13167
|
+
fontFamily: HELVETICA
|
|
13168
|
+
},
|
|
13169
|
+
// src/assets/tailwind.css `.theme-neon`. The DOM theme also swaps in the
|
|
13170
|
+
// MS Sans Serif webfont (`.zenuml .theme-neon`); the SVG names it first and
|
|
13171
|
+
// keeps the Helvetica stack behind it, since a consumer embedding the SVG
|
|
13172
|
+
// will not have that @font-face rule.
|
|
13173
|
+
"theme-neon": {
|
|
13174
|
+
frameBorder: "#60ff33",
|
|
13175
|
+
frameBg: "#000000",
|
|
13176
|
+
titleText: "#8ffc5b",
|
|
13177
|
+
participantBg: "#000000",
|
|
13178
|
+
participantBorder: "#8ffc5b",
|
|
13179
|
+
participantText: "#8ffc5b",
|
|
13180
|
+
messageArrow: "#8ffc5b",
|
|
13181
|
+
messageText: "#8ffc5b",
|
|
13182
|
+
occurrenceBg: "#8ffc5b",
|
|
13183
|
+
occurrenceBorder: "#8ffc5b",
|
|
13184
|
+
fragmentBorder: "#60ff33",
|
|
13185
|
+
fragmentHeaderBg: "#000000",
|
|
13186
|
+
fragmentHeaderOpacity: "1",
|
|
13187
|
+
fragmentText: "#8ffc5b",
|
|
13188
|
+
fragmentSeparator: "#60ff33",
|
|
13189
|
+
commentText: "#8ffc5b",
|
|
13190
|
+
fontFamily: `"MS Sans Serif", ${HELVETICA}`
|
|
13191
|
+
}
|
|
13192
|
+
};
|
|
13193
|
+
function resolvePalette(theme) {
|
|
13194
|
+
if (theme && theme in THEME_PALETTES) {
|
|
13195
|
+
return THEME_PALETTES[theme];
|
|
13196
|
+
}
|
|
13197
|
+
return DEFAULT_PALETTE;
|
|
13198
|
+
}
|
|
13199
|
+
function buildThemeStyles(p) {
|
|
13200
|
+
return `
|
|
13201
|
+
.frame-border-outer { fill: ${p.frameBorder}; }
|
|
13202
|
+
.frame-border-inner { fill: ${p.frameBg}; }
|
|
13203
|
+
.frame-header-bg { fill: ${p.frameBg}; }
|
|
13204
|
+
.frame-header-line { stroke: ${p.frameBorder}; stroke-width: 1; shape-rendering: crispEdges; }
|
|
13205
|
+
.frame-title { font-family: ${p.fontFamily}; font-size: 16px; font-weight: 600; fill: ${p.titleText}; }
|
|
13206
|
+
.participant-box { fill: ${p.participantBg}; stroke: ${p.participantBorder}; stroke-width: 2; }
|
|
13207
|
+
.participant-label { font-family: ${p.fontFamily}; font-size: 16px; fill: ${p.participantText}; }
|
|
13208
|
+
.participant-icon { color: ${p.participantText}; }
|
|
13209
|
+
.participant-icon [fill="currentColor"]:not([stroke]) { stroke: ${p.participantBorder}; stroke-width: 1; }
|
|
13210
|
+
.lifeline { stroke: ${p.participantBorder}; stroke-width: 1; }
|
|
13211
|
+
.message-line { stroke: ${p.messageArrow}; stroke-width: 2; shape-rendering: crispEdges; }
|
|
13212
|
+
.message-label { font-family: ${p.fontFamily}; font-size: 14px; fill: ${p.messageText}; }
|
|
13213
|
+
.arrow-head { fill: ${p.messageArrow}; stroke: ${p.messageArrow}; stroke-width: 2; }
|
|
13112
13214
|
.arrow-open { fill: none; }
|
|
13113
|
-
.occurrence { fill:
|
|
13114
|
-
.fragment-border { fill: none; stroke:
|
|
13115
|
-
.fragment-header { fill:
|
|
13116
|
-
.fragment-label { font-family:
|
|
13117
|
-
.fragment-condition { font-family:
|
|
13118
|
-
.fragment-separator { stroke:
|
|
13119
|
-
.fragment-section-label { font-family:
|
|
13120
|
-
.return-line { stroke:
|
|
13121
|
-
.return-arrow { stroke:
|
|
13122
|
-
.return-label { font-family:
|
|
13123
|
-
.return-icon { fill:
|
|
13215
|
+
.occurrence { fill: ${p.occurrenceBg}; stroke: ${p.occurrenceBorder}; stroke-width: 2; shape-rendering: crispEdges; }
|
|
13216
|
+
.fragment-border { fill: none; stroke: ${p.fragmentBorder}; stroke-width: 1; shape-rendering: crispEdges; }
|
|
13217
|
+
.fragment-header { fill: ${p.fragmentHeaderBg}; fill-opacity: ${p.fragmentHeaderOpacity}; stroke: none; shape-rendering: crispEdges; }
|
|
13218
|
+
.fragment-label { font-family: ${p.fontFamily}; font-size: 14px; font-weight: 600; fill: ${p.fragmentText}; }
|
|
13219
|
+
.fragment-condition { font-family: ${p.fontFamily}; font-size: 14px; fill: ${p.fragmentText}; }
|
|
13220
|
+
.fragment-separator { stroke: ${p.fragmentSeparator}; stroke-width: 1; shape-rendering: crispEdges; }
|
|
13221
|
+
.fragment-section-label { font-family: ${p.fontFamily}; font-size: 14px; fill: ${p.fragmentText}; }
|
|
13222
|
+
.return-line { stroke: ${p.messageArrow}; stroke-width: 2; stroke-dasharray: 6,4; shape-rendering: crispEdges; }
|
|
13223
|
+
.return-arrow { stroke: ${p.messageArrow}; stroke-width: 2; fill: none; }
|
|
13224
|
+
.return-label { font-family: ${p.fontFamily}; font-size: 14px; fill: ${p.messageText}; }
|
|
13225
|
+
.return-icon { fill: ${p.messageText}; }
|
|
13124
13226
|
.divider-line { stroke: #aaaa33; stroke-width: 1; }
|
|
13125
13227
|
.divider-bg { fill: #fff5ad; stroke: #aaaa33; stroke-width: 1; }
|
|
13126
|
-
.divider-label { font-family:
|
|
13127
|
-
.comment-text { font-family:
|
|
13128
|
-
.seq-number { font-family:
|
|
13129
|
-
.group-outline { fill: none; stroke:
|
|
13130
|
-
.group-title-bg { fill:
|
|
13131
|
-
.group-title-text { font-family:
|
|
13228
|
+
.divider-label { font-family: ${p.fontFamily}; font-size: 14px; fill: #333; }
|
|
13229
|
+
.comment-text { font-family: ${p.fontFamily}; font-size: 14px; fill: ${p.commentText}; opacity: 0.5; }
|
|
13230
|
+
.seq-number { font-family: ${p.fontFamily}; font-size: 12px; font-weight: 100; fill: #6b7280; }
|
|
13231
|
+
.group-outline { fill: none; stroke: ${p.participantBorder}; }
|
|
13232
|
+
.group-title-bg { fill: ${p.frameBg}; stroke: none; }
|
|
13233
|
+
.group-title-text { font-family: ${p.fontFamily}; font-size: 13px; font-weight: 400; fill: ${p.participantText}; }
|
|
13132
13234
|
`;
|
|
13235
|
+
}
|
|
13236
|
+
|
|
13237
|
+
const FRAME_HEADER_HEIGHT = 28;
|
|
13238
|
+
const FRAME_BORDER_RADIUS = 4;
|
|
13133
13239
|
function renderToSvg(code, options) {
|
|
13134
13240
|
const rootContext = RootContext(code);
|
|
13135
13241
|
if (!rootContext) {
|
|
13136
|
-
return {
|
|
13242
|
+
return {
|
|
13243
|
+
svg: "<svg></svg>",
|
|
13244
|
+
innerSvg: "",
|
|
13245
|
+
width: 0,
|
|
13246
|
+
height: 0,
|
|
13247
|
+
viewBox: "0 0 0 0",
|
|
13248
|
+
geometry: void 0
|
|
13249
|
+
};
|
|
13137
13250
|
}
|
|
13138
13251
|
const coordinates = new Coordinates(rootContext, WidthProviderOnCanvas);
|
|
13139
13252
|
const verticalCoordinates = new VerticalCoordinates(rootContext);
|
|
@@ -13147,7 +13260,7 @@ function renderToSvg(code, options) {
|
|
|
13147
13260
|
title,
|
|
13148
13261
|
measureText: WidthProviderOnCanvas
|
|
13149
13262
|
});
|
|
13150
|
-
return { ...composeSvg(geometry), geometry };
|
|
13263
|
+
return { ...composeSvg(geometry, options), geometry };
|
|
13151
13264
|
}
|
|
13152
13265
|
function composeSvg(g, options) {
|
|
13153
13266
|
const padding = 10;
|
|
@@ -13206,10 +13319,10 @@ function composeSvg(g, options) {
|
|
|
13206
13319
|
const headerLineY = headerH + contentPaddingTop;
|
|
13207
13320
|
const headerLineDrawY = headerLineY - 0.5;
|
|
13208
13321
|
const headerLineSvg = `<line class="frame-header-line" x1="1" y1="${headerLineDrawY}" x2="${viewWidth - 1}" y2="${headerLineDrawY}"/>`;
|
|
13209
|
-
const titleSvg = g.title ? `<text x="5" y="${headerLineDrawY / 2}" dominant-baseline="central" class="frame-title">${
|
|
13322
|
+
const titleSvg = g.title ? `<text x="5" y="${headerLineDrawY / 2}" dominant-baseline="central" class="frame-title">${esc(g.title)}</text>` : "";
|
|
13210
13323
|
const viewBox = `0 0 ${viewWidth} ${viewHeight}`;
|
|
13211
13324
|
const defs = `<defs>
|
|
13212
|
-
<style>${
|
|
13325
|
+
<style>${buildThemeStyles(resolvePalette(options?.theme))}</style>
|
|
13213
13326
|
</defs>`;
|
|
13214
13327
|
const frame = `${frameSvg}
|
|
13215
13328
|
${headerLineSvg}
|
|
@@ -13225,9 +13338,6 @@ ${innerSvg}
|
|
|
13225
13338
|
</svg>`;
|
|
13226
13339
|
return { svg, innerSvg, width: viewWidth, height: viewHeight, viewBox };
|
|
13227
13340
|
}
|
|
13228
|
-
function escXml(s) {
|
|
13229
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
13230
|
-
}
|
|
13231
13341
|
|
|
13232
13342
|
function readVersion() {
|
|
13233
13343
|
const pkgPath = resolve(import.meta.dir, "../../package.json");
|
|
@@ -13249,7 +13359,8 @@ Rendering:
|
|
|
13249
13359
|
-o, --output <file> Output file (use "-" for stdout; default: <input>.svg)
|
|
13250
13360
|
-e, --outputFormat <format> Output format: "svg" (default) or "png"
|
|
13251
13361
|
-s, --scale <factor> Pixel scale factor for PNG (default: 2; ignored for SVG)
|
|
13252
|
-
-t, --theme <name> Theme
|
|
13362
|
+
-t, --theme <name> Theme: default, mermaid, clean-light, clean-dark,
|
|
13363
|
+
neon (prefix "theme-"; unknown names use default)
|
|
13253
13364
|
-c, --configFile <file> JSON config file with { theme, scale, outputFormat }
|
|
13254
13365
|
--md Markdown mode: render zenuml code blocks and produce output Markdown
|
|
13255
13366
|
|
|
@@ -13610,7 +13721,6 @@ async function checkOne(input) {
|
|
|
13610
13721
|
errors: [{ line: 0, column: 0, msg: err.message }]
|
|
13611
13722
|
};
|
|
13612
13723
|
}
|
|
13613
|
-
Parser.Errors.length = 0;
|
|
13614
13724
|
Parser.ErrorDetails.length = 0;
|
|
13615
13725
|
Parser.RootContext(code);
|
|
13616
13726
|
const errors = Parser.ErrorDetails.map((e) => ({
|
|
@@ -13776,7 +13886,6 @@ async function main() {
|
|
|
13776
13886
|
`);
|
|
13777
13887
|
process.exit(1);
|
|
13778
13888
|
}
|
|
13779
|
-
Parser.Errors.length = 0;
|
|
13780
13889
|
Parser.ErrorDetails.length = 0;
|
|
13781
13890
|
const tree = Parser.RootContext(code);
|
|
13782
13891
|
if (Parser.ErrorDetails.length > 0) {
|