@zenuml/core 4.2.0 → 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 +711 -771
- package/dist/parser/index.cjs +2 -2
- package/dist/parser/index.mjs +1181 -1255
- package/dist/zenuml.esm.mjs +16924 -20126
- package/dist/zenuml.js +613 -741
- 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
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import antlr4 from 'antlr4';
|
|
3
3
|
import { marked } from 'marked';
|
|
4
|
-
import {
|
|
5
|
-
import { resolve,
|
|
4
|
+
import { readFileSync, statSync, mkdirSync, writeFileSync, watch } from 'node:fs';
|
|
5
|
+
import { resolve, join, dirname, basename, extname } from 'node:path';
|
|
6
6
|
|
|
7
7
|
// Generated from java-escape by ANTLR 4.11.1
|
|
8
8
|
// jshint ignore: start
|
|
@@ -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() {
|
|
9586
|
-
const fromCtx = this.from();
|
|
9587
|
-
return fromCtx?.name?.()?.getFormattedText?.() || fromCtx?.getFormattedText?.();
|
|
9588
|
-
};
|
|
9589
|
-
AsyncMessageContext.prototype.From = function() {
|
|
9590
|
-
return this.ProvidedFrom() || this.ClosestAncestorStat()?.Origin();
|
|
9591
|
-
};
|
|
9592
|
-
ReturnAsyncMessageContext.prototype.ProvidedFrom = function() {
|
|
9508
|
+
MessageContext.prototype.From = fromProvidedOrOrigin;
|
|
9509
|
+
function providedFromDirectFrom() {
|
|
9593
9510
|
const fromCtx = this.from();
|
|
9594
9511
|
return fromCtx?.name?.()?.getFormattedText?.() || fromCtx?.getFormattedText?.();
|
|
9595
|
-
}
|
|
9596
|
-
|
|
9597
|
-
|
|
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,14 +10685,26 @@ class FragmentAltVM extends FragmentVM {
|
|
|
10877
10685
|
}
|
|
10878
10686
|
}
|
|
10879
10687
|
|
|
10880
|
-
class
|
|
10881
|
-
|
|
10688
|
+
class FragmentRefVM extends StatementVM {
|
|
10689
|
+
kind = "ref";
|
|
10690
|
+
measure(top) {
|
|
10691
|
+
const context = this.context?.ref?.() || this.context;
|
|
10692
|
+
const commentHeight = this.measureComment(context);
|
|
10693
|
+
const headerHeight = this.metrics.fragmentHeaderHeight;
|
|
10694
|
+
const height = commentHeight + headerHeight + this.metrics.fragmentPaddingBottom;
|
|
10695
|
+
return { top, height, kind: this.kind };
|
|
10696
|
+
}
|
|
10697
|
+
}
|
|
10698
|
+
|
|
10699
|
+
class FragmentSingleBlockVM extends StatementVM {
|
|
10700
|
+
constructor(statement, fragment, runtime, kind) {
|
|
10882
10701
|
super(statement, runtime);
|
|
10883
10702
|
this.fragment = fragment;
|
|
10703
|
+
this.kind = kind;
|
|
10884
10704
|
}
|
|
10885
10705
|
measure(top, origin) {
|
|
10886
10706
|
const commentHeight = this.measureComment(this.fragment);
|
|
10887
|
-
let cursor = top +
|
|
10707
|
+
let cursor = top + FRAGMENT_BORDER_WIDTH + this.metrics.fragmentHeaderHeight + commentHeight;
|
|
10888
10708
|
const hasCondition = Boolean(this.fragment?.parExpr?.()?.condition?.());
|
|
10889
10709
|
if (hasCondition) cursor += 20;
|
|
10890
10710
|
const block = this.fragment?.braceBlock?.()?.block?.();
|
|
@@ -10892,7 +10712,7 @@ class FragmentSingleBlockVM extends FragmentVM {
|
|
|
10892
10712
|
const fragmentOrigin = this.findLeftParticipant(this.fragment, origin) || origin;
|
|
10893
10713
|
cursor = this.layoutBlock(block, fragmentOrigin, cursor, this.kind);
|
|
10894
10714
|
}
|
|
10895
|
-
cursor += this.metrics.fragmentPaddingBottom +
|
|
10715
|
+
cursor += this.metrics.fragmentPaddingBottom + FRAGMENT_BORDER_WIDTH;
|
|
10896
10716
|
return {
|
|
10897
10717
|
top,
|
|
10898
10718
|
height: cursor - top,
|
|
@@ -10901,38 +10721,7 @@ class FragmentSingleBlockVM extends FragmentVM {
|
|
|
10901
10721
|
}
|
|
10902
10722
|
}
|
|
10903
10723
|
|
|
10904
|
-
class
|
|
10905
|
-
kind = "critical";
|
|
10906
|
-
}
|
|
10907
|
-
|
|
10908
|
-
class FragmentLoopVM extends FragmentSingleBlockVM {
|
|
10909
|
-
kind = "loop";
|
|
10910
|
-
}
|
|
10911
|
-
|
|
10912
|
-
class FragmentOptVM extends FragmentSingleBlockVM {
|
|
10913
|
-
kind = "opt";
|
|
10914
|
-
}
|
|
10915
|
-
|
|
10916
|
-
class FragmentParVM extends FragmentSingleBlockVM {
|
|
10917
|
-
kind = "par";
|
|
10918
|
-
}
|
|
10919
|
-
|
|
10920
|
-
class FragmentRefVM extends FragmentVM {
|
|
10921
|
-
kind = "ref";
|
|
10922
|
-
measure(top) {
|
|
10923
|
-
const context = this.context?.ref?.() || this.context;
|
|
10924
|
-
const commentHeight = this.measureComment(context);
|
|
10925
|
-
const headerHeight = this.metrics.fragmentHeaderHeight;
|
|
10926
|
-
const height = commentHeight + headerHeight + this.metrics.fragmentPaddingBottom;
|
|
10927
|
-
return { top, height, kind: this.kind };
|
|
10928
|
-
}
|
|
10929
|
-
}
|
|
10930
|
-
|
|
10931
|
-
class FragmentSectionVM extends FragmentSingleBlockVM {
|
|
10932
|
-
kind = "section";
|
|
10933
|
-
}
|
|
10934
|
-
|
|
10935
|
-
class FragmentTryCatchVM extends FragmentVM {
|
|
10724
|
+
class FragmentTryCatchVM extends StatementVM {
|
|
10936
10725
|
constructor(statement, tcf, runtime) {
|
|
10937
10726
|
super(statement, runtime);
|
|
10938
10727
|
this.tcf = tcf;
|
|
@@ -11011,6 +10800,14 @@ class ReturnStatementVM extends StatementVM {
|
|
|
11011
10800
|
}
|
|
11012
10801
|
}
|
|
11013
10802
|
|
|
10803
|
+
const SINGLE_BLOCK_FRAGMENT_KINDS = [
|
|
10804
|
+
"loop",
|
|
10805
|
+
"opt",
|
|
10806
|
+
"par",
|
|
10807
|
+
"section",
|
|
10808
|
+
"critical"
|
|
10809
|
+
];
|
|
10810
|
+
|
|
11014
10811
|
class SyncMessageStatementVM extends StatementVM {
|
|
11015
10812
|
constructor(statement, message, runtime) {
|
|
11016
10813
|
super(statement, runtime);
|
|
@@ -11025,7 +10822,7 @@ class SyncMessageStatementVM extends StatementVM {
|
|
|
11025
10822
|
const block = this.message.braceBlock?.()?.block?.();
|
|
11026
10823
|
const assignee = this.message.Assignment?.();
|
|
11027
10824
|
const isSelf = source === target;
|
|
11028
|
-
const messageHeight = isSelf ?
|
|
10825
|
+
const messageHeight = isSelf ? SELF_MESSAGE_HEIGHT : MESSAGE_HEIGHT;
|
|
11029
10826
|
cursor += messageHeight;
|
|
11030
10827
|
if (block) {
|
|
11031
10828
|
const fragmentOrigin = this.findLeftParticipant(this.message, origin) || origin;
|
|
@@ -11061,25 +10858,11 @@ const createStatementVM = (statement, runtime) => {
|
|
|
11061
10858
|
if (statement.divider?.()) {
|
|
11062
10859
|
return new DividerStatementVM(statement, runtime);
|
|
11063
10860
|
}
|
|
11064
|
-
const
|
|
11065
|
-
|
|
11066
|
-
|
|
11067
|
-
|
|
11068
|
-
|
|
11069
|
-
if (opt) {
|
|
11070
|
-
return new FragmentOptVM(statement, opt, runtime);
|
|
11071
|
-
}
|
|
11072
|
-
const par = statement.par?.();
|
|
11073
|
-
if (par) {
|
|
11074
|
-
return new FragmentParVM(statement, par, runtime);
|
|
11075
|
-
}
|
|
11076
|
-
const section = statement.section?.();
|
|
11077
|
-
if (section) {
|
|
11078
|
-
return new FragmentSectionVM(statement, section, runtime);
|
|
11079
|
-
}
|
|
11080
|
-
const critical = statement.critical?.();
|
|
11081
|
-
if (critical) {
|
|
11082
|
-
return new FragmentCriticalVM(statement, critical, runtime);
|
|
10861
|
+
for (const kind of SINGLE_BLOCK_FRAGMENT_KINDS) {
|
|
10862
|
+
const fragment = statement[kind]?.();
|
|
10863
|
+
if (fragment) {
|
|
10864
|
+
return new FragmentSingleBlockVM(statement, fragment, runtime, kind);
|
|
10865
|
+
}
|
|
11083
10866
|
}
|
|
11084
10867
|
const tcf = statement.tcf?.();
|
|
11085
10868
|
if (tcf) {
|
|
@@ -11116,17 +10899,6 @@ class BlockVM extends NodeVM {
|
|
|
11116
10899
|
}
|
|
11117
10900
|
}
|
|
11118
10901
|
|
|
11119
|
-
const SPACING_UNIT = 4;
|
|
11120
|
-
const tw = (value) => value * SPACING_UNIT;
|
|
11121
|
-
const DEFAULT_LAYOUT_METRICS = {
|
|
11122
|
-
statementMarginY: tw(4),
|
|
11123
|
-
// .statement-container .my-4
|
|
11124
|
-
fragmentHeaderHeight: 25,
|
|
11125
|
-
// .fragment .leading-4 => line-height: 1rem
|
|
11126
|
-
fragmentPaddingBottom: 10
|
|
11127
|
-
// .zenuml .fragment =>padding-bottom: 10px
|
|
11128
|
-
};
|
|
11129
|
-
|
|
11130
10902
|
class VerticalCoordinates {
|
|
11131
10903
|
statementMap = /* @__PURE__ */ new Map();
|
|
11132
10904
|
creationTops = /* @__PURE__ */ new Map();
|
|
@@ -11138,16 +10910,13 @@ class VerticalCoordinates {
|
|
|
11138
10910
|
const originParticipant = messages.length === 0 ? _STARTER_ : messages[0].from || _STARTER_;
|
|
11139
10911
|
const runtime = {
|
|
11140
10912
|
metrics: DEFAULT_LAYOUT_METRICS,
|
|
11141
|
-
rootBlock,
|
|
11142
10913
|
participants,
|
|
11143
|
-
originParticipant,
|
|
11144
10914
|
recordCoordinate: (statement, coordinate) => {
|
|
11145
10915
|
const key = createStatementKey(statement);
|
|
11146
10916
|
this.statementMap.set(key, coordinate);
|
|
11147
10917
|
},
|
|
11148
10918
|
updateCreationTop: (participant, top) => {
|
|
11149
10919
|
const paddingTop = top - 8;
|
|
11150
|
-
rootLogger.info(`[VerticalCoordinates] updateCreationTop participant="${participant}" raw=${top} paddingTop=${paddingTop}`);
|
|
11151
10920
|
this.creationTops.set(participant, paddingTop);
|
|
11152
10921
|
}
|
|
11153
10922
|
};
|
|
@@ -11160,19 +10929,13 @@ class VerticalCoordinates {
|
|
|
11160
10929
|
getStatementCoordinate(key) {
|
|
11161
10930
|
return this.statementMap.get(key);
|
|
11162
10931
|
}
|
|
11163
|
-
getStatementCoordinateFor(statement) {
|
|
11164
|
-
return this.statementMap.get(createStatementKey(statement));
|
|
11165
|
-
}
|
|
11166
|
-
entries() {
|
|
11167
|
-
return Array.from(this.statementMap.entries());
|
|
11168
|
-
}
|
|
11169
10932
|
getTotalHeight() {
|
|
11170
10933
|
return this.totalHeight;
|
|
11171
10934
|
}
|
|
11172
10935
|
}
|
|
11173
10936
|
|
|
11174
10937
|
let dic = {};
|
|
11175
|
-
|
|
10938
|
+
let persistDic = {};
|
|
11176
10939
|
const getCache = (key) => {
|
|
11177
10940
|
if (key != null) {
|
|
11178
10941
|
const cacheValue = dic[key] ?? persistDic[key];
|
|
@@ -11186,6 +10949,10 @@ const setCache = (key, value, persist = false) => {
|
|
|
11186
10949
|
persistDic[key] = value;
|
|
11187
10950
|
}
|
|
11188
10951
|
};
|
|
10952
|
+
const clearPersistentCache = () => {
|
|
10953
|
+
persistDic = {};
|
|
10954
|
+
dic = {};
|
|
10955
|
+
};
|
|
11189
10956
|
|
|
11190
10957
|
const FONT_FAMILY = "Helvetica, Verdana, serif";
|
|
11191
10958
|
const FONT_SIZE_PARTICIPANT = "16px";
|
|
@@ -11195,28 +10962,25 @@ function getFontSpec() {
|
|
|
11195
10962
|
}
|
|
11196
10963
|
let canvasCtx = null;
|
|
11197
10964
|
function setCanvasContext(ctx) {
|
|
10965
|
+
if (ctx === canvasCtx) return;
|
|
11198
10966
|
canvasCtx = ctx;
|
|
10967
|
+
clearPersistentCache();
|
|
11199
10968
|
}
|
|
11200
10969
|
function getCanvasContext() {
|
|
11201
10970
|
if (canvasCtx) return canvasCtx;
|
|
11202
10971
|
try {
|
|
11203
10972
|
if (typeof OffscreenCanvas !== "undefined") {
|
|
11204
10973
|
canvasCtx = new OffscreenCanvas(1, 1).getContext("2d");
|
|
11205
|
-
rootLogger.debug("[ZenUML] WidthProviderOnCanvas: using OffscreenCanvas");
|
|
11206
10974
|
} else if (typeof document !== "undefined") {
|
|
11207
10975
|
canvasCtx = document.createElement("canvas").getContext("2d");
|
|
11208
|
-
rootLogger.debug("[ZenUML] WidthProviderOnCanvas: using <canvas> element");
|
|
11209
|
-
} else {
|
|
11210
|
-
rootLogger.debug("[ZenUML] WidthProviderOnCanvas: no canvas available, using character estimate fallback");
|
|
11211
10976
|
}
|
|
11212
10977
|
} catch {
|
|
11213
|
-
rootLogger.debug("[ZenUML] WidthProviderOnCanvas: canvas creation failed, using character estimate fallback");
|
|
11214
10978
|
}
|
|
11215
10979
|
return canvasCtx;
|
|
11216
10980
|
}
|
|
11217
10981
|
function WidthProviderOnCanvas(text, type) {
|
|
11218
10982
|
const measured = text.trim();
|
|
11219
|
-
const cacheKey = `WidthProviderOnCanvas_${measured}_${type}`;
|
|
10983
|
+
const cacheKey = `WidthProviderOnCanvas_${getFontSpec()}_${measured}_${type}`;
|
|
11220
10984
|
const cacheValue = getCache(cacheKey);
|
|
11221
10985
|
if (cacheValue != null) {
|
|
11222
10986
|
return cacheValue;
|
|
@@ -11224,7 +10988,7 @@ function WidthProviderOnCanvas(text, type) {
|
|
|
11224
10988
|
const ctx = getCanvasContext();
|
|
11225
10989
|
if (!ctx) {
|
|
11226
10990
|
const width2 = Math.ceil(measured.length * 16 * 0.6);
|
|
11227
|
-
setCache(cacheKey, width2
|
|
10991
|
+
setCache(cacheKey, width2);
|
|
11228
10992
|
return width2;
|
|
11229
10993
|
}
|
|
11230
10994
|
ctx.font = getFontSpec();
|
|
@@ -11232,7 +10996,10 @@ function WidthProviderOnCanvas(text, type) {
|
|
|
11232
10996
|
setCache(cacheKey, width, true);
|
|
11233
10997
|
return width;
|
|
11234
10998
|
}
|
|
11235
|
-
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
|
+
);
|
|
11236
11003
|
function measureWithSvg(text, fontSize) {
|
|
11237
11004
|
if (typeof document === "undefined") return null;
|
|
11238
11005
|
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
@@ -11251,7 +11018,8 @@ function measureTextWithFont(text, fontSize) {
|
|
|
11251
11018
|
const measured = text.trim();
|
|
11252
11019
|
if (!measured) return 0;
|
|
11253
11020
|
const hasEmoji = EMOJI_PATTERN.test(measured);
|
|
11254
|
-
const
|
|
11021
|
+
const font = `${fontSize} ${FONT_FAMILY}`;
|
|
11022
|
+
const cacheKey = hasEmoji ? `measureTextWithFont_svg_${font}_${measured}` : `measureTextWithFont_${font}_${measured}`;
|
|
11255
11023
|
const cacheValue = getCache(cacheKey);
|
|
11256
11024
|
if (cacheValue != null) {
|
|
11257
11025
|
return cacheValue;
|
|
@@ -11267,10 +11035,10 @@ function measureTextWithFont(text, fontSize) {
|
|
|
11267
11035
|
if (!ctx) {
|
|
11268
11036
|
const px = Number.parseFloat(fontSize) || 14;
|
|
11269
11037
|
const width2 = Math.ceil(measured.length * px * 0.6);
|
|
11270
|
-
setCache(cacheKey, width2
|
|
11038
|
+
setCache(cacheKey, width2);
|
|
11271
11039
|
return width2;
|
|
11272
11040
|
}
|
|
11273
|
-
ctx.font =
|
|
11041
|
+
ctx.font = font;
|
|
11274
11042
|
const width = ctx.measureText(measured).width;
|
|
11275
11043
|
setCache(cacheKey, width, true);
|
|
11276
11044
|
return width;
|
|
@@ -11391,22 +11159,42 @@ function FrameBorder(frame) {
|
|
|
11391
11159
|
return { left: 0, right: 0 };
|
|
11392
11160
|
}
|
|
11393
11161
|
return {
|
|
11394
|
-
type: frame.type,
|
|
11395
11162
|
left: FRAGMENT_PADDING_X * longestPath(frame, "LEFT" /* LEFT */),
|
|
11396
11163
|
right: FRAGMENT_PADDING_X * longestPath(frame, "RIGHT" /* RIGHT */)
|
|
11397
11164
|
};
|
|
11398
11165
|
}
|
|
11399
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
|
+
|
|
11400
11192
|
const PARTICIPANT_TOP_SPACE = PARTICIPANT_TOP_SPACE_FOR_GROUP + 8;
|
|
11401
11193
|
const PARTICIPANT_BOX_PADDING = 16;
|
|
11402
|
-
const PARTICIPANT_BOX_PADDING_ASSIGNEE = 16;
|
|
11403
11194
|
const PARTICIPANT_ICON_ROW_WIDTH = 28;
|
|
11404
11195
|
const PARTICIPANT_EMOJI_WIDTH = 20;
|
|
11405
11196
|
const PARTICIPANT_VISUAL_HEIGHT = 40;
|
|
11406
11197
|
const PARTICIPANT_MAX_WIDTH = 250;
|
|
11407
|
-
function snapX$1(x) {
|
|
11408
|
-
return x;
|
|
11409
|
-
}
|
|
11410
11198
|
function cssToSvgStyle(css) {
|
|
11411
11199
|
const result = {};
|
|
11412
11200
|
let hasKeys = false;
|
|
@@ -11425,24 +11213,32 @@ function cssToSvgStyle(css) {
|
|
|
11425
11213
|
|
|
11426
11214
|
function buildParticipants(models, coordinates, verticalCoordinates, measureText) {
|
|
11427
11215
|
return models.map((m) => {
|
|
11428
|
-
const centerX =
|
|
11216
|
+
const centerX = coordinates.getPosition(m.name);
|
|
11429
11217
|
const halfWidth = coordinates.half(m.name);
|
|
11430
|
-
const isAssignee = m.name.includes(":") && m.getDisplayName() === m.name;
|
|
11431
11218
|
let width;
|
|
11432
11219
|
let measuredTextWidth;
|
|
11433
11220
|
let measuredStereotypeWidth;
|
|
11434
11221
|
if (measureText && m.name !== _STARTER_) {
|
|
11435
11222
|
const textWidth = measureSvgParticipantLabelWidth(m.getDisplayName());
|
|
11436
11223
|
measuredTextWidth = textWidth;
|
|
11437
|
-
const padding =
|
|
11224
|
+
const padding = PARTICIPANT_BOX_PADDING;
|
|
11438
11225
|
const iconWidth = m.hasIcon() ? PARTICIPANT_ICON_ROW_WIDTH : 0;
|
|
11439
11226
|
const emojiWidth = m.emoji ? PARTICIPANT_EMOJI_WIDTH : 0;
|
|
11440
11227
|
const STEREOTYPE_BOX_OVERHEAD = 8;
|
|
11441
11228
|
if (m.stereotype) {
|
|
11442
|
-
measuredStereotypeWidth = measureSvgParticipantLabelWidth(
|
|
11229
|
+
measuredStereotypeWidth = measureSvgParticipantLabelWidth(
|
|
11230
|
+
`«${m.stereotype}»`
|
|
11231
|
+
);
|
|
11443
11232
|
}
|
|
11444
11233
|
const stereotypeBoxWidth = measuredStereotypeWidth != null ? measuredStereotypeWidth + STEREOTYPE_BOX_OVERHEAD : 0;
|
|
11445
|
-
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
|
+
);
|
|
11446
11242
|
} else {
|
|
11447
11243
|
width = Math.min(halfWidth * 2 - MARGIN, PARTICIPANT_MAX_WIDTH);
|
|
11448
11244
|
}
|
|
@@ -11521,39 +11317,49 @@ function buildGroups(participants, diagramHeight) {
|
|
|
11521
11317
|
return groups;
|
|
11522
11318
|
}
|
|
11523
11319
|
|
|
11524
|
-
|
|
11525
|
-
|
|
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
|
+
}
|
|
11526
11353
|
}
|
|
11354
|
+
|
|
11527
11355
|
const COMMENT_FONT_ASCENT = 15;
|
|
11528
11356
|
function buildFragmentGeometry(info, coord, coordinates, verticalCoordinates, allParticipants, _measureText, commentHeight = 0, commentText, commentStyle, commentYBase) {
|
|
11529
11357
|
const statNode = info.statNode;
|
|
11530
|
-
if (!statNode) return null;
|
|
11531
11358
|
const fragmentCtx = findFragmentContext(statNode);
|
|
11532
|
-
|
|
11533
|
-
|
|
11534
|
-
|
|
11535
|
-
|
|
11536
|
-
label: info.fragmentLabel || "",
|
|
11537
|
-
labelWidth: info.fragmentLabel ? measureSvgFragmentLabelWidth(resolveEmojiInText(info.fragmentLabel)) : void 0,
|
|
11538
|
-
x: 0,
|
|
11539
|
-
y: coord.top,
|
|
11540
|
-
width: coordinates.getWidth(),
|
|
11541
|
-
height: coord.height,
|
|
11542
|
-
headerY: coord.top + 1 + commentHeight,
|
|
11543
|
-
sections: [],
|
|
11544
|
-
number: info.number,
|
|
11545
|
-
depth: info.depth
|
|
11546
|
-
},
|
|
11547
|
-
comment: commentText && commentYBase != null ? {
|
|
11548
|
-
x: 1,
|
|
11549
|
-
y: commentYBase + 1 + COMMENT_FONT_ASCENT,
|
|
11550
|
-
text: commentText,
|
|
11551
|
-
style: commentStyle,
|
|
11552
|
-
fragmentComment: true
|
|
11553
|
-
} : void 0
|
|
11554
|
-
};
|
|
11555
|
-
}
|
|
11556
|
-
const localNames = getDeepParticipantNames(fragmentCtx, info.fragmentSections);
|
|
11359
|
+
const localNames = getDeepParticipantNames(
|
|
11360
|
+
fragmentCtx,
|
|
11361
|
+
info.fragmentSections
|
|
11362
|
+
);
|
|
11557
11363
|
const leftParticipant = allParticipants.find((p) => localNames.includes(p)) || "";
|
|
11558
11364
|
const rightParticipant = allParticipants.slice().reverse().find((p) => localNames.includes(p)) || "";
|
|
11559
11365
|
const frameBuilder = new FrameBuilder(allParticipants);
|
|
@@ -11562,14 +11368,8 @@ function buildFragmentGeometry(info, coord, coordinates, verticalCoordinates, al
|
|
|
11562
11368
|
let fragWidth;
|
|
11563
11369
|
let fragX;
|
|
11564
11370
|
if (leftParticipant && rightParticipant) {
|
|
11565
|
-
|
|
11566
|
-
|
|
11567
|
-
const extraWidths = selfMessages.map(
|
|
11568
|
-
(m) => coordinates.getMessageWidth(m) - coordinates.distance(m.from || _STARTER_, rightParticipant) - coordinates.half(rightParticipant)
|
|
11569
|
-
);
|
|
11570
|
-
const extraWidth = Math.max(0, ...extraWidths);
|
|
11571
|
-
fragWidth = Math.max(participantWidth, FRAGMENT_MIN_WIDTH) + fragBorder.left + fragBorder.right + extraWidth;
|
|
11572
|
-
fragX = snapX(coordinates.getPosition(leftParticipant)) - coordinates.half(leftParticipant);
|
|
11371
|
+
fragWidth = TotalWidth(statNode, coordinates);
|
|
11372
|
+
fragX = coordinates.getPosition(leftParticipant) - coordinates.half(leftParticipant);
|
|
11573
11373
|
} else {
|
|
11574
11374
|
fragWidth = Math.max(FRAGMENT_MIN_WIDTH, coordinates.getWidth());
|
|
11575
11375
|
fragX = 0;
|
|
@@ -11584,7 +11384,7 @@ function buildFragmentGeometry(info, coord, coordinates, verticalCoordinates, al
|
|
|
11584
11384
|
if (sectionBlock) {
|
|
11585
11385
|
const innerStats = sectionBlock.stat?.() || [];
|
|
11586
11386
|
if (innerStats.length > 0) {
|
|
11587
|
-
const firstStatKey =
|
|
11387
|
+
const firstStatKey = createStatementKey(innerStats[0]);
|
|
11588
11388
|
if (firstStatKey) {
|
|
11589
11389
|
const innerCoord = verticalCoordinates.getStatementCoordinate(firstStatKey);
|
|
11590
11390
|
if (innerCoord) {
|
|
@@ -11601,7 +11401,9 @@ function buildFragmentGeometry(info, coord, coordinates, verticalCoordinates, al
|
|
|
11601
11401
|
height: sectionHeight,
|
|
11602
11402
|
labelWidth: section.label ? measureSvgFragmentLabelWidth(resolveEmojiInText(section.label)) : void 0,
|
|
11603
11403
|
innerLabel: /^\[\s*.*\s*\]$/.test(section.label) ? section.label.slice(1, -1).trim() : void 0,
|
|
11604
|
-
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,
|
|
11605
11407
|
keyword: (() => {
|
|
11606
11408
|
const spaceIdx = section.label.indexOf(" ");
|
|
11607
11409
|
if (spaceIdx > 0 && !section.label.startsWith("finally") && !section.label.startsWith("[")) {
|
|
@@ -11612,7 +11414,9 @@ function buildFragmentGeometry(info, coord, coordinates, verticalCoordinates, al
|
|
|
11612
11414
|
keywordWidth: (() => {
|
|
11613
11415
|
const spaceIdx = section.label.indexOf(" ");
|
|
11614
11416
|
if (spaceIdx > 0 && !section.label.startsWith("finally") && !section.label.startsWith("[")) {
|
|
11615
|
-
return measureSvgFragmentLabelWidth(
|
|
11417
|
+
return measureSvgFragmentLabelWidth(
|
|
11418
|
+
section.label.substring(0, spaceIdx)
|
|
11419
|
+
);
|
|
11616
11420
|
}
|
|
11617
11421
|
return void 0;
|
|
11618
11422
|
})(),
|
|
@@ -11626,7 +11430,9 @@ function buildFragmentGeometry(info, coord, coordinates, verticalCoordinates, al
|
|
|
11626
11430
|
detailWidth: (() => {
|
|
11627
11431
|
const spaceIdx = section.label.indexOf(" ");
|
|
11628
11432
|
if (spaceIdx > 0 && !section.label.startsWith("finally") && !section.label.startsWith("[")) {
|
|
11629
|
-
return measureSvgFragmentLabelWidth(
|
|
11433
|
+
return measureSvgFragmentLabelWidth(
|
|
11434
|
+
section.label.substring(spaceIdx + 1)
|
|
11435
|
+
);
|
|
11630
11436
|
}
|
|
11631
11437
|
return void 0;
|
|
11632
11438
|
})()
|
|
@@ -11639,7 +11445,7 @@ function buildFragmentGeometry(info, coord, coordinates, verticalCoordinates, al
|
|
|
11639
11445
|
if (innerStats.length > 1) {
|
|
11640
11446
|
sections.push({ label: "", y: coord.top, height: 0 });
|
|
11641
11447
|
for (let i = 1; i < innerStats.length; i++) {
|
|
11642
|
-
const statKey =
|
|
11448
|
+
const statKey = createStatementKey(innerStats[i]);
|
|
11643
11449
|
if (!statKey) continue;
|
|
11644
11450
|
const innerCoord = verticalCoordinates.getStatementCoordinate(statKey);
|
|
11645
11451
|
if (!innerCoord) continue;
|
|
@@ -11672,7 +11478,9 @@ function buildFragmentGeometry(info, coord, coordinates, verticalCoordinates, al
|
|
|
11672
11478
|
y: coord.top,
|
|
11673
11479
|
width: fragWidth,
|
|
11674
11480
|
height: coord.height,
|
|
11675
|
-
|
|
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,
|
|
11676
11484
|
sections,
|
|
11677
11485
|
number: info.number,
|
|
11678
11486
|
depth: info.depth
|
|
@@ -11681,7 +11489,7 @@ function buildFragmentGeometry(info, coord, coordinates, verticalCoordinates, al
|
|
|
11681
11489
|
};
|
|
11682
11490
|
}
|
|
11683
11491
|
function findFragmentContext(stat) {
|
|
11684
|
-
for (const kind of
|
|
11492
|
+
for (const kind of SINGLE_BLOCK_FRAGMENT_KINDS) {
|
|
11685
11493
|
const frag = stat[kind]?.();
|
|
11686
11494
|
if (frag) return frag;
|
|
11687
11495
|
}
|
|
@@ -11693,10 +11501,6 @@ function findFragmentContext(stat) {
|
|
|
11693
11501
|
if (ref) return ref;
|
|
11694
11502
|
return null;
|
|
11695
11503
|
}
|
|
11696
|
-
function createStatementKeyFromStat(statement) {
|
|
11697
|
-
if (!statement?.start || !statement?.stop) return "";
|
|
11698
|
-
return `${statement.start.start}-${statement.stop.stop}`;
|
|
11699
|
-
}
|
|
11700
11504
|
function getDeepParticipantNames(fragmentCtx, sections) {
|
|
11701
11505
|
const names = new Set(getLocalParticipantNames(fragmentCtx));
|
|
11702
11506
|
if (sections) {
|
|
@@ -11734,11 +11538,37 @@ function walkBlock(block, currentOrigin, activeOccurrences, parentNumber, depth,
|
|
|
11734
11538
|
const to = message.Owner?.() || _STARTER_;
|
|
11735
11539
|
const label = normalizeLabel(message.SignatureText?.() || "");
|
|
11736
11540
|
const nestedBlock = message.braceBlock?.()?.block?.();
|
|
11737
|
-
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
|
+
});
|
|
11738
11558
|
if (nestedBlock) {
|
|
11739
11559
|
const innerOccs = new Map(activeOccurrences);
|
|
11740
11560
|
innerOccs.set(to, (innerOccs.get(to) || 0) + 1);
|
|
11741
|
-
results.push(
|
|
11561
|
+
results.push(
|
|
11562
|
+
...walkBlock(
|
|
11563
|
+
nestedBlock,
|
|
11564
|
+
to,
|
|
11565
|
+
innerOccs,
|
|
11566
|
+
number,
|
|
11567
|
+
depth + 1,
|
|
11568
|
+
"sync",
|
|
11569
|
+
0
|
|
11570
|
+
)
|
|
11571
|
+
);
|
|
11742
11572
|
}
|
|
11743
11573
|
continue;
|
|
11744
11574
|
}
|
|
@@ -11746,8 +11576,23 @@ function walkBlock(block, currentOrigin, activeOccurrences, parentNumber, depth,
|
|
|
11746
11576
|
if (asyncMsg) {
|
|
11747
11577
|
const from = asyncMsg.From?.() || asyncMsg.ProvidedFrom?.() || asyncMsg.Origin?.() || currentOrigin;
|
|
11748
11578
|
const to = asyncMsg.Owner?.() || asyncMsg.to?.()?.getFormattedText?.() || from;
|
|
11749
|
-
const label = normalizeLabel(
|
|
11750
|
-
|
|
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
|
+
});
|
|
11751
11596
|
continue;
|
|
11752
11597
|
}
|
|
11753
11598
|
const creation = stat.creation?.();
|
|
@@ -11756,11 +11601,36 @@ function walkBlock(block, currentOrigin, activeOccurrences, parentNumber, depth,
|
|
|
11756
11601
|
const to = creation.Owner?.() || "";
|
|
11757
11602
|
const label = normalizeLabel(creation.SignatureText?.() || "«create»");
|
|
11758
11603
|
const creationBlock = creation.braceBlock?.()?.block?.();
|
|
11759
|
-
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
|
+
});
|
|
11760
11620
|
if (creationBlock) {
|
|
11761
11621
|
const innerOccs = new Map(activeOccurrences);
|
|
11762
11622
|
innerOccs.set(to, (innerOccs.get(to) || 0) + 1);
|
|
11763
|
-
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
|
+
);
|
|
11764
11634
|
}
|
|
11765
11635
|
continue;
|
|
11766
11636
|
}
|
|
@@ -11770,13 +11640,40 @@ function walkBlock(block, currentOrigin, activeOccurrences, parentNumber, depth,
|
|
|
11770
11640
|
const asyncMessage = ret?.asyncMessage?.();
|
|
11771
11641
|
const from = asyncMessage?.From?.() || ret?.From?.() || currentOrigin;
|
|
11772
11642
|
const to = asyncMessage?.to?.()?.getFormattedText?.() || ret?.ReturnTo?.() || _STARTER_;
|
|
11773
|
-
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
|
+
});
|
|
11774
11658
|
continue;
|
|
11775
11659
|
}
|
|
11776
11660
|
const divider = stat.divider?.();
|
|
11777
11661
|
if (divider) {
|
|
11778
|
-
const label = normalizeLabel(
|
|
11779
|
-
|
|
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
|
+
});
|
|
11780
11677
|
continue;
|
|
11781
11678
|
}
|
|
11782
11679
|
const fragmentInfo = extractFragmentInfo(stat);
|
|
@@ -11798,12 +11695,19 @@ function walkBlock(block, currentOrigin, activeOccurrences, parentNumber, depth,
|
|
|
11798
11695
|
number,
|
|
11799
11696
|
depth
|
|
11800
11697
|
});
|
|
11801
|
-
walkFragmentBlocks(
|
|
11698
|
+
walkFragmentBlocks(
|
|
11699
|
+
stat,
|
|
11700
|
+
currentOrigin,
|
|
11701
|
+
results,
|
|
11702
|
+
activeOccurrences,
|
|
11703
|
+
number,
|
|
11704
|
+
depth
|
|
11705
|
+
);
|
|
11802
11706
|
}
|
|
11803
11707
|
return results;
|
|
11804
11708
|
}
|
|
11805
11709
|
function extractFragmentInfo(stat) {
|
|
11806
|
-
for (const kind of
|
|
11710
|
+
for (const kind of SINGLE_BLOCK_FRAGMENT_KINDS) {
|
|
11807
11711
|
const frag = stat[kind]?.();
|
|
11808
11712
|
if (frag) {
|
|
11809
11713
|
const condition = frag.parExpr?.()?.condition?.();
|
|
@@ -11820,16 +11724,25 @@ function extractFragmentInfo(stat) {
|
|
|
11820
11724
|
const sections = [];
|
|
11821
11725
|
const ifBlock = alt.ifBlock?.();
|
|
11822
11726
|
if (ifBlock) {
|
|
11823
|
-
sections.push({
|
|
11727
|
+
sections.push({
|
|
11728
|
+
label: "Alt",
|
|
11729
|
+
blockNode: ifBlock.braceBlock?.()?.block?.()
|
|
11730
|
+
});
|
|
11824
11731
|
}
|
|
11825
11732
|
for (const elseIf of alt.elseIfBlock?.() || []) {
|
|
11826
11733
|
const condition = elseIf.parExpr?.()?.condition?.();
|
|
11827
11734
|
const label = condition?.getFormattedText?.() || "";
|
|
11828
|
-
sections.push({
|
|
11735
|
+
sections.push({
|
|
11736
|
+
label: `[ ${label} ]`,
|
|
11737
|
+
blockNode: elseIf.braceBlock?.()?.block?.()
|
|
11738
|
+
});
|
|
11829
11739
|
}
|
|
11830
11740
|
const elseBlock = alt.elseBlock?.();
|
|
11831
11741
|
if (elseBlock) {
|
|
11832
|
-
sections.push({
|
|
11742
|
+
sections.push({
|
|
11743
|
+
label: "[else]",
|
|
11744
|
+
blockNode: elseBlock.braceBlock?.()?.block?.()
|
|
11745
|
+
});
|
|
11833
11746
|
}
|
|
11834
11747
|
const ifCondition = alt.ifBlock?.()?.parExpr?.()?.condition?.();
|
|
11835
11748
|
const firstLabel = ifCondition?.getFormattedText?.() || "";
|
|
@@ -11840,15 +11753,24 @@ function extractFragmentInfo(stat) {
|
|
|
11840
11753
|
const sections = [];
|
|
11841
11754
|
const tryBlock = tcf.tryBlock?.();
|
|
11842
11755
|
if (tryBlock) {
|
|
11843
|
-
sections.push({
|
|
11756
|
+
sections.push({
|
|
11757
|
+
label: "Try",
|
|
11758
|
+
blockNode: tryBlock.braceBlock?.()?.block?.()
|
|
11759
|
+
});
|
|
11844
11760
|
}
|
|
11845
11761
|
for (const catchBlock of tcf.catchBlock?.() || []) {
|
|
11846
11762
|
const exception = catchBlock.invocation?.()?.parameters?.()?.getFormattedText?.() || "";
|
|
11847
|
-
sections.push({
|
|
11763
|
+
sections.push({
|
|
11764
|
+
label: `catch ${exception}`,
|
|
11765
|
+
blockNode: catchBlock.braceBlock?.()?.block?.()
|
|
11766
|
+
});
|
|
11848
11767
|
}
|
|
11849
11768
|
const finallyBlock = tcf.finallyBlock?.();
|
|
11850
11769
|
if (finallyBlock) {
|
|
11851
|
-
sections.push({
|
|
11770
|
+
sections.push({
|
|
11771
|
+
label: "finally",
|
|
11772
|
+
blockNode: finallyBlock.braceBlock?.()?.block?.()
|
|
11773
|
+
});
|
|
11852
11774
|
}
|
|
11853
11775
|
return { fragmentKind: "tcf", label: "", sections };
|
|
11854
11776
|
}
|
|
@@ -11860,14 +11782,27 @@ function extractFragmentInfo(stat) {
|
|
|
11860
11782
|
return null;
|
|
11861
11783
|
}
|
|
11862
11784
|
function blockLength(block) {
|
|
11863
|
-
return (block?.stat?.() || []).filter(
|
|
11785
|
+
return (block?.stat?.() || []).filter(
|
|
11786
|
+
(stat) => !!createStatementKey(stat)
|
|
11787
|
+
).length;
|
|
11864
11788
|
}
|
|
11865
11789
|
function walkFragmentBlocks(stat, origin, results, activeOccurrences, parentNumber, depth) {
|
|
11866
|
-
for (const kind of
|
|
11790
|
+
for (const kind of SINGLE_BLOCK_FRAGMENT_KINDS) {
|
|
11867
11791
|
const frag = stat[kind]?.();
|
|
11868
11792
|
if (frag) {
|
|
11869
11793
|
const block = frag.braceBlock?.()?.block?.();
|
|
11870
|
-
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
|
+
);
|
|
11871
11806
|
return;
|
|
11872
11807
|
}
|
|
11873
11808
|
}
|
|
@@ -11878,14 +11813,32 @@ function walkFragmentBlocks(stat, origin, results, activeOccurrences, parentNumb
|
|
|
11878
11813
|
if (ifBlock) {
|
|
11879
11814
|
const block = ifBlock.braceBlock?.()?.block?.();
|
|
11880
11815
|
if (block) {
|
|
11881
|
-
results.push(
|
|
11816
|
+
results.push(
|
|
11817
|
+
...walkBlock(
|
|
11818
|
+
block,
|
|
11819
|
+
origin,
|
|
11820
|
+
activeOccurrences,
|
|
11821
|
+
parentNumber,
|
|
11822
|
+
depth + 1,
|
|
11823
|
+
null,
|
|
11824
|
+
sectionOffset
|
|
11825
|
+
)
|
|
11826
|
+
);
|
|
11882
11827
|
sectionOffset += blockLength(block);
|
|
11883
11828
|
}
|
|
11884
11829
|
}
|
|
11885
11830
|
for (const elseIf of alt.elseIfBlock?.() || []) {
|
|
11886
11831
|
const block = elseIf.braceBlock?.()?.block?.();
|
|
11887
11832
|
if (block) {
|
|
11888
|
-
const sectionStmts = walkBlock(
|
|
11833
|
+
const sectionStmts = walkBlock(
|
|
11834
|
+
block,
|
|
11835
|
+
origin,
|
|
11836
|
+
activeOccurrences,
|
|
11837
|
+
parentNumber,
|
|
11838
|
+
depth + 1,
|
|
11839
|
+
null,
|
|
11840
|
+
sectionOffset
|
|
11841
|
+
);
|
|
11889
11842
|
if (sectionStmts.length > 0) sectionStmts[0].sectionReset = true;
|
|
11890
11843
|
results.push(...sectionStmts);
|
|
11891
11844
|
sectionOffset += blockLength(block);
|
|
@@ -11895,7 +11848,15 @@ function walkFragmentBlocks(stat, origin, results, activeOccurrences, parentNumb
|
|
|
11895
11848
|
if (elseBlock) {
|
|
11896
11849
|
const block = elseBlock.braceBlock?.()?.block?.();
|
|
11897
11850
|
if (block) {
|
|
11898
|
-
const sectionStmts = walkBlock(
|
|
11851
|
+
const sectionStmts = walkBlock(
|
|
11852
|
+
block,
|
|
11853
|
+
origin,
|
|
11854
|
+
activeOccurrences,
|
|
11855
|
+
parentNumber,
|
|
11856
|
+
depth + 1,
|
|
11857
|
+
null,
|
|
11858
|
+
sectionOffset
|
|
11859
|
+
);
|
|
11899
11860
|
if (sectionStmts.length > 0) sectionStmts[0].sectionReset = true;
|
|
11900
11861
|
results.push(...sectionStmts);
|
|
11901
11862
|
}
|
|
@@ -11909,14 +11870,32 @@ function walkFragmentBlocks(stat, origin, results, activeOccurrences, parentNumb
|
|
|
11909
11870
|
if (tryBlock) {
|
|
11910
11871
|
const block = tryBlock.braceBlock?.()?.block?.();
|
|
11911
11872
|
if (block) {
|
|
11912
|
-
results.push(
|
|
11873
|
+
results.push(
|
|
11874
|
+
...walkBlock(
|
|
11875
|
+
block,
|
|
11876
|
+
origin,
|
|
11877
|
+
activeOccurrences,
|
|
11878
|
+
parentNumber,
|
|
11879
|
+
depth + 1,
|
|
11880
|
+
null,
|
|
11881
|
+
sectionOffset
|
|
11882
|
+
)
|
|
11883
|
+
);
|
|
11913
11884
|
sectionOffset += blockLength(block);
|
|
11914
11885
|
}
|
|
11915
11886
|
}
|
|
11916
11887
|
for (const catchBlock of tcf.catchBlock?.() || []) {
|
|
11917
11888
|
const block = catchBlock.braceBlock?.()?.block?.();
|
|
11918
11889
|
if (block) {
|
|
11919
|
-
const sectionStmts = walkBlock(
|
|
11890
|
+
const sectionStmts = walkBlock(
|
|
11891
|
+
block,
|
|
11892
|
+
origin,
|
|
11893
|
+
activeOccurrences,
|
|
11894
|
+
parentNumber,
|
|
11895
|
+
depth + 1,
|
|
11896
|
+
null,
|
|
11897
|
+
sectionOffset
|
|
11898
|
+
);
|
|
11920
11899
|
if (sectionStmts.length > 0) sectionStmts[0].sectionReset = true;
|
|
11921
11900
|
results.push(...sectionStmts);
|
|
11922
11901
|
sectionOffset += blockLength(block);
|
|
@@ -11926,7 +11905,15 @@ function walkFragmentBlocks(stat, origin, results, activeOccurrences, parentNumb
|
|
|
11926
11905
|
if (finallyBlock) {
|
|
11927
11906
|
const block = finallyBlock.braceBlock?.()?.block?.();
|
|
11928
11907
|
if (block) {
|
|
11929
|
-
const sectionStmts = walkBlock(
|
|
11908
|
+
const sectionStmts = walkBlock(
|
|
11909
|
+
block,
|
|
11910
|
+
origin,
|
|
11911
|
+
activeOccurrences,
|
|
11912
|
+
parentNumber,
|
|
11913
|
+
depth + 1,
|
|
11914
|
+
null,
|
|
11915
|
+
sectionOffset
|
|
11916
|
+
);
|
|
11930
11917
|
if (sectionStmts.length > 0) sectionStmts[0].sectionReset = true;
|
|
11931
11918
|
results.push(...sectionStmts);
|
|
11932
11919
|
}
|
|
@@ -11958,10 +11945,6 @@ function computeReturnDebt(statements, verticalCoordinates, returnHeight) {
|
|
|
11958
11945
|
if (ownerKey && occInnerDebt > 0) {
|
|
11959
11946
|
result.set(`inner:${ownerKey}`, occInnerDebt);
|
|
11960
11947
|
}
|
|
11961
|
-
const hasMixed = hasNonReturnChild[maxDepth] || false;
|
|
11962
|
-
if (ownerKey && hasMixed) {
|
|
11963
|
-
result.set(`mixed:${ownerKey}`, 1);
|
|
11964
|
-
}
|
|
11965
11948
|
const hasAssign = blockHasAssignment[maxDepth] || false;
|
|
11966
11949
|
debtByDepth.pop();
|
|
11967
11950
|
directDebtByDepth.pop();
|
|
@@ -12045,10 +12028,6 @@ function computeReturnDebt(statements, verticalCoordinates, returnHeight) {
|
|
|
12045
12028
|
if (ownerKey && occInnerDebtEnd > 0) {
|
|
12046
12029
|
result.set(`inner:${ownerKey}`, occInnerDebtEnd);
|
|
12047
12030
|
}
|
|
12048
|
-
const hasMixedEnd = hasNonReturnChild[maxDepth] || false;
|
|
12049
|
-
if (ownerKey && hasMixedEnd) {
|
|
12050
|
-
result.set(`mixed:${ownerKey}`, 1);
|
|
12051
|
-
}
|
|
12052
12031
|
const hasAssignEnd = blockHasAssignment[maxDepth] || false;
|
|
12053
12032
|
debtByDepth.pop();
|
|
12054
12033
|
directDebtByDepth.pop();
|
|
@@ -12064,7 +12043,6 @@ function computeReturnDebt(statements, verticalCoordinates, returnHeight) {
|
|
|
12064
12043
|
}
|
|
12065
12044
|
}
|
|
12066
12045
|
}
|
|
12067
|
-
result.set("__totalDebt__", debtByDepth[0] || 0);
|
|
12068
12046
|
return result;
|
|
12069
12047
|
}
|
|
12070
12048
|
|
|
@@ -12092,7 +12070,11 @@ function buildMessages(rootContext, coordinates, verticalCoordinates, participan
|
|
|
12092
12070
|
}
|
|
12093
12071
|
}
|
|
12094
12072
|
const RETURN_VISUAL_HEIGHT = 16;
|
|
12095
|
-
const adjustMap = computeReturnDebt(
|
|
12073
|
+
const adjustMap = computeReturnDebt(
|
|
12074
|
+
statements,
|
|
12075
|
+
verticalCoordinates,
|
|
12076
|
+
RETURN_VISUAL_HEIGHT
|
|
12077
|
+
);
|
|
12096
12078
|
for (const info of statements) {
|
|
12097
12079
|
const coord = verticalCoordinates.getStatementCoordinate(info.key);
|
|
12098
12080
|
if (!coord) continue;
|
|
@@ -12108,7 +12090,7 @@ function buildMessages(rootContext, coordinates, verticalCoordinates, participan
|
|
|
12108
12090
|
const tX = coordinates.getPosition(info.to);
|
|
12109
12091
|
if (fX > tX) commentParticipant = info.to;
|
|
12110
12092
|
}
|
|
12111
|
-
const commentX = commentParticipant ?
|
|
12093
|
+
const commentX = commentParticipant ? coordinates.getPosition(commentParticipant) : 10;
|
|
12112
12094
|
const COMMENT_FONT_ASCENT = 15;
|
|
12113
12095
|
const commentXOffset = info.senderOccurrenceDepth >= 1 ? OCCURRENCE_BAR_SIDE_WIDTH + 1 : 1;
|
|
12114
12096
|
const codeSpanPadding = commentObj.text.trimStart().startsWith("`") ? 2 : 0;
|
|
@@ -12121,30 +12103,31 @@ function buildMessages(rootContext, coordinates, verticalCoordinates, participan
|
|
|
12121
12103
|
}
|
|
12122
12104
|
const messageStyle = commentObj ? cssToSvgStyle(commentObj.messageStyle) : void 0;
|
|
12123
12105
|
if (info.kind === "sync" || info.kind === "async") {
|
|
12124
|
-
let fromX =
|
|
12125
|
-
const toX =
|
|
12126
|
-
const
|
|
12127
|
-
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;
|
|
12128
12111
|
const messageY = coord.top + adjust + msgCommentHeight + messageHeight - 0.5;
|
|
12129
12112
|
if (info.senderOccurrenceDepth >= 1 && !info.isSelf) {
|
|
12130
|
-
const
|
|
12131
|
-
const occOffset = depth * OCCURRENCE_BAR_SIDE_WIDTH;
|
|
12113
|
+
const senderAnchor = new Anchor2(fromX, info.senderOccurrenceDepth);
|
|
12132
12114
|
const isLTR = fromX < toX;
|
|
12133
|
-
fromX = isLTR ?
|
|
12115
|
+
fromX = isLTR ? senderAnchor.rightEdgeOfRightWall() : senderAnchor.leftEdgeOfRightWall();
|
|
12134
12116
|
}
|
|
12135
12117
|
const targetDepth = info.targetOccurrenceDepth || (info.targetHasOccurrence ? 1 : 0);
|
|
12136
12118
|
const nestingOffset = targetDepth * OCCURRENCE_BAR_SIDE_WIDTH;
|
|
12137
12119
|
if (info.isSelf) {
|
|
12138
|
-
const isAsync = info.kind === "async";
|
|
12139
12120
|
const selfYOffset = 0;
|
|
12140
12121
|
const selfWidth = isAsync ? 28 : OCCURRENCE_WIDTH;
|
|
12141
|
-
const
|
|
12142
|
-
|
|
12122
|
+
const selfX = new Anchor2(
|
|
12123
|
+
fromX,
|
|
12124
|
+
info.senderOccurrenceDepth
|
|
12125
|
+
).rightEdgeOfRightWall();
|
|
12143
12126
|
selfCalls.push({
|
|
12144
12127
|
x: selfX,
|
|
12145
12128
|
y: coord.top + selfYOffset + msgCommentHeight,
|
|
12146
12129
|
width: selfWidth,
|
|
12147
|
-
height:
|
|
12130
|
+
height: messageHeight,
|
|
12148
12131
|
label: info.label,
|
|
12149
12132
|
arrowStyle: isAsync ? "open" : "solid",
|
|
12150
12133
|
number: info.number,
|
|
@@ -12216,16 +12199,15 @@ function buildMessages(rootContext, coordinates, verticalCoordinates, participan
|
|
|
12216
12199
|
continue;
|
|
12217
12200
|
}
|
|
12218
12201
|
if (info.kind === "creation") {
|
|
12219
|
-
|
|
12220
|
-
|
|
12221
|
-
const toX = snapX$1(coordinates.getPosition(info.to));
|
|
12202
|
+
let fromX = coordinates.getPosition(info.from);
|
|
12203
|
+
const toX = coordinates.getPosition(info.to);
|
|
12222
12204
|
if (info.senderOccurrenceDepth >= 1) {
|
|
12223
12205
|
const occOffset = OCCURRENCE_BAR_SIDE_WIDTH + (info.senderOccurrenceDepth - 1) * OCCURRENCE_BAR_SIDE_WIDTH;
|
|
12224
12206
|
const isLTR = fromX < toX;
|
|
12225
12207
|
fromX = isLTR ? fromX + occOffset : fromX - occOffset;
|
|
12226
12208
|
}
|
|
12227
12209
|
const targetParticipant = participants.find((p) => p.name === info.to);
|
|
12228
|
-
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;
|
|
12229
12211
|
if (targetParticipant) {
|
|
12230
12212
|
creations.push({
|
|
12231
12213
|
participant: targetParticipant,
|
|
@@ -12244,7 +12226,7 @@ function buildMessages(rootContext, coordinates, verticalCoordinates, participan
|
|
|
12244
12226
|
});
|
|
12245
12227
|
}
|
|
12246
12228
|
const occX = toX - OCCURRENCE_BAR_SIDE_WIDTH;
|
|
12247
|
-
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;
|
|
12248
12230
|
const occHeight = Math.max(
|
|
12249
12231
|
coord.top + coord.height - occY,
|
|
12250
12232
|
OCCURRENCE_EMPTY_HEIGHT
|
|
@@ -12261,7 +12243,7 @@ function buildMessages(rootContext, coordinates, verticalCoordinates, participan
|
|
|
12261
12243
|
const creationAssign = creationCtx?.Assignment?.();
|
|
12262
12244
|
if (creationAssign?.assignee) {
|
|
12263
12245
|
const occBottom = occY + occHeight - 2;
|
|
12264
|
-
const rawFromX =
|
|
12246
|
+
const rawFromX = coordinates.getPosition(info.from);
|
|
12265
12247
|
const isLTR = rawFromX < toX;
|
|
12266
12248
|
const occHalf = OCCURRENCE_BAR_SIDE_WIDTH;
|
|
12267
12249
|
const senderNest = Math.max(info.senderOccurrenceDepth - 1, 0) * OCCURRENCE_BAR_SIDE_WIDTH;
|
|
@@ -12283,7 +12265,7 @@ function buildMessages(rootContext, coordinates, verticalCoordinates, participan
|
|
|
12283
12265
|
}
|
|
12284
12266
|
if (info.kind === "fragment" && info.fragmentKind) {
|
|
12285
12267
|
const adjustedCoord = { top: coord.top + adjust, height: coord.height };
|
|
12286
|
-
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;
|
|
12287
12269
|
const fragmentResult = buildFragmentGeometry(
|
|
12288
12270
|
info,
|
|
12289
12271
|
adjustedCoord,
|
|
@@ -12305,26 +12287,14 @@ function buildMessages(rootContext, coordinates, verticalCoordinates, participan
|
|
|
12305
12287
|
continue;
|
|
12306
12288
|
}
|
|
12307
12289
|
if (info.kind === "return") {
|
|
12308
|
-
const rawFromX =
|
|
12309
|
-
const rawToX =
|
|
12290
|
+
const rawFromX = coordinates.getPosition(info.from);
|
|
12291
|
+
const rawToX = coordinates.getPosition(info.to);
|
|
12310
12292
|
const isReverse = rawToX < rawFromX;
|
|
12311
|
-
const
|
|
12312
|
-
|
|
12313
|
-
|
|
12314
|
-
|
|
12315
|
-
|
|
12316
|
-
fromX = rawFromX + OCCURRENCE_BAR_SIDE_WIDTH * fromLayers + 1;
|
|
12317
|
-
}
|
|
12318
|
-
const toLayers = info.targetOccurrenceDepth || 0;
|
|
12319
|
-
let toX;
|
|
12320
|
-
if (isReverse) {
|
|
12321
|
-
toX = rawToX + OCCURRENCE_BAR_SIDE_WIDTH * toLayers;
|
|
12322
|
-
} else {
|
|
12323
|
-
toX = toLayers === 0 ? rawToX : (toLayers <= 1 ? rawToX : rawToX + OCCURRENCE_BAR_SIDE_WIDTH * (toLayers - 1)) - OCCURRENCE_BAR_SIDE_WIDTH;
|
|
12324
|
-
}
|
|
12325
|
-
if (isReverse) {
|
|
12326
|
-
toX += LIFELINE_WIDTH;
|
|
12327
|
-
}
|
|
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();
|
|
12328
12298
|
const returnOffset = coord.height === 0 ? 16.5 : 15.5;
|
|
12329
12299
|
const returnY = coord.top + adjust + returnOffset;
|
|
12330
12300
|
returns.push({
|
|
@@ -12346,7 +12316,9 @@ function buildMessages(rootContext, coordinates, verticalCoordinates, participan
|
|
|
12346
12316
|
y: coord.top + adjust + coord.height / 2,
|
|
12347
12317
|
width: diagramWidth,
|
|
12348
12318
|
label: info.label,
|
|
12349
|
-
labelWidth: measureSvgFragmentLabelWidth(
|
|
12319
|
+
labelWidth: measureSvgFragmentLabelWidth(
|
|
12320
|
+
resolveEmojiInText(cleanLabel)
|
|
12321
|
+
)
|
|
12350
12322
|
});
|
|
12351
12323
|
continue;
|
|
12352
12324
|
}
|
|
@@ -12369,11 +12341,23 @@ function buildMessages(rootContext, coordinates, verticalCoordinates, participan
|
|
|
12369
12341
|
}
|
|
12370
12342
|
}
|
|
12371
12343
|
if (depth > 0) {
|
|
12372
|
-
occurrences[i] = {
|
|
12344
|
+
occurrences[i] = {
|
|
12345
|
+
...inner,
|
|
12346
|
+
x: inner.x + depth * OCCURRENCE_BAR_SIDE_WIDTH
|
|
12347
|
+
};
|
|
12373
12348
|
}
|
|
12374
12349
|
}
|
|
12375
|
-
|
|
12376
|
-
|
|
12350
|
+
return {
|
|
12351
|
+
messages,
|
|
12352
|
+
selfCalls,
|
|
12353
|
+
occurrences,
|
|
12354
|
+
creations,
|
|
12355
|
+
fragments,
|
|
12356
|
+
returns,
|
|
12357
|
+
dividers,
|
|
12358
|
+
comments,
|
|
12359
|
+
maxReturnBottom
|
|
12360
|
+
};
|
|
12377
12361
|
}
|
|
12378
12362
|
|
|
12379
12363
|
function buildGeometry(input) {
|
|
@@ -12417,17 +12401,7 @@ function buildGeometry(input) {
|
|
|
12417
12401
|
participants,
|
|
12418
12402
|
lifelineBottom
|
|
12419
12403
|
);
|
|
12420
|
-
|
|
12421
|
-
const orderedNames = coordinates.orderedParticipantNames();
|
|
12422
|
-
const leftParticipant = orderedNames.find((p) => localParticipants.includes(p)) || "";
|
|
12423
|
-
const rightParticipant = orderedNames.slice().reverse().find((p) => localParticipants.includes(p)) || "";
|
|
12424
|
-
const participantWidth = coordinates.distance(leftParticipant, rightParticipant) + coordinates.half(leftParticipant) + coordinates.half(rightParticipant);
|
|
12425
|
-
const selfMessages = AllMessages(rootContext).filter((m) => m.from === m.to);
|
|
12426
|
-
const extraWidths = selfMessages.map(
|
|
12427
|
-
(m) => coordinates.getMessageWidth(m) - coordinates.distance(m.from || _STARTER_, rightParticipant) - coordinates.half(rightParticipant)
|
|
12428
|
-
);
|
|
12429
|
-
const extraWidthDueToSelfMessage = Math.max(0, ...extraWidths);
|
|
12430
|
-
let diagramWidth = Math.max(participantWidth, FRAGMENT_MIN_WIDTH) + extraWidthDueToSelfMessage;
|
|
12404
|
+
let diagramWidth = TotalWidth(rootContext, coordinates) - frameBorder.left - frameBorder.right;
|
|
12431
12405
|
if (measureText) {
|
|
12432
12406
|
const LABEL_PAD = 10;
|
|
12433
12407
|
for (const msg of messages) {
|
|
@@ -12765,7 +12739,7 @@ function renderOccurrence(o) {
|
|
|
12765
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)}"/>`;
|
|
12766
12740
|
}
|
|
12767
12741
|
|
|
12768
|
-
const HEADER_HEIGHT =
|
|
12742
|
+
const HEADER_HEIGHT = DEFAULT_LAYOUT_METRICS.fragmentHeaderHeight;
|
|
12769
12743
|
const BRACKET_WIDTH = 3.89;
|
|
12770
12744
|
const TEXT_PAD_X = 4;
|
|
12771
12745
|
const STROKE_WIDTH = 1;
|
|
@@ -13126,47 +13100,153 @@ function renderGroup(g) {
|
|
|
13126
13100
|
</g>`;
|
|
13127
13101
|
}
|
|
13128
13102
|
|
|
13129
|
-
const
|
|
13130
|
-
const
|
|
13131
|
-
|
|
13132
|
-
|
|
13133
|
-
|
|
13134
|
-
|
|
13135
|
-
|
|
13136
|
-
|
|
13137
|
-
|
|
13138
|
-
|
|
13139
|
-
|
|
13140
|
-
|
|
13141
|
-
|
|
13142
|
-
|
|
13143
|
-
|
|
13144
|
-
|
|
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; }
|
|
13145
13214
|
.arrow-open { fill: none; }
|
|
13146
|
-
.occurrence { fill:
|
|
13147
|
-
.fragment-border { fill: none; stroke:
|
|
13148
|
-
.fragment-header { fill:
|
|
13149
|
-
.fragment-label { font-family:
|
|
13150
|
-
.fragment-condition { font-family:
|
|
13151
|
-
.fragment-separator { stroke:
|
|
13152
|
-
.fragment-section-label { font-family:
|
|
13153
|
-
.return-line { stroke:
|
|
13154
|
-
.return-arrow { stroke:
|
|
13155
|
-
.return-label { font-family:
|
|
13156
|
-
.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}; }
|
|
13157
13226
|
.divider-line { stroke: #aaaa33; stroke-width: 1; }
|
|
13158
13227
|
.divider-bg { fill: #fff5ad; stroke: #aaaa33; stroke-width: 1; }
|
|
13159
|
-
.divider-label { font-family:
|
|
13160
|
-
.comment-text { font-family:
|
|
13161
|
-
.seq-number { font-family:
|
|
13162
|
-
.group-outline { fill: none; stroke:
|
|
13163
|
-
.group-title-bg { fill:
|
|
13164
|
-
.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}; }
|
|
13165
13234
|
`;
|
|
13235
|
+
}
|
|
13236
|
+
|
|
13237
|
+
const FRAME_HEADER_HEIGHT = 28;
|
|
13238
|
+
const FRAME_BORDER_RADIUS = 4;
|
|
13166
13239
|
function renderToSvg(code, options) {
|
|
13167
13240
|
const rootContext = RootContext(code);
|
|
13168
13241
|
if (!rootContext) {
|
|
13169
|
-
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
|
+
};
|
|
13170
13250
|
}
|
|
13171
13251
|
const coordinates = new Coordinates(rootContext, WidthProviderOnCanvas);
|
|
13172
13252
|
const verticalCoordinates = new VerticalCoordinates(rootContext);
|
|
@@ -13180,7 +13260,7 @@ function renderToSvg(code, options) {
|
|
|
13180
13260
|
title,
|
|
13181
13261
|
measureText: WidthProviderOnCanvas
|
|
13182
13262
|
});
|
|
13183
|
-
return { ...composeSvg(geometry), geometry };
|
|
13263
|
+
return { ...composeSvg(geometry, options), geometry };
|
|
13184
13264
|
}
|
|
13185
13265
|
function composeSvg(g, options) {
|
|
13186
13266
|
const padding = 10;
|
|
@@ -13239,10 +13319,10 @@ function composeSvg(g, options) {
|
|
|
13239
13319
|
const headerLineY = headerH + contentPaddingTop;
|
|
13240
13320
|
const headerLineDrawY = headerLineY - 0.5;
|
|
13241
13321
|
const headerLineSvg = `<line class="frame-header-line" x1="1" y1="${headerLineDrawY}" x2="${viewWidth - 1}" y2="${headerLineDrawY}"/>`;
|
|
13242
|
-
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>` : "";
|
|
13243
13323
|
const viewBox = `0 0 ${viewWidth} ${viewHeight}`;
|
|
13244
13324
|
const defs = `<defs>
|
|
13245
|
-
<style>${
|
|
13325
|
+
<style>${buildThemeStyles(resolvePalette(options?.theme))}</style>
|
|
13246
13326
|
</defs>`;
|
|
13247
13327
|
const frame = `${frameSvg}
|
|
13248
13328
|
${headerLineSvg}
|
|
@@ -13258,9 +13338,6 @@ ${innerSvg}
|
|
|
13258
13338
|
</svg>`;
|
|
13259
13339
|
return { svg, innerSvg, width: viewWidth, height: viewHeight, viewBox };
|
|
13260
13340
|
}
|
|
13261
|
-
function escXml(s) {
|
|
13262
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
13263
|
-
}
|
|
13264
13341
|
|
|
13265
13342
|
function readVersion() {
|
|
13266
13343
|
const pkgPath = resolve(import.meta.dir, "../../package.json");
|
|
@@ -13282,7 +13359,8 @@ Rendering:
|
|
|
13282
13359
|
-o, --output <file> Output file (use "-" for stdout; default: <input>.svg)
|
|
13283
13360
|
-e, --outputFormat <format> Output format: "svg" (default) or "png"
|
|
13284
13361
|
-s, --scale <factor> Pixel scale factor for PNG (default: 2; ignored for SVG)
|
|
13285
|
-
-t, --theme <name> Theme
|
|
13362
|
+
-t, --theme <name> Theme: default, mermaid, clean-light, clean-dark,
|
|
13363
|
+
neon (prefix "theme-"; unknown names use default)
|
|
13286
13364
|
-c, --configFile <file> JSON config file with { theme, scale, outputFormat }
|
|
13287
13365
|
--md Markdown mode: render zenuml code blocks and produce output Markdown
|
|
13288
13366
|
|
|
@@ -13643,7 +13721,6 @@ async function checkOne(input) {
|
|
|
13643
13721
|
errors: [{ line: 0, column: 0, msg: err.message }]
|
|
13644
13722
|
};
|
|
13645
13723
|
}
|
|
13646
|
-
Parser.Errors.length = 0;
|
|
13647
13724
|
Parser.ErrorDetails.length = 0;
|
|
13648
13725
|
Parser.RootContext(code);
|
|
13649
13726
|
const errors = Parser.ErrorDetails.map((e) => ({
|
|
@@ -13657,6 +13734,69 @@ async function checkOne(input) {
|
|
|
13657
13734
|
errors
|
|
13658
13735
|
};
|
|
13659
13736
|
}
|
|
13737
|
+
async function renderMarkdownFile(inputArg, args, config) {
|
|
13738
|
+
const mdContent = await readCode(inputArg);
|
|
13739
|
+
const effectiveFormat = args.outputFormat ?? config.configOutputFormat ?? "svg";
|
|
13740
|
+
if (effectiveFormat !== "svg" && effectiveFormat !== "png") {
|
|
13741
|
+
throw new Error(
|
|
13742
|
+
`Unsupported output format: "${effectiveFormat}". Use "svg" or "png".`
|
|
13743
|
+
);
|
|
13744
|
+
}
|
|
13745
|
+
const inputPath = inputArg === "-" ? void 0 : resolve(inputArg);
|
|
13746
|
+
const outputPath = args.output === "-" ? "-" : args.output ? resolve(args.output) : inputPath ? join(
|
|
13747
|
+
dirname(inputPath),
|
|
13748
|
+
`${basename(inputArg, extname(inputArg))}-rendered.md`
|
|
13749
|
+
) : "-";
|
|
13750
|
+
const imageDir = outputPath !== "-" ? dirname(outputPath) : inputPath ? dirname(inputPath) : process.cwd();
|
|
13751
|
+
const imageStem = inputPath ? basename(inputArg, extname(inputArg)) : outputPath !== "-" ? basename(outputPath, extname(outputPath)) : "diagram";
|
|
13752
|
+
const renderOptions = {};
|
|
13753
|
+
const effectiveTheme = args.theme ?? config.configTheme;
|
|
13754
|
+
if (effectiveTheme) {
|
|
13755
|
+
renderOptions.theme = effectiveTheme;
|
|
13756
|
+
}
|
|
13757
|
+
const blocks = extractZenumlBlocks(mdContent);
|
|
13758
|
+
const imageFiles = /* @__PURE__ */ new Map();
|
|
13759
|
+
for (const block of blocks) {
|
|
13760
|
+
if (block.empty) continue;
|
|
13761
|
+
const imageFilename = `${imageStem}-zenuml-${block.index}.${effectiveFormat}`;
|
|
13762
|
+
const imageFilePath = join(imageDir, imageFilename);
|
|
13763
|
+
let result;
|
|
13764
|
+
try {
|
|
13765
|
+
result = renderToSvg(block.code, renderOptions);
|
|
13766
|
+
} catch (err) {
|
|
13767
|
+
throw new Error(
|
|
13768
|
+
`Failed to render zenuml block ${block.index}: ${err.message}`
|
|
13769
|
+
);
|
|
13770
|
+
}
|
|
13771
|
+
mkdirSync(imageDir, { recursive: true });
|
|
13772
|
+
const image = effectiveFormat === "png" ? await rasterizeToPng(
|
|
13773
|
+
result.svg,
|
|
13774
|
+
result.width,
|
|
13775
|
+
result.height,
|
|
13776
|
+
args.scale ?? config.configScale ?? 2
|
|
13777
|
+
) : result.svg;
|
|
13778
|
+
writeFileSync(imageFilePath, image);
|
|
13779
|
+
imageFiles.set(block.index, imageFilename);
|
|
13780
|
+
if (!args.quiet && !args.watch) {
|
|
13781
|
+
process.stderr.write(`Wrote ${imageFilePath}
|
|
13782
|
+
`);
|
|
13783
|
+
}
|
|
13784
|
+
}
|
|
13785
|
+
const outputMd = [...blocks].reverse().reduce((markdown, block) => {
|
|
13786
|
+
const replacement = block.empty ? "" : `})`;
|
|
13787
|
+
return markdown.replace(block.raw, replacement);
|
|
13788
|
+
}, mdContent);
|
|
13789
|
+
if (outputPath === "-") {
|
|
13790
|
+
process.stdout.write(outputMd);
|
|
13791
|
+
return;
|
|
13792
|
+
}
|
|
13793
|
+
mkdirSync(dirname(outputPath), { recursive: true });
|
|
13794
|
+
writeFileSync(outputPath, outputMd, "utf-8");
|
|
13795
|
+
if (!args.quiet && !args.watch) {
|
|
13796
|
+
process.stderr.write(`Wrote ${outputPath}
|
|
13797
|
+
`);
|
|
13798
|
+
}
|
|
13799
|
+
}
|
|
13660
13800
|
async function main() {
|
|
13661
13801
|
if (!globalThis.OffscreenCanvas && typeof document === "undefined") {
|
|
13662
13802
|
try {
|
|
@@ -13746,7 +13886,6 @@ async function main() {
|
|
|
13746
13886
|
`);
|
|
13747
13887
|
process.exit(1);
|
|
13748
13888
|
}
|
|
13749
|
-
Parser.Errors.length = 0;
|
|
13750
13889
|
Parser.ErrorDetails.length = 0;
|
|
13751
13890
|
const tree = Parser.RootContext(code);
|
|
13752
13891
|
if (Parser.ErrorDetails.length > 0) {
|
|
@@ -13760,146 +13899,6 @@ async function main() {
|
|
|
13760
13899
|
process.stdout.write(JSON.stringify(ast, null, 2) + "\n");
|
|
13761
13900
|
process.exit(0);
|
|
13762
13901
|
}
|
|
13763
|
-
const isMdMode = args.md || expandedInputs.some((f) => f !== "-" && /\.(?:md|markdown)$/i.test(f));
|
|
13764
|
-
if (isMdMode) {
|
|
13765
|
-
if (expandedInputs.length > 1) {
|
|
13766
|
-
process.stderr.write(
|
|
13767
|
-
"Error: --md mode supports only a single input file.\n"
|
|
13768
|
-
);
|
|
13769
|
-
process.exit(1);
|
|
13770
|
-
}
|
|
13771
|
-
const inputArg = expandedInputs[0];
|
|
13772
|
-
if (args.md && inputArg !== "-") {
|
|
13773
|
-
const ext = extname(inputArg).toLowerCase();
|
|
13774
|
-
if (ext !== ".md" && ext !== ".markdown") {
|
|
13775
|
-
process.stderr.write(
|
|
13776
|
-
`Error: --md flag requires a .md or .markdown input file, got: ${inputArg}
|
|
13777
|
-
`
|
|
13778
|
-
);
|
|
13779
|
-
process.exit(1);
|
|
13780
|
-
}
|
|
13781
|
-
}
|
|
13782
|
-
let mdContent;
|
|
13783
|
-
try {
|
|
13784
|
-
mdContent = await readCode(inputArg);
|
|
13785
|
-
} catch (err) {
|
|
13786
|
-
process.stderr.write(`Error: ${err.message}
|
|
13787
|
-
`);
|
|
13788
|
-
process.exit(1);
|
|
13789
|
-
}
|
|
13790
|
-
const effectiveFormat = args.outputFormat ?? "svg";
|
|
13791
|
-
if (effectiveFormat !== "svg" && effectiveFormat !== "png") {
|
|
13792
|
-
process.stderr.write(
|
|
13793
|
-
`Error: Unsupported output format: "${effectiveFormat}". Use "svg" or "png".
|
|
13794
|
-
`
|
|
13795
|
-
);
|
|
13796
|
-
process.exit(1);
|
|
13797
|
-
}
|
|
13798
|
-
let imageDir;
|
|
13799
|
-
let mdOutputPath;
|
|
13800
|
-
if (args.output && args.output !== "-") {
|
|
13801
|
-
const resolvedOutput = resolve(args.output);
|
|
13802
|
-
imageDir = dirname(resolvedOutput);
|
|
13803
|
-
mdOutputPath = resolvedOutput;
|
|
13804
|
-
} else if (args.output === "-") {
|
|
13805
|
-
if (inputArg !== "-") {
|
|
13806
|
-
imageDir = dirname(resolve(inputArg));
|
|
13807
|
-
} else {
|
|
13808
|
-
imageDir = process.cwd();
|
|
13809
|
-
}
|
|
13810
|
-
mdOutputPath = "-";
|
|
13811
|
-
} else {
|
|
13812
|
-
if (inputArg !== "-") {
|
|
13813
|
-
const resolvedInput = resolve(inputArg);
|
|
13814
|
-
const inputDir = dirname(resolvedInput);
|
|
13815
|
-
const ext = extname(inputArg);
|
|
13816
|
-
const stem = basename(inputArg, ext);
|
|
13817
|
-
imageDir = inputDir;
|
|
13818
|
-
mdOutputPath = join(inputDir, `${stem}-rendered.md`);
|
|
13819
|
-
} else {
|
|
13820
|
-
imageDir = process.cwd();
|
|
13821
|
-
mdOutputPath = "-";
|
|
13822
|
-
}
|
|
13823
|
-
}
|
|
13824
|
-
let imageStem;
|
|
13825
|
-
if (inputArg !== "-") {
|
|
13826
|
-
const ext = extname(inputArg);
|
|
13827
|
-
imageStem = basename(inputArg, ext);
|
|
13828
|
-
} else if (mdOutputPath !== "-") {
|
|
13829
|
-
const ext = extname(mdOutputPath);
|
|
13830
|
-
imageStem = basename(mdOutputPath, ext);
|
|
13831
|
-
} else {
|
|
13832
|
-
imageStem = "diagram";
|
|
13833
|
-
}
|
|
13834
|
-
const blocks = extractZenumlBlocks(mdContent);
|
|
13835
|
-
const effectiveScale = args.scale ?? 2;
|
|
13836
|
-
const effectiveTheme = args.theme;
|
|
13837
|
-
const renderOptions = {};
|
|
13838
|
-
if (effectiveTheme) {
|
|
13839
|
-
renderOptions.theme = effectiveTheme;
|
|
13840
|
-
}
|
|
13841
|
-
const imageFiles = /* @__PURE__ */ new Map();
|
|
13842
|
-
for (const block of blocks) {
|
|
13843
|
-
if (block.empty) continue;
|
|
13844
|
-
const imageFilename = `${imageStem}-zenuml-${block.index}.${effectiveFormat}`;
|
|
13845
|
-
const imageFilePath = join(imageDir, imageFilename);
|
|
13846
|
-
let svg;
|
|
13847
|
-
let svgWidth;
|
|
13848
|
-
let svgHeight;
|
|
13849
|
-
try {
|
|
13850
|
-
const result = renderToSvg(block.code, renderOptions);
|
|
13851
|
-
svg = result.svg;
|
|
13852
|
-
svgWidth = result.width;
|
|
13853
|
-
svgHeight = result.height;
|
|
13854
|
-
} catch (err) {
|
|
13855
|
-
process.stderr.write(
|
|
13856
|
-
`Error: Failed to render zenuml block ${block.index}: ${err.message}
|
|
13857
|
-
`
|
|
13858
|
-
);
|
|
13859
|
-
process.exit(1);
|
|
13860
|
-
}
|
|
13861
|
-
mkdirSync(imageDir, { recursive: true });
|
|
13862
|
-
if (effectiveFormat === "png") {
|
|
13863
|
-
const pngBuffer = await rasterizeToPng(
|
|
13864
|
-
svg,
|
|
13865
|
-
svgWidth,
|
|
13866
|
-
svgHeight,
|
|
13867
|
-
effectiveScale
|
|
13868
|
-
);
|
|
13869
|
-
writeFileSync(imageFilePath, pngBuffer);
|
|
13870
|
-
} else {
|
|
13871
|
-
writeFileSync(imageFilePath, svg, "utf-8");
|
|
13872
|
-
}
|
|
13873
|
-
if (!args.quiet) {
|
|
13874
|
-
process.stderr.write(`Wrote ${imageFilePath}
|
|
13875
|
-
`);
|
|
13876
|
-
}
|
|
13877
|
-
imageFiles.set(block.index, imageFilename);
|
|
13878
|
-
}
|
|
13879
|
-
let outputMd = mdContent;
|
|
13880
|
-
const sortedBlocks = [...blocks].reverse();
|
|
13881
|
-
for (const block of sortedBlocks) {
|
|
13882
|
-
const altText = block.title || `diagram ${block.index + 1}`;
|
|
13883
|
-
if (block.empty) {
|
|
13884
|
-
outputMd = outputMd.replace(block.raw, "");
|
|
13885
|
-
} else {
|
|
13886
|
-
const imageFilename = imageFiles.get(block.index);
|
|
13887
|
-
const replacement = ``;
|
|
13888
|
-
outputMd = outputMd.replace(block.raw, replacement);
|
|
13889
|
-
}
|
|
13890
|
-
}
|
|
13891
|
-
if (mdOutputPath === "-") {
|
|
13892
|
-
process.stdout.write(outputMd);
|
|
13893
|
-
} else {
|
|
13894
|
-
mkdirSync(dirname(mdOutputPath), { recursive: true });
|
|
13895
|
-
writeFileSync(mdOutputPath, outputMd, "utf-8");
|
|
13896
|
-
if (!args.quiet) {
|
|
13897
|
-
process.stderr.write(`Wrote ${mdOutputPath}
|
|
13898
|
-
`);
|
|
13899
|
-
}
|
|
13900
|
-
}
|
|
13901
|
-
process.exit(0);
|
|
13902
|
-
}
|
|
13903
13902
|
let configScale;
|
|
13904
13903
|
let configTheme;
|
|
13905
13904
|
let configOutputFormat;
|
|
@@ -13917,99 +13916,30 @@ async function main() {
|
|
|
13917
13916
|
);
|
|
13918
13917
|
process.exit(1);
|
|
13919
13918
|
}
|
|
13920
|
-
|
|
13921
|
-
|
|
13922
|
-
|
|
13923
|
-
|
|
13924
|
-
|
|
13925
|
-
|
|
13926
|
-
|
|
13927
|
-
|
|
13928
|
-
|
|
13929
|
-
|
|
13930
|
-
mdContent = readFileSync(resolve(inputArg), "utf-8");
|
|
13931
|
-
} catch {
|
|
13932
|
-
throw new Error(`Cannot read input file: ${resolve(inputArg)}`);
|
|
13933
|
-
}
|
|
13934
|
-
const effectiveFormat = args.outputFormat ?? "svg";
|
|
13935
|
-
if (effectiveFormat !== "svg" && effectiveFormat !== "png") {
|
|
13936
|
-
throw new Error(
|
|
13937
|
-
`Unsupported output format: "${effectiveFormat}". Use "svg" or "png".`
|
|
13938
|
-
);
|
|
13939
|
-
}
|
|
13940
|
-
let mdOutputPath;
|
|
13941
|
-
let imageDir;
|
|
13942
|
-
if (args.output && args.output !== "-") {
|
|
13943
|
-
const resolvedOutput = resolve(args.output);
|
|
13944
|
-
imageDir = dirname(resolvedOutput);
|
|
13945
|
-
mdOutputPath = resolvedOutput;
|
|
13946
|
-
} else if (args.output === "-") {
|
|
13947
|
-
imageDir = dirname(resolve(inputArg));
|
|
13948
|
-
mdOutputPath = "-";
|
|
13949
|
-
} else {
|
|
13950
|
-
const resolvedInput = resolve(inputArg);
|
|
13951
|
-
const inputDir = dirname(resolvedInput);
|
|
13952
|
-
const ext2 = extname(inputArg);
|
|
13953
|
-
const stem = basename(inputArg, ext2);
|
|
13954
|
-
imageDir = inputDir;
|
|
13955
|
-
mdOutputPath = join(inputDir, `${stem}-rendered.md`);
|
|
13956
|
-
}
|
|
13957
|
-
const ext = extname(inputArg);
|
|
13958
|
-
const imageStem = basename(inputArg, ext);
|
|
13959
|
-
const blocks = extractZenumlBlocks(mdContent);
|
|
13960
|
-
const effectiveScale = args.scale ?? configScale ?? 2;
|
|
13961
|
-
const imageFiles = /* @__PURE__ */ new Map();
|
|
13962
|
-
for (const block of blocks) {
|
|
13963
|
-
if (block.empty) continue;
|
|
13964
|
-
const imageFilename = `${imageStem}-zenuml-${block.index}.${effectiveFormat}`;
|
|
13965
|
-
const imageFilePath = join(imageDir, imageFilename);
|
|
13966
|
-
const result = renderToSvg(block.code);
|
|
13967
|
-
const { svg, width: svgWidth, height: svgHeight } = result;
|
|
13968
|
-
mkdirSync(imageDir, { recursive: true });
|
|
13969
|
-
if (effectiveFormat === "png") {
|
|
13970
|
-
const pngBuffer = await rasterizeToPng(
|
|
13971
|
-
svg,
|
|
13972
|
-
svgWidth,
|
|
13973
|
-
svgHeight,
|
|
13974
|
-
effectiveScale
|
|
13975
|
-
);
|
|
13976
|
-
writeFileSync(imageFilePath, pngBuffer);
|
|
13977
|
-
} else {
|
|
13978
|
-
writeFileSync(imageFilePath, svg, "utf-8");
|
|
13979
|
-
}
|
|
13980
|
-
imageFiles.set(block.index, imageFilename);
|
|
13981
|
-
}
|
|
13982
|
-
let outputMd = mdContent;
|
|
13983
|
-
const sortedBlocks = [...blocks].reverse();
|
|
13984
|
-
for (const block of sortedBlocks) {
|
|
13985
|
-
const altText = block.title || `diagram ${block.index + 1}`;
|
|
13986
|
-
if (block.empty) {
|
|
13987
|
-
outputMd = outputMd.replace(block.raw, "");
|
|
13988
|
-
} else {
|
|
13989
|
-
const imageFilename = imageFiles.get(block.index);
|
|
13990
|
-
const replacement = ``;
|
|
13991
|
-
outputMd = outputMd.replace(block.raw, replacement);
|
|
13992
|
-
}
|
|
13993
|
-
}
|
|
13994
|
-
if (mdOutputPath === "-") {
|
|
13995
|
-
process.stdout.write(outputMd);
|
|
13996
|
-
} else {
|
|
13997
|
-
mkdirSync(dirname(mdOutputPath), { recursive: true });
|
|
13998
|
-
writeFileSync(mdOutputPath, outputMd, "utf-8");
|
|
13999
|
-
}
|
|
14000
|
-
};
|
|
14001
|
-
const hasMdInputs = expandedInputs.some(
|
|
14002
|
-
(f) => /\.(?:md|markdown)$/i.test(f)
|
|
13919
|
+
const config = {
|
|
13920
|
+
configScale,
|
|
13921
|
+
configTheme,
|
|
13922
|
+
configOutputFormat,
|
|
13923
|
+
multipleInputs
|
|
13924
|
+
};
|
|
13925
|
+
const isMdMode = args.md || expandedInputs.some((f) => f !== "-" && /\.(?:md|markdown)$/i.test(f));
|
|
13926
|
+
if (isMdMode && multipleInputs) {
|
|
13927
|
+
process.stderr.write(
|
|
13928
|
+
"Error: --md mode supports only a single input file.\n"
|
|
14003
13929
|
);
|
|
14004
|
-
|
|
14005
|
-
|
|
14006
|
-
|
|
14007
|
-
|
|
14008
|
-
|
|
14009
|
-
|
|
14010
|
-
|
|
14011
|
-
renderMdFnForWatch
|
|
13930
|
+
process.exit(1);
|
|
13931
|
+
}
|
|
13932
|
+
const inputArg = expandedInputs[0];
|
|
13933
|
+
if (args.md && inputArg !== "-" && !/\.(?:md|markdown)$/i.test(inputArg)) {
|
|
13934
|
+
process.stderr.write(
|
|
13935
|
+
`Error: --md flag requires a .md or .markdown input file, got: ${inputArg}
|
|
13936
|
+
`
|
|
14012
13937
|
);
|
|
13938
|
+
process.exit(1);
|
|
13939
|
+
}
|
|
13940
|
+
if (args.watch) {
|
|
13941
|
+
const renderForWatch = (input) => isMdMode ? renderMarkdownFile(input, args, config) : renderOneFile(input, args, config);
|
|
13942
|
+
const watchHandle = await startWatchMode(expandedInputs, renderForWatch);
|
|
14013
13943
|
process.on("SIGINT", () => {
|
|
14014
13944
|
watchHandle.shutdown();
|
|
14015
13945
|
process.exit(0);
|
|
@@ -14018,16 +13948,26 @@ async function main() {
|
|
|
14018
13948
|
});
|
|
14019
13949
|
return;
|
|
14020
13950
|
}
|
|
13951
|
+
if (isMdMode) {
|
|
13952
|
+
try {
|
|
13953
|
+
await renderMarkdownFile(inputArg, args, config);
|
|
13954
|
+
process.exit(0);
|
|
13955
|
+
} catch (err) {
|
|
13956
|
+
process.stderr.write(`Error: ${err.message}
|
|
13957
|
+
`);
|
|
13958
|
+
process.exit(1);
|
|
13959
|
+
}
|
|
13960
|
+
}
|
|
14021
13961
|
let rendered = 0;
|
|
14022
13962
|
let errors = 0;
|
|
14023
|
-
for (const
|
|
13963
|
+
for (const inputArg2 of expandedInputs) {
|
|
14024
13964
|
if (!args.quiet) {
|
|
14025
|
-
const displayName =
|
|
13965
|
+
const displayName = inputArg2 === "-" ? "<stdin>" : inputArg2;
|
|
14026
13966
|
process.stderr.write(`Rendering ${displayName}...
|
|
14027
13967
|
`);
|
|
14028
13968
|
}
|
|
14029
13969
|
try {
|
|
14030
|
-
await renderOneFile(
|
|
13970
|
+
await renderOneFile(inputArg2, args, {
|
|
14031
13971
|
configScale,
|
|
14032
13972
|
configTheme,
|
|
14033
13973
|
configOutputFormat,
|
|
@@ -14036,7 +13976,7 @@ async function main() {
|
|
|
14036
13976
|
rendered++;
|
|
14037
13977
|
} catch (err) {
|
|
14038
13978
|
errors++;
|
|
14039
|
-
process.stderr.write(`Error: ${
|
|
13979
|
+
process.stderr.write(`Error: ${inputArg2}: ${err.message}
|
|
14040
13980
|
`);
|
|
14041
13981
|
}
|
|
14042
13982
|
}
|