@diagrammo/dgmo 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1275,6 +1275,67 @@ var init_palettes = __esm({
1275
1275
  }
1276
1276
  });
1277
1277
 
1278
+ // src/utils/parsing.ts
1279
+ function measureIndent(line7) {
1280
+ let indent = 0;
1281
+ for (const ch of line7) {
1282
+ if (ch === " ") indent++;
1283
+ else if (ch === " ") indent += 4;
1284
+ else break;
1285
+ }
1286
+ return indent;
1287
+ }
1288
+ function extractColor(label, palette) {
1289
+ const m = label.match(COLOR_SUFFIX_RE);
1290
+ if (!m) return { label };
1291
+ const colorName = m[1].trim();
1292
+ return {
1293
+ label: label.substring(0, m.index).trim(),
1294
+ color: resolveColor(colorName, palette)
1295
+ };
1296
+ }
1297
+ function collectIndentedValues(lines, startIndex) {
1298
+ const values = [];
1299
+ let j = startIndex + 1;
1300
+ for (; j < lines.length; j++) {
1301
+ const raw = lines[j];
1302
+ const trimmed = raw.trim();
1303
+ if (!trimmed) continue;
1304
+ if (trimmed.startsWith("//")) continue;
1305
+ if (raw[0] !== " " && raw[0] !== " ") break;
1306
+ values.push(trimmed.replace(/,\s*$/, ""));
1307
+ }
1308
+ return { values, newIndex: j - 1 };
1309
+ }
1310
+ function parsePipeMetadata(segments, aliasMap = /* @__PURE__ */ new Map()) {
1311
+ const metadata = {};
1312
+ for (let j = 1; j < segments.length; j++) {
1313
+ for (const part of segments[j].split(",")) {
1314
+ const trimmedPart = part.trim();
1315
+ if (!trimmedPart) continue;
1316
+ const colonIdx = trimmedPart.indexOf(":");
1317
+ if (colonIdx > 0) {
1318
+ const rawKey = trimmedPart.substring(0, colonIdx).trim().toLowerCase();
1319
+ const key = aliasMap.get(rawKey) ?? rawKey;
1320
+ const value = trimmedPart.substring(colonIdx + 1).trim();
1321
+ metadata[key] = value;
1322
+ }
1323
+ }
1324
+ }
1325
+ return metadata;
1326
+ }
1327
+ var COLOR_SUFFIX_RE, CHART_TYPE_RE, TITLE_RE, OPTION_RE;
1328
+ var init_parsing = __esm({
1329
+ "src/utils/parsing.ts"() {
1330
+ "use strict";
1331
+ init_colors();
1332
+ COLOR_SUFFIX_RE = /\(([^)]+)\)\s*$/;
1333
+ CHART_TYPE_RE = /^chart\s*:\s*(.+)/i;
1334
+ TITLE_RE = /^title\s*:\s*(.+)/i;
1335
+ OPTION_RE = /^([a-z][a-z0-9-]*)\s*:\s*(.+)$/i;
1336
+ }
1337
+ });
1338
+
1278
1339
  // src/sequence/participant-inference.ts
1279
1340
  function inferParticipantType(name) {
1280
1341
  for (const rule of PARTICIPANT_RULES) {
@@ -1591,54 +1652,6 @@ var init_arrows = __esm({
1591
1652
  }
1592
1653
  });
1593
1654
 
1594
- // src/utils/parsing.ts
1595
- function measureIndent(line7) {
1596
- let indent = 0;
1597
- for (const ch of line7) {
1598
- if (ch === " ") indent++;
1599
- else if (ch === " ") indent += 4;
1600
- else break;
1601
- }
1602
- return indent;
1603
- }
1604
- function extractColor(label, palette) {
1605
- const m = label.match(COLOR_SUFFIX_RE);
1606
- if (!m) return { label };
1607
- const colorName = m[1].trim();
1608
- return {
1609
- label: label.substring(0, m.index).trim(),
1610
- color: resolveColor(colorName, palette)
1611
- };
1612
- }
1613
- function parsePipeMetadata(segments, aliasMap = /* @__PURE__ */ new Map()) {
1614
- const metadata = {};
1615
- for (let j = 1; j < segments.length; j++) {
1616
- for (const part of segments[j].split(",")) {
1617
- const trimmedPart = part.trim();
1618
- if (!trimmedPart) continue;
1619
- const colonIdx = trimmedPart.indexOf(":");
1620
- if (colonIdx > 0) {
1621
- const rawKey = trimmedPart.substring(0, colonIdx).trim().toLowerCase();
1622
- const key = aliasMap.get(rawKey) ?? rawKey;
1623
- const value = trimmedPart.substring(colonIdx + 1).trim();
1624
- metadata[key] = value;
1625
- }
1626
- }
1627
- }
1628
- return metadata;
1629
- }
1630
- var COLOR_SUFFIX_RE, CHART_TYPE_RE, TITLE_RE, OPTION_RE;
1631
- var init_parsing = __esm({
1632
- "src/utils/parsing.ts"() {
1633
- "use strict";
1634
- init_colors();
1635
- COLOR_SUFFIX_RE = /\(([^)]+)\)\s*$/;
1636
- CHART_TYPE_RE = /^chart\s*:\s*(.+)/i;
1637
- TITLE_RE = /^title\s*:\s*(.+)/i;
1638
- OPTION_RE = /^([a-z][a-z0-9-]*)\s*:\s*(.+)$/i;
1639
- }
1640
- });
1641
-
1642
1655
  // src/sequence/parser.ts
1643
1656
  var parser_exports = {};
1644
1657
  __export(parser_exports, {
@@ -1659,6 +1672,13 @@ function isSequenceNote(el) {
1659
1672
  }
1660
1673
  function parseReturnLabel(rawLabel) {
1661
1674
  if (!rawLabel) return { label: "" };
1675
+ const standaloneMatch = rawLabel.match(/^<-\s*(.*)$/);
1676
+ if (standaloneMatch) {
1677
+ return {
1678
+ label: standaloneMatch[1].trim(),
1679
+ standaloneReturn: true
1680
+ };
1681
+ }
1662
1682
  const arrowReturn = rawLabel.match(ARROW_RETURN_PATTERN);
1663
1683
  if (arrowReturn) {
1664
1684
  return { label: arrowReturn[1].trim(), returnLabel: arrowReturn[2].trim() };
@@ -1996,14 +2016,15 @@ function parseSequenceDgmo(content) {
1996
2016
  const to = arrowMatch[2];
1997
2017
  lastMsgFrom = from;
1998
2018
  const rawLabel = arrowMatch[3]?.trim() || "";
1999
- const { label, returnLabel } = isAsync ? { label: rawLabel, returnLabel: void 0 } : parseReturnLabel(rawLabel);
2019
+ const { label, returnLabel, standaloneReturn } = isAsync ? { label: rawLabel, returnLabel: void 0, standaloneReturn: void 0 } : parseReturnLabel(rawLabel);
2000
2020
  const msg = {
2001
2021
  from,
2002
2022
  to,
2003
2023
  label,
2004
2024
  returnLabel,
2005
2025
  lineNumber,
2006
- ...isAsync ? { async: true } : {}
2026
+ ...isAsync ? { async: true } : {},
2027
+ ...standaloneReturn ? { standaloneReturn: true } : {}
2007
2028
  };
2008
2029
  result.messages.push(msg);
2009
2030
  currentContainer().push(msg);
@@ -3143,8 +3164,16 @@ function parseChart(content, palette) {
3143
3164
  continue;
3144
3165
  }
3145
3166
  if (key === "series") {
3146
- result.series = value;
3147
- const rawNames = value.split(",").map((s) => s.trim()).filter(Boolean);
3167
+ let rawNames;
3168
+ if (value) {
3169
+ result.series = value;
3170
+ rawNames = value.split(",").map((s) => s.trim()).filter(Boolean);
3171
+ } else {
3172
+ const collected = collectIndentedValues(lines, i);
3173
+ i = collected.newIndex;
3174
+ rawNames = collected.values;
3175
+ result.series = rawNames.join(", ");
3176
+ }
3148
3177
  const names = [];
3149
3178
  const nameColors = [];
3150
3179
  for (const raw of rawNames) {
@@ -3223,6 +3252,7 @@ var init_chart = __esm({
3223
3252
  "use strict";
3224
3253
  init_colors();
3225
3254
  init_diagnostics();
3255
+ init_parsing();
3226
3256
  VALID_TYPES = /* @__PURE__ */ new Set([
3227
3257
  "bar",
3228
3258
  "line",
@@ -3298,8 +3328,16 @@ function parseEChart(content, palette) {
3298
3328
  continue;
3299
3329
  }
3300
3330
  if (key === "series") {
3301
- result.series = value;
3302
- const rawNames = value.split(",").map((s) => s.trim()).filter(Boolean);
3331
+ let rawNames;
3332
+ if (value) {
3333
+ result.series = value;
3334
+ rawNames = value.split(",").map((s) => s.trim()).filter(Boolean);
3335
+ } else {
3336
+ const collected = collectIndentedValues(lines, i);
3337
+ i = collected.newIndex;
3338
+ rawNames = collected.values;
3339
+ result.series = rawNames.join(", ");
3340
+ }
3303
3341
  const names = [];
3304
3342
  const nameColors = [];
3305
3343
  for (const raw of rawNames) {
@@ -3335,11 +3373,23 @@ function parseEChart(content, palette) {
3335
3373
  continue;
3336
3374
  }
3337
3375
  if (key === "columns") {
3338
- result.columns = value.split(",").map((s) => s.trim());
3376
+ if (value) {
3377
+ result.columns = value.split(",").map((s) => s.trim());
3378
+ } else {
3379
+ const collected = collectIndentedValues(lines, i);
3380
+ i = collected.newIndex;
3381
+ result.columns = collected.values;
3382
+ }
3339
3383
  continue;
3340
3384
  }
3341
3385
  if (key === "rows") {
3342
- result.rows = value.split(",").map((s) => s.trim());
3386
+ if (value) {
3387
+ result.rows = value.split(",").map((s) => s.trim());
3388
+ } else {
3389
+ const collected = collectIndentedValues(lines, i);
3390
+ i = collected.newIndex;
3391
+ result.rows = collected.values;
3392
+ }
3343
3393
  continue;
3344
3394
  }
3345
3395
  if (key === "x") {
@@ -4167,19 +4217,36 @@ function resolveAxisLabels(parsed) {
4167
4217
  yLabel: parsed.ylabel ?? (isHorizontal ? void 0 : parsed.label)
4168
4218
  };
4169
4219
  }
4170
- function makeGridAxis(type, textColor, axisLineColor, splitLineColor, gridOpacity, label, data, nameGapOverride) {
4220
+ function makeGridAxis(type, textColor, axisLineColor, splitLineColor, gridOpacity, label, data, nameGapOverride, chartWidthHint) {
4171
4221
  const defaultGap = type === "value" ? 75 : 40;
4222
+ let catFontSize = 16;
4223
+ let catLabelExtras = {};
4224
+ if (type === "category" && data && data.length > 0) {
4225
+ const maxLabelLen = Math.max(...data.map((l) => l.length));
4226
+ const count = data.length;
4227
+ if (count > 10 || maxLabelLen > 20) catFontSize = 10;
4228
+ else if (count > 5 || maxLabelLen > 14) catFontSize = 11;
4229
+ else if (maxLabelLen > 8) catFontSize = 12;
4230
+ if (chartWidthHint && count > 0) {
4231
+ const availPerLabel = Math.floor(chartWidthHint * 0.85 / count);
4232
+ catLabelExtras = {
4233
+ width: availPerLabel,
4234
+ overflow: "break"
4235
+ };
4236
+ }
4237
+ }
4172
4238
  return {
4173
4239
  type,
4174
4240
  ...data && { data },
4175
4241
  axisLine: { lineStyle: { color: axisLineColor } },
4176
4242
  axisLabel: {
4177
4243
  color: textColor,
4178
- fontSize: type === "category" && data ? data.length > 10 ? 11 : data.length > 5 ? 12 : 16 : 16,
4244
+ fontSize: type === "category" && data ? catFontSize : 16,
4179
4245
  fontFamily: FONT_FAMILY,
4180
4246
  ...type === "category" && {
4181
4247
  interval: 0,
4182
- formatter: (value) => value.replace(/([a-z])([A-Z])/g, "$1\n$2").replace(/ /g, "\n")
4248
+ formatter: (value) => value.replace(/([a-z])([A-Z])/g, "$1\n$2"),
4249
+ ...catLabelExtras
4183
4250
  }
4184
4251
  },
4185
4252
  splitLine: { lineStyle: { color: splitLineColor, opacity: gridOpacity } },
@@ -4191,7 +4258,7 @@ function makeGridAxis(type, textColor, axisLineColor, splitLineColor, gridOpacit
4191
4258
  }
4192
4259
  };
4193
4260
  }
4194
- function buildEChartsOptionFromChart(parsed, palette, isDark) {
4261
+ function buildEChartsOptionFromChart(parsed, palette, isDark, chartWidth) {
4195
4262
  if (parsed.error) return {};
4196
4263
  const textColor = palette.text;
4197
4264
  const axisLineColor = palette.border;
@@ -4216,13 +4283,13 @@ function buildEChartsOptionFromChart(parsed, palette, isDark) {
4216
4283
  };
4217
4284
  switch (parsed.type) {
4218
4285
  case "bar":
4219
- return buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme);
4286
+ return buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth);
4220
4287
  case "bar-stacked":
4221
- return buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme);
4288
+ return buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth);
4222
4289
  case "line":
4223
- return parsed.seriesNames ? buildMultiLineOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme) : buildLineOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme);
4290
+ return parsed.seriesNames ? buildMultiLineOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth) : buildLineOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme, chartWidth);
4224
4291
  case "area":
4225
- return buildAreaOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme);
4292
+ return buildAreaOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme, chartWidth);
4226
4293
  case "pie":
4227
4294
  return buildPieOption(parsed, textColor, getSegmentColors(palette, parsed.data.length), titleConfig, tooltipTheme, false);
4228
4295
  case "doughnut":
@@ -4233,7 +4300,7 @@ function buildEChartsOptionFromChart(parsed, palette, isDark) {
4233
4300
  return buildPolarAreaOption(parsed, textColor, getSegmentColors(palette, parsed.data.length), titleConfig, tooltipTheme);
4234
4301
  }
4235
4302
  }
4236
- function buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme) {
4303
+ function buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth) {
4237
4304
  const { xLabel, yLabel } = resolveAxisLabels(parsed);
4238
4305
  const isHorizontal = parsed.orientation === "horizontal";
4239
4306
  const labels = parsed.data.map((d) => d.label);
@@ -4242,7 +4309,7 @@ function buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOp
4242
4309
  itemStyle: { color: d.color ?? colors[i % colors.length] }
4243
4310
  }));
4244
4311
  const hCatGap = isHorizontal && yLabel ? Math.max(40, Math.max(...labels.map((l) => l.length)) * 8 + 16) : void 0;
4245
- const categoryAxis = makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? yLabel : xLabel, labels, hCatGap);
4312
+ const categoryAxis = makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? yLabel : xLabel, labels, hCatGap, !isHorizontal ? chartWidth : void 0);
4246
4313
  const valueAxis = makeGridAxis("value", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? xLabel : yLabel);
4247
4314
  return {
4248
4315
  backgroundColor: "transparent",
@@ -4274,7 +4341,7 @@ function buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOp
4274
4341
  ]
4275
4342
  };
4276
4343
  }
4277
- function buildLineOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme) {
4344
+ function buildLineOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme, chartWidth) {
4278
4345
  const { xLabel, yLabel } = resolveAxisLabels(parsed);
4279
4346
  const lineColor = parsed.color ?? parsed.seriesNameColors?.[0] ?? palette.primary;
4280
4347
  const labels = parsed.data.map((d) => d.label);
@@ -4295,7 +4362,7 @@ function buildLineOption(parsed, palette, textColor, axisLineColor, splitLineCol
4295
4362
  top: parsed.title ? "15%" : "5%",
4296
4363
  containLabel: true
4297
4364
  },
4298
- xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels),
4365
+ xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels, void 0, chartWidth),
4299
4366
  yAxis: makeGridAxis("value", textColor, axisLineColor, splitLineColor, gridOpacity, yLabel),
4300
4367
  series: [
4301
4368
  {
@@ -4313,7 +4380,7 @@ function buildLineOption(parsed, palette, textColor, axisLineColor, splitLineCol
4313
4380
  ]
4314
4381
  };
4315
4382
  }
4316
- function buildMultiLineOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme) {
4383
+ function buildMultiLineOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth) {
4317
4384
  const { xLabel, yLabel } = resolveAxisLabels(parsed);
4318
4385
  const seriesNames = parsed.seriesNames ?? [];
4319
4386
  const labels = parsed.data.map((d) => d.label);
@@ -4357,12 +4424,12 @@ function buildMultiLineOption(parsed, textColor, axisLineColor, splitLineColor,
4357
4424
  top: parsed.title ? "15%" : "5%",
4358
4425
  containLabel: true
4359
4426
  },
4360
- xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels),
4427
+ xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels, void 0, chartWidth),
4361
4428
  yAxis: makeGridAxis("value", textColor, axisLineColor, splitLineColor, gridOpacity, yLabel),
4362
4429
  series
4363
4430
  };
4364
4431
  }
4365
- function buildAreaOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme) {
4432
+ function buildAreaOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme, chartWidth) {
4366
4433
  const { xLabel, yLabel } = resolveAxisLabels(parsed);
4367
4434
  const lineColor = parsed.color ?? parsed.seriesNameColors?.[0] ?? palette.primary;
4368
4435
  const labels = parsed.data.map((d) => d.label);
@@ -4383,7 +4450,7 @@ function buildAreaOption(parsed, palette, textColor, axisLineColor, splitLineCol
4383
4450
  top: parsed.title ? "15%" : "5%",
4384
4451
  containLabel: true
4385
4452
  },
4386
- xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels),
4453
+ xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels, void 0, chartWidth),
4387
4454
  yAxis: makeGridAxis("value", textColor, axisLineColor, splitLineColor, gridOpacity, yLabel),
4388
4455
  series: [
4389
4456
  {
@@ -4543,7 +4610,7 @@ function buildPolarAreaOption(parsed, textColor, colors, titleConfig, tooltipThe
4543
4610
  ]
4544
4611
  };
4545
4612
  }
4546
- function buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme) {
4613
+ function buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth) {
4547
4614
  const { xLabel, yLabel } = resolveAxisLabels(parsed);
4548
4615
  const isHorizontal = parsed.orientation === "horizontal";
4549
4616
  const seriesNames = parsed.seriesNames ?? [];
@@ -4575,8 +4642,9 @@ function buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor,
4575
4642
  };
4576
4643
  });
4577
4644
  const hCatGap = isHorizontal && yLabel ? Math.max(40, Math.max(...labels.map((l) => l.length)) * 8 + 16) : void 0;
4578
- const categoryAxis = makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? yLabel : xLabel, labels, hCatGap);
4579
- const valueAxis = makeGridAxis("value", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? xLabel : yLabel);
4645
+ const categoryAxis = makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? yLabel : xLabel, labels, hCatGap, !isHorizontal ? chartWidth : void 0);
4646
+ const hValueGap = isHorizontal && xLabel ? 40 : void 0;
4647
+ const valueAxis = makeGridAxis("value", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? xLabel : yLabel, void 0, hValueGap);
4580
4648
  return {
4581
4649
  backgroundColor: "transparent",
4582
4650
  animation: false,
@@ -4613,7 +4681,7 @@ async function renderEChartsForExport(content, theme, palette, options) {
4613
4681
  if (chartType && STANDARD_CHART_TYPES.has(chartType)) {
4614
4682
  const parsed = parseChart(content, effectivePalette);
4615
4683
  if (parsed.error) return "";
4616
- option = buildEChartsOptionFromChart(parsed, effectivePalette, isDark);
4684
+ option = buildEChartsOptionFromChart(parsed, effectivePalette, isDark, ECHART_EXPORT_WIDTH);
4617
4685
  } else {
4618
4686
  const parsed = parseEChart(content, effectivePalette);
4619
4687
  if (parsed.error) return "";
@@ -4655,6 +4723,7 @@ var init_echarts = __esm({
4655
4723
  init_palettes();
4656
4724
  init_chart();
4657
4725
  init_diagnostics();
4726
+ init_parsing();
4658
4727
  ECHART_EXPORT_WIDTH = 1200;
4659
4728
  ECHART_EXPORT_HEIGHT = 800;
4660
4729
  STANDARD_CHART_TYPES = /* @__PURE__ */ new Set([
@@ -12140,6 +12209,22 @@ function buildRenderSequence(messages) {
12140
12209
  messageIndex: top.messageIndex
12141
12210
  });
12142
12211
  }
12212
+ if (msg.standaloneReturn) {
12213
+ for (let si = stack.length - 1; si >= 0; si--) {
12214
+ if (stack[si].from === msg.to && stack[si].to === msg.from) {
12215
+ stack.splice(si, 1);
12216
+ break;
12217
+ }
12218
+ }
12219
+ steps.push({
12220
+ type: "return",
12221
+ from: msg.from,
12222
+ to: msg.to,
12223
+ label: msg.label,
12224
+ messageIndex: mi
12225
+ });
12226
+ continue;
12227
+ }
12143
12228
  steps.push({
12144
12229
  type: "call",
12145
12230
  from: msg.from,
@@ -13421,18 +13506,34 @@ function parseD3(content, palette) {
13421
13506
  }
13422
13507
  }
13423
13508
  if (result.type === "quadrant") {
13424
- const xAxisMatch = line7.match(/^x-axis\s*:\s*(.+)/i);
13509
+ const xAxisMatch = line7.match(/^x-axis\s*:\s*(.*)/i);
13425
13510
  if (xAxisMatch) {
13426
- const parts = xAxisMatch[1].split(",").map((s) => s.trim());
13511
+ const val = xAxisMatch[1].trim();
13512
+ let parts;
13513
+ if (val) {
13514
+ parts = val.split(",").map((s) => s.trim());
13515
+ } else {
13516
+ const collected = collectIndentedValues(lines, i);
13517
+ i = collected.newIndex;
13518
+ parts = collected.values;
13519
+ }
13427
13520
  if (parts.length >= 2) {
13428
13521
  result.quadrantXAxis = [parts[0], parts[1]];
13429
13522
  result.quadrantXAxisLineNumber = lineNumber;
13430
13523
  }
13431
13524
  continue;
13432
13525
  }
13433
- const yAxisMatch = line7.match(/^y-axis\s*:\s*(.+)/i);
13526
+ const yAxisMatch = line7.match(/^y-axis\s*:\s*(.*)/i);
13434
13527
  if (yAxisMatch) {
13435
- const parts = yAxisMatch[1].split(",").map((s) => s.trim());
13528
+ const val = yAxisMatch[1].trim();
13529
+ let parts;
13530
+ if (val) {
13531
+ parts = val.split(",").map((s) => s.trim());
13532
+ } else {
13533
+ const collected = collectIndentedValues(lines, i);
13534
+ i = collected.newIndex;
13535
+ parts = collected.values;
13536
+ }
13436
13537
  if (parts.length >= 2) {
13437
13538
  result.quadrantYAxis = [parts[0], parts[1]];
13438
13539
  result.quadrantYAxisLineNumber = lineNumber;
@@ -13714,6 +13815,19 @@ function tokenizeFreeformText(text) {
13714
13815
  }
13715
13816
  return Array.from(counts.entries()).map(([text2, count]) => ({ text: text2, weight: count, lineNumber: 0 })).sort((a, b) => b.weight - a.weight);
13716
13817
  }
13818
+ function resolveVerticalCollisions(items, minGap) {
13819
+ if (items.length === 0) return [];
13820
+ const sorted = items.map((it, i) => ({ ...it, idx: i })).sort((a, b) => a.naturalY - b.naturalY);
13821
+ const adjustedY = new Array(items.length);
13822
+ let prevBottom = -Infinity;
13823
+ for (const item of sorted) {
13824
+ const halfH = item.height / 2;
13825
+ const top = Math.max(item.naturalY - halfH, prevBottom + minGap);
13826
+ adjustedY[item.idx] = top + halfH;
13827
+ prevBottom = top + item.height;
13828
+ }
13829
+ return adjustedY;
13830
+ }
13717
13831
  function renderSlopeChart(container, parsed, palette, isDark, onClickItem, exportDims) {
13718
13832
  d3Selection9.select(container).selectAll(":not([data-d3-tooltip])").remove();
13719
13833
  const { periods, data, title } = parsed;
@@ -13764,25 +13878,80 @@ function renderSlopeChart(container, parsed, palette, isDark, onClickItem, expor
13764
13878
  g.append("line").attr("x1", x).attr("y1", 0).attr("x2", x).attr("y2", innerHeight).attr("stroke", mutedColor).attr("stroke-width", 1).attr("stroke-dasharray", "4,4");
13765
13879
  }
13766
13880
  const lineGen = d3Shape6.line().x((_d, i) => xScale(periods[i])).y((d) => yScale(d));
13767
- data.forEach((item, idx) => {
13881
+ const seriesInfo = data.map((item, idx) => {
13768
13882
  const color = item.color ?? colors[idx % colors.length];
13769
- const seriesG = g.append("g").attr("class", "slope-series").attr("data-line-number", String(item.lineNumber));
13770
13883
  const firstVal = item.values[0];
13771
13884
  const lastVal = item.values[item.values.length - 1];
13772
13885
  const absChange = lastVal - firstVal;
13773
13886
  const pctChange = firstVal !== 0 ? absChange / firstVal * 100 : null;
13774
13887
  const sign = absChange > 0 ? "+" : "";
13775
- const pctPart = pctChange !== null ? ` (${sign}${pctChange.toFixed(1)}%)` : "";
13776
- const tipLines = [`${sign}${absChange}`];
13888
+ const tipLines = [`${sign}${parseFloat(absChange.toFixed(2))}`];
13777
13889
  if (pctChange !== null) tipLines.push(`${sign}${pctChange.toFixed(1)}%`);
13778
13890
  const tipHtml = tipLines.join("<br>");
13891
+ const lastX = xScale(periods[periods.length - 1]);
13892
+ const labelText = `${lastVal} \u2014 ${item.label}`;
13893
+ const availableWidth = rightMargin - 15;
13894
+ const maxChars = Math.floor(availableWidth / SLOPE_CHAR_WIDTH);
13895
+ let labelLineCount = 1;
13896
+ let wrappedLines = null;
13897
+ if (labelText.length > maxChars) {
13898
+ const words = labelText.split(/\s+/);
13899
+ const lines = [];
13900
+ let current = "";
13901
+ for (const word of words) {
13902
+ const test = current ? `${current} ${word}` : word;
13903
+ if (test.length > maxChars && current) {
13904
+ lines.push(current);
13905
+ current = word;
13906
+ } else {
13907
+ current = test;
13908
+ }
13909
+ }
13910
+ if (current) lines.push(current);
13911
+ labelLineCount = lines.length;
13912
+ wrappedLines = lines;
13913
+ }
13914
+ const lineHeight = SLOPE_LABEL_FONT_SIZE * 1.2;
13915
+ const labelHeight = labelLineCount === 1 ? SLOPE_LABEL_FONT_SIZE : labelLineCount * lineHeight;
13916
+ return {
13917
+ item,
13918
+ idx,
13919
+ color,
13920
+ firstVal,
13921
+ lastVal,
13922
+ tipHtml,
13923
+ lastX,
13924
+ labelText,
13925
+ maxChars,
13926
+ wrappedLines,
13927
+ labelHeight
13928
+ };
13929
+ });
13930
+ const leftLabelHeight = 20;
13931
+ const leftLabelCollisions = /* @__PURE__ */ new Map();
13932
+ for (let pi = 0; pi < periods.length - 1; pi++) {
13933
+ const entries = data.map((item) => ({
13934
+ naturalY: yScale(item.values[pi]),
13935
+ height: leftLabelHeight
13936
+ }));
13937
+ leftLabelCollisions.set(pi, resolveVerticalCollisions(entries, 4));
13938
+ }
13939
+ const rightEntries = seriesInfo.map((si) => ({
13940
+ naturalY: yScale(si.lastVal),
13941
+ height: Math.max(si.labelHeight, SLOPE_LABEL_FONT_SIZE * 1.4)
13942
+ }));
13943
+ const rightAdjustedY = resolveVerticalCollisions(rightEntries, 4);
13944
+ data.forEach((item, idx) => {
13945
+ const si = seriesInfo[idx];
13946
+ const color = si.color;
13947
+ const seriesG = g.append("g").attr("class", "slope-series").attr("data-line-number", String(item.lineNumber));
13779
13948
  seriesG.append("path").datum(item.values).attr("fill", "none").attr("stroke", color).attr("stroke-width", 2.5).attr("d", lineGen);
13780
13949
  seriesG.append("path").datum(item.values).attr("fill", "none").attr("stroke", "transparent").attr("stroke-width", 14).attr("d", lineGen).style("cursor", onClickItem ? "pointer" : "default").on(
13781
13950
  "mouseenter",
13782
- (event) => showTooltip(tooltip, tipHtml, event)
13951
+ (event) => showTooltip(tooltip, si.tipHtml, event)
13783
13952
  ).on(
13784
13953
  "mousemove",
13785
- (event) => showTooltip(tooltip, tipHtml, event)
13954
+ (event) => showTooltip(tooltip, si.tipHtml, event)
13786
13955
  ).on("mouseleave", () => hideTooltip(tooltip)).on("click", () => {
13787
13956
  if (onClickItem && item.lineNumber) onClickItem(item.lineNumber);
13788
13957
  });
@@ -13791,46 +13960,30 @@ function renderSlopeChart(container, parsed, palette, isDark, onClickItem, expor
13791
13960
  const y = yScale(val);
13792
13961
  seriesG.append("circle").attr("cx", x).attr("cy", y).attr("r", 4).attr("fill", color).attr("stroke", bgColor).attr("stroke-width", 1.5).style("cursor", onClickItem ? "pointer" : "default").on(
13793
13962
  "mouseenter",
13794
- (event) => showTooltip(tooltip, tipHtml, event)
13963
+ (event) => showTooltip(tooltip, si.tipHtml, event)
13795
13964
  ).on(
13796
13965
  "mousemove",
13797
- (event) => showTooltip(tooltip, tipHtml, event)
13966
+ (event) => showTooltip(tooltip, si.tipHtml, event)
13798
13967
  ).on("mouseleave", () => hideTooltip(tooltip)).on("click", () => {
13799
13968
  if (onClickItem && item.lineNumber) onClickItem(item.lineNumber);
13800
13969
  });
13801
13970
  const isFirst = i === 0;
13802
13971
  const isLast = i === periods.length - 1;
13803
13972
  if (!isLast) {
13804
- seriesG.append("text").attr("x", isFirst ? x - 10 : x).attr("y", y).attr("dy", "0.35em").attr("text-anchor", isFirst ? "end" : "middle").attr("fill", textColor).attr("font-size", "16px").text(val.toString());
13973
+ const adjustedY = leftLabelCollisions.get(i)[idx];
13974
+ seriesG.append("text").attr("x", isFirst ? x - 10 : x).attr("y", adjustedY).attr("dy", "0.35em").attr("text-anchor", isFirst ? "end" : "middle").attr("fill", color).attr("font-size", "16px").text(val.toString());
13805
13975
  }
13806
13976
  });
13807
- const lastX = xScale(periods[periods.length - 1]);
13808
- const lastY = yScale(lastVal);
13809
- const labelText = `${lastVal} \u2014 ${item.label}`;
13810
- const availableWidth = rightMargin - 15;
13811
- const maxChars = Math.floor(availableWidth / SLOPE_CHAR_WIDTH);
13812
- const labelEl = seriesG.append("text").attr("x", lastX + 10).attr("y", lastY).attr("text-anchor", "start").attr("fill", color).attr("font-size", `${SLOPE_LABEL_FONT_SIZE}px`).attr("font-weight", "500");
13813
- if (labelText.length <= maxChars) {
13814
- labelEl.attr("dy", "0.35em").text(labelText);
13977
+ const adjustedLastY = rightAdjustedY[idx];
13978
+ const labelEl = seriesG.append("text").attr("x", si.lastX + 10).attr("y", adjustedLastY).attr("text-anchor", "start").attr("fill", color).attr("font-size", `${SLOPE_LABEL_FONT_SIZE}px`).attr("font-weight", "500");
13979
+ if (!si.wrappedLines) {
13980
+ labelEl.attr("dy", "0.35em").text(si.labelText);
13815
13981
  } else {
13816
- const words = labelText.split(/\s+/);
13817
- const lines = [];
13818
- let current = "";
13819
- for (const word of words) {
13820
- const test = current ? `${current} ${word}` : word;
13821
- if (test.length > maxChars && current) {
13822
- lines.push(current);
13823
- current = word;
13824
- } else {
13825
- current = test;
13826
- }
13827
- }
13828
- if (current) lines.push(current);
13829
13982
  const lineHeight = SLOPE_LABEL_FONT_SIZE * 1.2;
13830
- const totalHeight = (lines.length - 1) * lineHeight;
13983
+ const totalHeight = (si.wrappedLines.length - 1) * lineHeight;
13831
13984
  const startDy = -totalHeight / 2;
13832
- lines.forEach((line7, li) => {
13833
- labelEl.append("tspan").attr("x", lastX + 10).attr(
13985
+ si.wrappedLines.forEach((line7, li) => {
13986
+ labelEl.append("tspan").attr("x", si.lastX + 10).attr(
13834
13987
  "dy",
13835
13988
  li === 0 ? `${startDy + SLOPE_LABEL_FONT_SIZE * 0.35}px` : `${lineHeight}px`
13836
13989
  ).text(line7);
@@ -16248,6 +16401,7 @@ var init_d3 = __esm({
16248
16401
  init_colors();
16249
16402
  init_palettes();
16250
16403
  init_diagnostics();
16404
+ init_parsing();
16251
16405
  DEFAULT_CLOUD_OPTIONS = {
16252
16406
  rotate: "none",
16253
16407
  max: 0,