schematex 0.5.0 → 0.5.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.
Files changed (90) hide show
  1. package/README.md +15 -7
  2. package/dist/ai/ai-sdk.cjs +18 -12
  3. package/dist/ai/ai-sdk.cjs.map +1 -1
  4. package/dist/ai/ai-sdk.d.cts +4 -3
  5. package/dist/ai/ai-sdk.d.ts +4 -3
  6. package/dist/ai/ai-sdk.js +14 -8
  7. package/dist/ai/ai-sdk.js.map +1 -1
  8. package/dist/ai/index.cjs +15 -11
  9. package/dist/ai/index.d.cts +20 -153
  10. package/dist/ai/index.d.ts +20 -153
  11. package/dist/ai/index.js +3 -3
  12. package/dist/api-C5SECOxZ.d.cts +69 -0
  13. package/dist/api-Cr_MxttI.d.ts +69 -0
  14. package/dist/browser.cjs +23 -5
  15. package/dist/browser.cjs.map +1 -1
  16. package/dist/browser.d.cts +12 -3
  17. package/dist/browser.d.ts +12 -3
  18. package/dist/browser.js +13 -5
  19. package/dist/browser.js.map +1 -1
  20. package/dist/{chunk-3YUUC6RN.cjs → chunk-4QPDZJAL.cjs} +1421 -37
  21. package/dist/chunk-4QPDZJAL.cjs.map +1 -0
  22. package/dist/{chunk-NWPCY65Z.cjs → chunk-HK56GQQP.cjs} +544 -61
  23. package/dist/chunk-HK56GQQP.cjs.map +1 -0
  24. package/dist/{chunk-GTDQAN2Z.js → chunk-OK5ZS3LU.js} +1419 -38
  25. package/dist/chunk-OK5ZS3LU.js.map +1 -0
  26. package/dist/{chunk-XRCY75UV.cjs → chunk-QMTWG6JL.cjs} +947 -916
  27. package/dist/chunk-QMTWG6JL.cjs.map +1 -0
  28. package/dist/{chunk-HUPDIRBX.js → chunk-VCH7RI5H.js} +947 -916
  29. package/dist/chunk-VCH7RI5H.js.map +1 -0
  30. package/dist/{chunk-IM4RCUHA.js → chunk-VKPCR7BG.js} +544 -62
  31. package/dist/chunk-VKPCR7BG.js.map +1 -0
  32. package/dist/diagrams/blockdiagram/index.d.cts +1 -1
  33. package/dist/diagrams/blockdiagram/index.d.ts +1 -1
  34. package/dist/diagrams/circuit/index.cjs +7 -7
  35. package/dist/diagrams/circuit/index.d.cts +1 -1
  36. package/dist/diagrams/circuit/index.d.ts +1 -1
  37. package/dist/diagrams/circuit/index.js +1 -1
  38. package/dist/diagrams/ecomap/index.d.cts +1 -1
  39. package/dist/diagrams/ecomap/index.d.ts +1 -1
  40. package/dist/diagrams/entity/index.d.cts +1 -1
  41. package/dist/diagrams/entity/index.d.ts +1 -1
  42. package/dist/diagrams/fishbone/index.d.cts +1 -1
  43. package/dist/diagrams/fishbone/index.d.ts +1 -1
  44. package/dist/diagrams/flowchart/index.d.cts +2 -2
  45. package/dist/diagrams/flowchart/index.d.ts +2 -2
  46. package/dist/diagrams/genogram/index.d.cts +1 -1
  47. package/dist/diagrams/genogram/index.d.ts +1 -1
  48. package/dist/diagrams/ladder/index.d.cts +1 -1
  49. package/dist/diagrams/ladder/index.d.ts +1 -1
  50. package/dist/diagrams/logic/index.d.cts +1 -1
  51. package/dist/diagrams/logic/index.d.ts +1 -1
  52. package/dist/diagrams/orgchart/index.d.cts +1 -1
  53. package/dist/diagrams/orgchart/index.d.ts +1 -1
  54. package/dist/diagrams/pedigree/index.d.cts +1 -1
  55. package/dist/diagrams/pedigree/index.d.ts +1 -1
  56. package/dist/diagrams/phylo/index.d.cts +1 -1
  57. package/dist/diagrams/phylo/index.d.ts +1 -1
  58. package/dist/diagrams/sld/index.d.cts +1 -1
  59. package/dist/diagrams/sld/index.d.ts +1 -1
  60. package/dist/diagrams/sociogram/index.d.cts +1 -1
  61. package/dist/diagrams/sociogram/index.d.ts +1 -1
  62. package/dist/diagrams/timing/index.d.cts +1 -1
  63. package/dist/diagrams/timing/index.d.ts +1 -1
  64. package/dist/diagrams/venn/index.d.cts +1 -1
  65. package/dist/diagrams/venn/index.d.ts +1 -1
  66. package/dist/{index-C9A0h-CB.d.cts → index-BD2yDfQM.d.cts} +1 -1
  67. package/dist/{index-CJai_TEZ.d.ts → index-C30zQWZI.d.ts} +1 -1
  68. package/dist/index.cjs +24 -12
  69. package/dist/index.d.cts +3 -3
  70. package/dist/index.d.ts +3 -3
  71. package/dist/index.js +2 -2
  72. package/dist/react.cjs +7 -9
  73. package/dist/react.cjs.map +1 -1
  74. package/dist/react.d.cts +3 -2
  75. package/dist/react.d.ts +3 -2
  76. package/dist/react.js +7 -9
  77. package/dist/react.js.map +1 -1
  78. package/dist/tools-BHWaJPOl.d.ts +153 -0
  79. package/dist/tools-DlpuE76u.d.cts +153 -0
  80. package/dist/{types-BOAsqHoU.d.cts → types-WTr9W5Ud.d.cts} +2 -2
  81. package/dist/{types-BOAsqHoU.d.ts → types-WTr9W5Ud.d.ts} +2 -2
  82. package/package.json +2 -2
  83. package/dist/api-C5UcmT7n.d.cts +0 -22
  84. package/dist/api-C5UcmT7n.d.ts +0 -22
  85. package/dist/chunk-3YUUC6RN.cjs.map +0 -1
  86. package/dist/chunk-GTDQAN2Z.js.map +0 -1
  87. package/dist/chunk-HUPDIRBX.js.map +0 -1
  88. package/dist/chunk-IM4RCUHA.js.map +0 -1
  89. package/dist/chunk-NWPCY65Z.cjs.map +0 -1
  90. package/dist/chunk-XRCY75UV.cjs.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import { orgchart } from './chunk-I55HO32M.js';
2
- import { circuit } from './chunk-HUPDIRBX.js';
2
+ import { circuit } from './chunk-VCH7RI5H.js';
3
3
  import { blockdiagram } from './chunk-EPKIJEH7.js';
4
4
  import { ladder } from './chunk-IBRW3UOA.js';
5
5
  import { sld } from './chunk-6OSUNBZY.js';
@@ -16,7 +16,7 @@ import { sociogram } from './chunk-ZX74KJPM.js';
16
16
  import { timing } from './chunk-6URNSB6G.js';
17
17
  import { logic } from './chunk-ZYRCPSBU.js';
18
18
  import { resolveBaseTheme, resolveTimelineTheme, cssCustomProperties, resolveMindmapTheme } from './chunk-2VNMKOUO.js';
19
- import { matchQuotedTitle } from './chunk-5IKOLUWK.js';
19
+ import { matchQuotedTitle, stripQuotes } from './chunk-5IKOLUWK.js';
20
20
  import { el, escapeXml, title, desc, text, path, rect, group, svgRoot, defs, circle, polygon, line, multilineText } from './chunk-SYYBKDL7.js';
21
21
 
22
22
  // src/diagrams/decisiontree/parser.ts
@@ -3935,7 +3935,7 @@ function renderLayout(layout) {
3935
3935
  var state = {
3936
3936
  type: "state",
3937
3937
  detect(text2) {
3938
- return /^\s*state\b/i.test(text2);
3938
+ return /^\s*(?:state\b|stateDiagram(?:-v2)?\b)/i.test(text2);
3939
3939
  },
3940
3940
  parse: parseStateDiagram,
3941
3941
  render(text2, config) {
@@ -7184,7 +7184,7 @@ function parseHeader(state2) {
7184
7184
  if (!m) break;
7185
7185
  const key = m[1].toLowerCase();
7186
7186
  const valueRaw = m[2].trim();
7187
- const value = stripQuotes(valueRaw);
7187
+ const value = stripQuotes2(valueRaw);
7188
7188
  if (key === "title") state2.ast.title = value;
7189
7189
  else if (key === "system") state2.ast.system = value;
7190
7190
  else if (key === "direction") {
@@ -7202,7 +7202,7 @@ function parseHeader(state2) {
7202
7202
  state2.i++;
7203
7203
  }
7204
7204
  }
7205
- function stripQuotes(s) {
7205
+ function stripQuotes2(s) {
7206
7206
  const t = s.trim();
7207
7207
  if (t.startsWith('"') && t.endsWith('"') && t.length >= 2) return t.slice(1, -1);
7208
7208
  return t;
@@ -7239,7 +7239,7 @@ function parseActorDecl(ln, state2) {
7239
7239
  id = asMatch[1];
7240
7240
  rest = rest.slice(0, asMatch.index).trim();
7241
7241
  }
7242
- const name = stripQuotes(rest);
7242
+ const name = stripQuotes2(rest);
7243
7243
  if (!name) throw new UsecaseParseError(`actor declaration missing name`, ln.line);
7244
7244
  const actorId = id ?? defaultIdFor(name);
7245
7245
  declareId(state2, actorId, "actor", ln.line);
@@ -7275,7 +7275,7 @@ function parseUsecaseDecl(ln, state2) {
7275
7275
  id = asMatch[1];
7276
7276
  rest = rest.slice(0, asMatch.index).trim();
7277
7277
  }
7278
- const name = stripQuotes(rest);
7278
+ const name = stripQuotes2(rest);
7279
7279
  if (!name) throw new UsecaseParseError(`usecase declaration missing name`, ln.line);
7280
7280
  const ucId = id ?? defaultIdFor(name);
7281
7281
  declareId(state2, ucId, "usecase", ln.line);
@@ -8030,13 +8030,13 @@ function layoutUsecase(ast) {
8030
8030
  pb = perimeter(r.target, a.cx, a.cy);
8031
8031
  }
8032
8032
  const dashed = r.kind === "include" || r.kind === "extend";
8033
- let arrowKind = "none";
8034
- if (r.kind === "directed" || r.kind === "include" || r.kind === "extend") arrowKind = "open";
8035
- else if (r.kind === "generalization") arrowKind = "hollow";
8033
+ let arrowKind2 = "none";
8034
+ if (r.kind === "directed" || r.kind === "include" || r.kind === "extend") arrowKind2 = "open";
8035
+ else if (r.kind === "generalization") arrowKind2 = "hollow";
8036
8036
  const edge = {
8037
8037
  relation: r,
8038
8038
  d: `M ${round(pa.x)} ${round(pa.y)} L ${round(pb.x)} ${round(pb.y)}`,
8039
- arrowKind,
8039
+ arrowKind: arrowKind2,
8040
8040
  dashed
8041
8041
  };
8042
8042
  if (r.kind === "include" || r.kind === "extend") {
@@ -8519,7 +8519,7 @@ function preprocess7(src) {
8519
8519
  }
8520
8520
  return out;
8521
8521
  }
8522
- function stripQuotes2(s) {
8522
+ function stripQuotes3(s) {
8523
8523
  const t = s.trim();
8524
8524
  if (t.length >= 2 && (t.startsWith('"') && t.endsWith('"') || t.startsWith("'") && t.endsWith("'"))) {
8525
8525
  return t.slice(1, -1);
@@ -8537,7 +8537,7 @@ function parseHeaderLine(ln, ast) {
8537
8537
  if (!m) return false;
8538
8538
  const key = m[1].toLowerCase();
8539
8539
  const valueRaw = m[2].trim();
8540
- const value = stripQuotes2(valueRaw);
8540
+ const value = stripQuotes3(valueRaw);
8541
8541
  switch (key) {
8542
8542
  case "title":
8543
8543
  ast.title = value;
@@ -8666,23 +8666,23 @@ function parseTaskLine(ln, ast) {
8666
8666
  milestone = true;
8667
8667
  return "";
8668
8668
  }).trim();
8669
- const markers3 = [];
8669
+ const markers4 = [];
8670
8670
  KEY_RE.lastIndex = 0;
8671
8671
  let mm;
8672
8672
  while ((mm = KEY_RE.exec(rest)) !== null) {
8673
- markers3.push({ key: mm[1].toLowerCase(), start: mm.index, valStart: mm.index + mm[0].length });
8673
+ markers4.push({ key: mm[1].toLowerCase(), start: mm.index, valStart: mm.index + mm[0].length });
8674
8674
  }
8675
8675
  const values = {};
8676
- for (let i = 0; i < markers3.length; i++) {
8677
- const cur = markers3[i];
8678
- const nextStart = i + 1 < markers3.length ? markers3[i + 1].start : rest.length;
8676
+ for (let i = 0; i < markers4.length; i++) {
8677
+ const cur = markers4[i];
8678
+ const nextStart = i + 1 < markers4.length ? markers4[i + 1].start : rest.length;
8679
8679
  const val = rest.slice(cur.valStart, nextStart).trim();
8680
8680
  if (cur.key in values) {
8681
8681
  throw new PertParseError(`duplicate '${cur.key}:' on task '${id}'`, ln.line);
8682
8682
  }
8683
8683
  values[cur.key] = val;
8684
8684
  }
8685
- const preamble = (markers3.length ? rest.slice(0, markers3[0].start) : rest).trim();
8685
+ const preamble = (markers4.length ? rest.slice(0, markers4[0].start) : rest).trim();
8686
8686
  if (preamble) {
8687
8687
  throw new PertParseError(`unexpected text '${preamble}' in task '${id}'`, ln.line);
8688
8688
  }
@@ -8710,7 +8710,7 @@ function parseTaskLine(ln, ast) {
8710
8710
  }
8711
8711
  const tags = values.tags ? values.tags.split(",").map((t) => t.trim()).filter(Boolean) : [];
8712
8712
  const className = values.class ? values.class.trim() : void 0;
8713
- const lane = values.lane ? stripQuotes2(values.lane) : void 0;
8713
+ const lane = values.lane ? stripQuotes3(values.lane) : void 0;
8714
8714
  const task = {
8715
8715
  id,
8716
8716
  label,
@@ -10265,6 +10265,155 @@ var pert = {
10265
10265
  }
10266
10266
  };
10267
10267
 
10268
+ // src/core/diagnostics.ts
10269
+ var ENGINE_BUG_NAMES = /* @__PURE__ */ new Set([
10270
+ "ReferenceError",
10271
+ "TypeError",
10272
+ "RangeError"
10273
+ ]);
10274
+ function diagnosticFromError(err) {
10275
+ if (err instanceof Error) {
10276
+ const anyErr = err;
10277
+ const hasParseFields = typeof anyErr.line === "number";
10278
+ const isEngineBug = !hasParseFields && ENGINE_BUG_NAMES.has(err.name);
10279
+ const source = typeof anyErr.source === "string" ? anyErr.source : isEngineBug ? firstStackFrame(err.stack) : void 0;
10280
+ return {
10281
+ severity: "error",
10282
+ code: isEngineBug ? "ENGINE_BUG" : "DSL_INVALID",
10283
+ line: typeof anyErr.line === "number" ? anyErr.line : void 0,
10284
+ column: typeof anyErr.column === "number" ? anyErr.column : void 0,
10285
+ source,
10286
+ message: isEngineBug ? `[engine bug: ${err.name}] ${err.message}` : err.message,
10287
+ hint: typeof anyErr.hint === "string" ? anyErr.hint : isEngineBug ? "This looks like a Schematex internal error rather than a DSL syntax problem. Keep the failing DSL and file an issue." : void 0,
10288
+ fatal: true
10289
+ };
10290
+ }
10291
+ return {
10292
+ severity: "error",
10293
+ code: "UNKNOWN_THROW",
10294
+ message: String(err),
10295
+ fatal: true
10296
+ };
10297
+ }
10298
+ function renderDiagnosticSvg(diagnostics, type, config = {}) {
10299
+ const headline = type ? `${type} preview could not be rendered` : "Diagram preview could not be rendered";
10300
+ const detail = diagnostics[0]?.message ?? "Schematex could not parse this DSL.";
10301
+ const lines = wrapText3(detail, 88).slice(0, 5);
10302
+ const source = diagnostics[0]?.source ? wrapText3(`Source: ${diagnostics[0].source}`, 88).slice(0, 2) : [];
10303
+ const foot = "Strict validation failed before a diagram could be drawn.";
10304
+ const width = 760;
10305
+ const lineHeight = 20;
10306
+ const height = 174 + (lines.length + source.length) * lineHeight;
10307
+ const fontFamily = config.fontFamily ?? "system-ui, -apple-system, sans-serif";
10308
+ const children = [
10309
+ title(headline),
10310
+ desc(`${headline}. ${detail}`),
10311
+ el(
10312
+ "style",
10313
+ {},
10314
+ `
10315
+ .schematex-preview-error { font-family: ${escapeXml(fontFamily)}; }
10316
+ .schematex-preview-error-frame { fill: #fff7ed; stroke: #c2410c; stroke-width: 1.5; }
10317
+ .schematex-preview-error-mark { fill: #c2410c; }
10318
+ .schematex-preview-error-title { fill: #7c2d12; font-size: 18px; font-weight: 600; }
10319
+ .schematex-preview-error-copy { fill: #431407; font-size: 13px; }
10320
+ .schematex-preview-error-muted { fill: #9a3412; font-size: 12px; }
10321
+ `
10322
+ ),
10323
+ el("g", { class: "schematex-preview-error" }, [
10324
+ rect({
10325
+ x: 1,
10326
+ y: 1,
10327
+ width: width - 2,
10328
+ height: height - 2,
10329
+ rx: 6,
10330
+ class: "schematex-preview-error-frame"
10331
+ }),
10332
+ rect({
10333
+ x: 28,
10334
+ y: 30,
10335
+ width: 8,
10336
+ height: 34,
10337
+ rx: 4,
10338
+ class: "schematex-preview-error-mark"
10339
+ }),
10340
+ rect({
10341
+ x: 28,
10342
+ y: 72,
10343
+ width: 8,
10344
+ height: 8,
10345
+ rx: 4,
10346
+ class: "schematex-preview-error-mark"
10347
+ }),
10348
+ text(
10349
+ { x: 58, y: 49, class: "schematex-preview-error-title" },
10350
+ headline
10351
+ ),
10352
+ text(
10353
+ { x: 58, y: 76, class: "schematex-preview-error-muted" },
10354
+ "The DSL is still available to repair or retry."
10355
+ ),
10356
+ ...renderRows(lines, 58, 112, lineHeight, "schematex-preview-error-copy"),
10357
+ ...renderRows(
10358
+ source,
10359
+ 58,
10360
+ 112 + lines.length * lineHeight + 10,
10361
+ lineHeight,
10362
+ "schematex-preview-error-muted"
10363
+ ),
10364
+ text(
10365
+ { x: 58, y: height - 28, class: "schematex-preview-error-muted" },
10366
+ foot
10367
+ )
10368
+ ])
10369
+ ];
10370
+ return svgRoot(
10371
+ {
10372
+ width,
10373
+ height,
10374
+ viewBox: `0 0 ${width} ${height}`,
10375
+ role: "img",
10376
+ "aria-label": headline,
10377
+ "data-schematex-status": "invalid"
10378
+ },
10379
+ children
10380
+ );
10381
+ }
10382
+ function renderRows(rows, x, y, lineHeight, className) {
10383
+ return rows.map(
10384
+ (row, idx) => text({ x, y: y + idx * lineHeight, class: className }, row)
10385
+ );
10386
+ }
10387
+ function wrapText3(value, max) {
10388
+ const words = value.replace(/\s+/g, " ").trim().split(" ");
10389
+ const rows = [];
10390
+ let current = "";
10391
+ for (const word of words) {
10392
+ if (!current) {
10393
+ current = word;
10394
+ continue;
10395
+ }
10396
+ if (current.length + word.length + 1 <= max) {
10397
+ current += ` ${word}`;
10398
+ continue;
10399
+ }
10400
+ rows.push(current);
10401
+ current = word;
10402
+ }
10403
+ if (current) rows.push(current);
10404
+ return rows.length > 0 ? rows : [value];
10405
+ }
10406
+ function firstStackFrame(stack) {
10407
+ if (!stack) return void 0;
10408
+ for (const line2 of stack.split("\n")) {
10409
+ const trimmed = line2.trim();
10410
+ if (trimmed.startsWith("at ")) {
10411
+ return trimmed.replace(/\((?:.*\/)?([^/]+)\)/, "($1)");
10412
+ }
10413
+ }
10414
+ return void 0;
10415
+ }
10416
+
10268
10417
  // src/diagrams/mindmap/inline.ts
10269
10418
  var RE_TASK = /^\[( |x|X)\]\s+(.*)$/;
10270
10419
  function tokenizeInline(raw) {
@@ -11234,7 +11383,7 @@ function newAST() {
11234
11383
  config: { ...DEFAULT_CONFIG }
11235
11384
  };
11236
11385
  }
11237
- function stripQuotes3(s) {
11386
+ function stripQuotes4(s) {
11238
11387
  const t = s.trim();
11239
11388
  if (t.startsWith('"') && t.endsWith('"') || t.startsWith("'") && t.endsWith("'")) {
11240
11389
  return t.slice(1, -1);
@@ -11270,7 +11419,7 @@ function parseAxis(raw) {
11270
11419
  function parseNumberList2(raw) {
11271
11420
  const t = raw.trim();
11272
11421
  const inner = t.startsWith("[") && t.endsWith("]") ? t.slice(1, -1) : t;
11273
- return inner.split(",").map((s) => stripQuotes3(s.trim())).filter((s) => s.length > 0);
11422
+ return inner.split(",").map((s) => stripQuotes4(s.trim())).filter((s) => s.length > 0);
11274
11423
  }
11275
11424
  function parseProperties2(raw, point) {
11276
11425
  let i = 0;
@@ -11385,7 +11534,7 @@ function parseHeader2(line2, ast) {
11385
11534
  ast.cols = Number(heatMatch[1]);
11386
11535
  ast.rows = Number(heatMatch[2]);
11387
11536
  const title2 = heatMatch[3].trim();
11388
- if (title2) ast.title = stripQuotes3(title2);
11537
+ if (title2) ast.title = stripQuotes4(title2);
11389
11538
  return void 0;
11390
11539
  }
11391
11540
  const corrMatch = rest.match(/^correlation\s*(?:(\d+)\s*x\s*(\d+))?\s*(.*)$/i);
@@ -11397,7 +11546,7 @@ function parseHeader2(line2, ast) {
11397
11546
  ast.rows = Number(corrMatch[2]);
11398
11547
  }
11399
11548
  const title2 = corrMatch[3].trim();
11400
- if (title2) ast.title = stripQuotes3(title2);
11549
+ if (title2) ast.title = stripQuotes4(title2);
11401
11550
  return void 0;
11402
11551
  }
11403
11552
  const tokenMatch = rest.match(/^([a-zA-Z0-9_-]+)\s*(.*)$/);
@@ -11405,13 +11554,13 @@ function parseHeader2(line2, ast) {
11405
11554
  const tok = tokenMatch[1].toLowerCase();
11406
11555
  const remainder = tokenMatch[2].trim();
11407
11556
  if (TEMPLATE_NAMES.has(tok)) {
11408
- if (remainder) ast.title = stripQuotes3(remainder);
11557
+ if (remainder) ast.title = stripQuotes4(remainder);
11409
11558
  return tok;
11410
11559
  }
11411
11560
  if (rest.startsWith('"') || rest.startsWith("'")) {
11412
- ast.title = stripQuotes3(rest);
11561
+ ast.title = stripQuotes4(rest);
11413
11562
  } else if (rest.length > 0) {
11414
- ast.title = stripQuotes3(rest);
11563
+ ast.title = stripQuotes4(rest);
11415
11564
  }
11416
11565
  }
11417
11566
  return void 0;
@@ -11447,7 +11596,7 @@ function parseMatrix(text2) {
11447
11596
  inConfig = false;
11448
11597
  }
11449
11598
  if (/^title\s*:/i.test(line2)) {
11450
- st.ast.title = stripQuotes3(line2.replace(/^title\s*:\s*/i, ""));
11599
+ st.ast.title = stripQuotes4(line2.replace(/^title\s*:\s*/i, ""));
11451
11600
  continue;
11452
11601
  }
11453
11602
  if (/^x-axis\s*:/i.test(line2)) {
@@ -11532,7 +11681,7 @@ function parseMatrix(text2) {
11532
11681
  if (qShort) {
11533
11682
  const q = Number(qShort[1]);
11534
11683
  const labelRaw = qShort[2].trim();
11535
- const label = stripQuotes3(labelRaw);
11684
+ const label = stripQuotes4(labelRaw);
11536
11685
  const cell = quadrantToCell(q);
11537
11686
  st.ast.cellLabels.push({ col: cell.col, row: cell.row, label });
11538
11687
  continue;
@@ -13420,10 +13569,10 @@ function renderEntity(e) {
13420
13569
  a.name
13421
13570
  )
13422
13571
  );
13423
- const markers3 = attrMarkers(a);
13572
+ const markers4 = attrMarkers(a);
13424
13573
  const markerW = 26;
13425
13574
  const markerGap = 4;
13426
- const markersBlockW = markers3.length * markerW + (markers3.length - 1) * markerGap;
13575
+ const markersBlockW = markers4.length * markerW + (markers4.length - 1) * markerGap;
13427
13576
  const markersStartX = e.x + e.width - C2.ENTITY_PADDING_X - markersBlockW;
13428
13577
  if (a.type) {
13429
13578
  body.push(
@@ -13438,8 +13587,8 @@ function renderEntity(e) {
13438
13587
  )
13439
13588
  );
13440
13589
  }
13441
- for (let j = 0; j < markers3.length; j++) {
13442
- const m = markers3[j];
13590
+ for (let j = 0; j < markers4.length; j++) {
13591
+ const m = markers4[j];
13443
13592
  const px = markersStartX + j * (markerW + markerGap);
13444
13593
  body.push(
13445
13594
  rect({
@@ -18613,6 +18762,1178 @@ var sfc = {
18613
18762
  }
18614
18763
  };
18615
18764
 
18765
+ // src/diagrams/sequence/parser.ts
18766
+ var SequenceParseError = class extends Error {
18767
+ line;
18768
+ constructor(message, line2) {
18769
+ super(line2 ? `${message} (line ${line2})` : message);
18770
+ this.name = "SequenceParseError";
18771
+ this.line = line2;
18772
+ }
18773
+ };
18774
+ var KINDS = /* @__PURE__ */ new Set([
18775
+ "participant",
18776
+ "actor",
18777
+ "boundary",
18778
+ "control",
18779
+ "entity",
18780
+ "database",
18781
+ "collections",
18782
+ "queue"
18783
+ ]);
18784
+ var SIMPLE_FRAG = /* @__PURE__ */ new Set([
18785
+ "opt",
18786
+ "loop",
18787
+ "break",
18788
+ "critical",
18789
+ "neg",
18790
+ "ignore",
18791
+ "consider",
18792
+ "assert"
18793
+ ]);
18794
+ var MULTI_FRAG = /* @__PURE__ */ new Set(["par", "seq", "strict"]);
18795
+ var MSGSET_FRAG = /* @__PURE__ */ new Set(["ignore", "consider"]);
18796
+ var ALL_FRAG = /* @__PURE__ */ new Set([
18797
+ "alt",
18798
+ ...SIMPLE_FRAG,
18799
+ ...MULTI_FRAG
18800
+ ]);
18801
+ var ARROW_RE = /(-->|->>|o->|-x|->)/;
18802
+ function arrowKind(token) {
18803
+ switch (token) {
18804
+ case "-->":
18805
+ return "reply";
18806
+ case "->>":
18807
+ return "async";
18808
+ case "o->":
18809
+ return "found";
18810
+ case "-x":
18811
+ return "lost";
18812
+ default:
18813
+ return "sync";
18814
+ }
18815
+ }
18816
+ function firstWord(s) {
18817
+ const m = /^(\S+)/.exec(s);
18818
+ return m ? m[1] : "";
18819
+ }
18820
+ function extractGuard(rest) {
18821
+ const t = rest.trim();
18822
+ if (!t) return void 0;
18823
+ if (t.startsWith("[") && t.endsWith("]")) return t.slice(1, -1).trim();
18824
+ if (t.startsWith("(") && t.endsWith(")")) return t.slice(1, -1).trim();
18825
+ return t;
18826
+ }
18827
+ var SequenceParser = class {
18828
+ lines;
18829
+ i = 0;
18830
+ order = [];
18831
+ byId = /* @__PURE__ */ new Map();
18832
+ warnings = [];
18833
+ constructor(source) {
18834
+ this.lines = source.split(/\r?\n/).map((raw, idx) => ({
18835
+ text: raw.trim(),
18836
+ n: idx + 1
18837
+ }));
18838
+ }
18839
+ parse() {
18840
+ const header = this.consumeHeader();
18841
+ const ast = {
18842
+ type: "sequence",
18843
+ participants: [],
18844
+ statements: [],
18845
+ warnings: this.warnings
18846
+ };
18847
+ if (header.title) ast.title = header.title;
18848
+ const statements = this.parseBlock();
18849
+ const leftover = this.peek();
18850
+ if (leftover) {
18851
+ const fw = firstWord(leftover.text).toLowerCase();
18852
+ throw new SequenceParseError(
18853
+ `'${fw}' without a matching combined fragment`,
18854
+ leftover.n
18855
+ );
18856
+ }
18857
+ if (this.autonumberSpec) ast.autonumber = this.autonumberSpec;
18858
+ ast.statements = statements;
18859
+ ast.participants = this.order.map((id) => this.byId.get(id));
18860
+ return ast;
18861
+ }
18862
+ autonumberSpec;
18863
+ // ── line cursor ──────────────────────────────────────────────
18864
+ peek() {
18865
+ while (this.i < this.lines.length) {
18866
+ const ln = this.lines[this.i];
18867
+ if (ln.text === "" || ln.text.startsWith("#") || ln.text.startsWith("//")) {
18868
+ this.i++;
18869
+ continue;
18870
+ }
18871
+ return ln;
18872
+ }
18873
+ return null;
18874
+ }
18875
+ next() {
18876
+ const ln = this.peek();
18877
+ if (ln) this.i++;
18878
+ return ln;
18879
+ }
18880
+ // ── header ───────────────────────────────────────────────────
18881
+ consumeHeader() {
18882
+ const ln = this.next();
18883
+ if (!ln || !/^sequence\b/i.test(ln.text)) {
18884
+ throw new SequenceParseError(
18885
+ "A sequence diagram must start with the keyword 'sequence'",
18886
+ ln?.n
18887
+ );
18888
+ }
18889
+ const title2 = matchQuotedTitle(ln.text);
18890
+ return title2 ? { title: title2 } : {};
18891
+ }
18892
+ // ── participants ─────────────────────────────────────────────
18893
+ ensure(id, kind = "participant", line2) {
18894
+ let p = this.byId.get(id);
18895
+ if (!p) {
18896
+ p = { id, name: id, kind, line: line2 };
18897
+ this.byId.set(id, p);
18898
+ this.order.push(id);
18899
+ }
18900
+ return p;
18901
+ }
18902
+ declare(line2) {
18903
+ const fw = firstWord(line2.text);
18904
+ const kind = fw.toLowerCase();
18905
+ let rest = line2.text.slice(fw.length).trim();
18906
+ let stereotype;
18907
+ const stereoMatch = /«([^»]*)»|<<([^>]*)>>/.exec(rest);
18908
+ if (stereoMatch) {
18909
+ stereotype = (stereoMatch[1] ?? stereoMatch[2] ?? "").trim();
18910
+ rest = (rest.slice(0, stereoMatch.index) + rest.slice(stereoMatch.index + stereoMatch[0].length)).trim();
18911
+ }
18912
+ let id;
18913
+ let name;
18914
+ const asMatch = /\sas\s/i.exec(rest);
18915
+ if (asMatch) {
18916
+ id = stripQuotes(rest.slice(0, asMatch.index).trim());
18917
+ name = stripQuotes(rest.slice(asMatch.index + asMatch[0].length).trim());
18918
+ } else {
18919
+ id = stripQuotes(rest);
18920
+ name = id;
18921
+ }
18922
+ if (!id) {
18923
+ throw new SequenceParseError(`'${fw}' declaration needs a name`, line2.n);
18924
+ }
18925
+ const existing = this.byId.get(id);
18926
+ if (existing) {
18927
+ existing.kind = kind;
18928
+ existing.name = name;
18929
+ if (stereotype) existing.stereotype = stereotype;
18930
+ } else {
18931
+ const p = { id, name, kind, line: line2.n };
18932
+ if (stereotype) p.stereotype = stereotype;
18933
+ this.byId.set(id, p);
18934
+ this.order.push(id);
18935
+ }
18936
+ }
18937
+ // ── block / statement dispatch ───────────────────────────────
18938
+ /** Parse statements until a terminator (`end`/`else`/`and`) or EOF. Terminators are left unconsumed. */
18939
+ parseBlock() {
18940
+ const out = [];
18941
+ for (; ; ) {
18942
+ const ln = this.peek();
18943
+ if (!ln) break;
18944
+ const fw = firstWord(ln.text).toLowerCase();
18945
+ if (fw === "end" || fw === "else" || fw === "and") break;
18946
+ if (KINDS.has(fw)) {
18947
+ this.i++;
18948
+ this.declare(ln);
18949
+ continue;
18950
+ }
18951
+ if (ALL_FRAG.has(fw)) {
18952
+ out.push(this.parseFragment(ln));
18953
+ continue;
18954
+ }
18955
+ this.i++;
18956
+ const stmt = this.parseSimpleStatement(ln);
18957
+ if (stmt) out.push(stmt);
18958
+ }
18959
+ return out;
18960
+ }
18961
+ parseFragment(open) {
18962
+ const fw = firstWord(open.text).toLowerCase();
18963
+ this.i++;
18964
+ let rest = open.text.slice(fw.length);
18965
+ let messageSet;
18966
+ if (MSGSET_FRAG.has(fw)) {
18967
+ const bm = /\{([^}]*)\}/.exec(rest);
18968
+ if (bm) {
18969
+ messageSet = bm[1].split(",").map((s) => s.trim()).filter(Boolean);
18970
+ rest = rest.slice(0, bm.index) + rest.slice(bm.index + bm[0].length);
18971
+ }
18972
+ }
18973
+ const firstGuard = extractGuard(rest);
18974
+ const operands = [
18975
+ { guard: firstGuard, statements: this.parseBlock() }
18976
+ ];
18977
+ for (; ; ) {
18978
+ const ln = this.peek();
18979
+ if (!ln) {
18980
+ throw new SequenceParseError(`Unterminated '${fw}' fragment`, open.n);
18981
+ }
18982
+ const term = firstWord(ln.text).toLowerCase();
18983
+ if (term === "end") {
18984
+ this.i++;
18985
+ break;
18986
+ }
18987
+ if (term === "else") {
18988
+ if (fw !== "alt") {
18989
+ throw new SequenceParseError(
18990
+ `'else' is only valid inside an 'alt' fragment, not '${fw}'`,
18991
+ ln.n
18992
+ );
18993
+ }
18994
+ this.i++;
18995
+ operands.push({
18996
+ guard: extractGuard(ln.text.slice(4)),
18997
+ statements: this.parseBlock()
18998
+ });
18999
+ continue;
19000
+ }
19001
+ if (term === "and") {
19002
+ if (!MULTI_FRAG.has(fw)) {
19003
+ throw new SequenceParseError(
19004
+ `'and' is only valid inside par/seq/strict, not '${fw}'`,
19005
+ ln.n
19006
+ );
19007
+ }
19008
+ this.i++;
19009
+ const label = ln.text.slice(3).trim();
19010
+ operands.push({
19011
+ guard: label ? extractGuard(label) : void 0,
19012
+ statements: this.parseBlock()
19013
+ });
19014
+ continue;
19015
+ }
19016
+ throw new SequenceParseError(`Unexpected '${term}' in '${fw}'`, ln.n);
19017
+ }
19018
+ const frag = { kind: "fragment", op: fw, operands, line: open.n };
19019
+ if (messageSet && messageSet.length) frag.messageSet = messageSet;
19020
+ return frag;
19021
+ }
19022
+ /** Non-fragment, non-participant statements. */
19023
+ parseSimpleStatement(ln) {
19024
+ const text2 = ln.text;
19025
+ const fw = firstWord(text2).toLowerCase();
19026
+ if (fw === "activate" || fw === "deactivate") {
19027
+ const m = /^(?:de)?activate\s+(\S+)$/i.exec(text2);
19028
+ if (!m) throw new SequenceParseError(`Malformed ${fw} statement`, ln.n);
19029
+ this.ensure(m[1], "participant", ln.n);
19030
+ return { kind: fw, id: m[1], line: ln.n };
19031
+ }
19032
+ if (fw === "note") {
19033
+ return this.parseNote(ln);
19034
+ }
19035
+ if (fw === "ref") {
19036
+ const m = /^ref\s+over\s+(.+?)\s*:\s*(.*)$/i.exec(text2);
19037
+ if (!m) throw new SequenceParseError("Malformed ref (expected: ref over A, B : text)", ln.n);
19038
+ const ids = m[1].split(",").map((s) => stripQuotes(s.trim())).filter(Boolean);
19039
+ ids.forEach((id) => this.ensure(id, "participant", ln.n));
19040
+ return { kind: "ref", ids, text: m[2].trim(), line: ln.n };
19041
+ }
19042
+ if (text2.startsWith("==")) {
19043
+ const m = /^==\s*(.*?)\s*==\s*$/.exec(text2);
19044
+ return { kind: "divider", text: m ? m[1].trim() : "", line: ln.n };
19045
+ }
19046
+ if (fw === "state") {
19047
+ const m = /^state\s+(\S+)\s*:\s*(.*)$/i.exec(text2);
19048
+ if (!m) throw new SequenceParseError("Malformed state invariant (expected: state A : text)", ln.n);
19049
+ this.ensure(m[1], "participant", ln.n);
19050
+ return { kind: "invariant", id: m[1], text: m[2].trim(), line: ln.n };
19051
+ }
19052
+ if (fw === "destroy") {
19053
+ const m = /^destroy\s+(\S+)$/i.exec(text2);
19054
+ if (!m) throw new SequenceParseError("Malformed destroy statement", ln.n);
19055
+ this.ensure(m[1], "participant", ln.n);
19056
+ return { kind: "destroy", id: m[1], line: ln.n };
19057
+ }
19058
+ if (fw === "autonumber") {
19059
+ const m = /^autonumber(?:\s+(\d+))?(?:\s+(\d+))?$/i.exec(text2);
19060
+ const start = m && m[1] ? parseInt(m[1], 10) : 1;
19061
+ const step = m && m[2] ? parseInt(m[2], 10) : 1;
19062
+ this.autonumberSpec = { start, step };
19063
+ return null;
19064
+ }
19065
+ return this.parseMessage(ln);
19066
+ }
19067
+ parseNote(ln) {
19068
+ const m = /^note\s+(over|left of|right of)\s+(.+?)\s*:\s*(.*)$/i.exec(ln.text);
19069
+ if (!m) {
19070
+ throw new SequenceParseError(
19071
+ "Malformed note (expected: note over|left of|right of A[, B] : text)",
19072
+ ln.n
19073
+ );
19074
+ }
19075
+ const placementRaw = m[1].toLowerCase();
19076
+ const placement = placementRaw === "over" ? "over" : placementRaw.startsWith("left") ? "left" : "right";
19077
+ const ids = m[2].split(",").map((s) => stripQuotes(s.trim())).filter(Boolean);
19078
+ ids.forEach((id) => this.ensure(id, "participant", ln.n));
19079
+ return { kind: "note", placement, ids, text: m[3].trim(), line: ln.n };
19080
+ }
19081
+ parseMessage(ln) {
19082
+ const text2 = ln.text;
19083
+ const arrowMatch = ARROW_RE.exec(text2);
19084
+ if (!arrowMatch) {
19085
+ throw new SequenceParseError(`Cannot parse statement: "${text2}"`, ln.n);
19086
+ }
19087
+ const token = arrowMatch[1];
19088
+ const at = arrowMatch.index;
19089
+ const leftRaw = text2.slice(0, at);
19090
+ let rightRaw = text2.slice(at + token.length);
19091
+ let label;
19092
+ const colon = rightRaw.indexOf(":");
19093
+ if (colon >= 0) {
19094
+ label = rightRaw.slice(colon + 1).trim();
19095
+ rightRaw = rightRaw.slice(0, colon);
19096
+ }
19097
+ let activateTarget = false;
19098
+ let deactivateSource = false;
19099
+ let left = leftRaw.trim();
19100
+ if (left.endsWith("+")) {
19101
+ activateTarget = true;
19102
+ left = left.slice(0, -1).trim();
19103
+ } else if (left.endsWith("-")) {
19104
+ deactivateSource = true;
19105
+ left = left.slice(0, -1).trim();
19106
+ }
19107
+ let right = rightRaw.trim();
19108
+ if (right.startsWith("+")) {
19109
+ activateTarget = true;
19110
+ right = right.slice(1).trim();
19111
+ } else if (right.startsWith("-")) {
19112
+ deactivateSource = true;
19113
+ right = right.slice(1).trim();
19114
+ }
19115
+ const arrow = arrowKind(token);
19116
+ let create = false;
19117
+ if (right.startsWith("*")) {
19118
+ create = true;
19119
+ right = right.slice(1).trim();
19120
+ }
19121
+ const from = arrow === "found" ? "" : stripQuotes(left);
19122
+ const to = arrow === "lost" ? "" : stripQuotes(right);
19123
+ if (from) this.ensure(from, "participant", ln.n);
19124
+ if (to) {
19125
+ const p = this.ensure(to, "participant", ln.n);
19126
+ if (create) p.createdInline = true;
19127
+ }
19128
+ const msg = {
19129
+ kind: "message",
19130
+ from,
19131
+ to,
19132
+ arrow,
19133
+ line: ln.n
19134
+ };
19135
+ if (label) msg.label = label;
19136
+ if (activateTarget) msg.activateTarget = true;
19137
+ if (deactivateSource) msg.deactivateSource = true;
19138
+ if (create) msg.create = true;
19139
+ return msg;
19140
+ }
19141
+ };
19142
+ function parseSequence(text2) {
19143
+ return new SequenceParser(text2).parse();
19144
+ }
19145
+
19146
+ // src/diagrams/sequence/layout.ts
19147
+ var SEQ_CONST = {
19148
+ HEAD_W_MIN: 90,
19149
+ HEAD_H: 38,
19150
+ HEAD_PAD_X: 14,
19151
+ LIFELINE_GAP: 140,
19152
+ LEFT_MARGIN: 24,
19153
+ RIGHT_PAD: 28,
19154
+ TOP_PAD: 16,
19155
+ HEAD_TO_FIRST: 30,
19156
+ EVENT_GAP: 38,
19157
+ BOTTOM_PAD: 30,
19158
+ SELF_GAP: 30,
19159
+ SELF_LOOP_W: 48,
19160
+ ACT_W: 10,
19161
+ ACT_NEST_DX: 6,
19162
+ ACT_STEP: 30,
19163
+ FRAG_PAD_X: 10,
19164
+ FRAG_LABEL_H: 18,
19165
+ FRAG_PAD_TOP: 16,
19166
+ FRAG_PAD_BOTTOM: 12,
19167
+ FRAG_GAP_BEFORE: 12,
19168
+ FRAG_OPERAND_GAP: 18,
19169
+ FRAG_NEST_INSET: 8,
19170
+ REF_H: 40,
19171
+ REF_GAP_BEFORE: 12,
19172
+ NOTE_GAP_BEFORE: 10,
19173
+ NOTE_PAD: 8,
19174
+ NOTE_MIN_W: 70,
19175
+ NOTE_LINE_H: 15,
19176
+ NOTE_SIDE_GAP: 16,
19177
+ DIV_H: 26,
19178
+ DIV_GAP_BEFORE: 8,
19179
+ INV_GAP_BEFORE: 10,
19180
+ INV_PAD: 10,
19181
+ INV_H: 24,
19182
+ LABEL_GAP_PAD: 26,
19183
+ LOST_LEN: 72
19184
+ };
19185
+ var LABEL_SIZE = 11;
19186
+ var HEAD_TEXT_SIZE = 12.5;
19187
+ function textWidth(s, size) {
19188
+ let w = 0;
19189
+ for (const ch of s) {
19190
+ w += /[⺀-￿]/.test(ch) ? size : size * 0.55;
19191
+ }
19192
+ return w;
19193
+ }
19194
+ var SequenceLayout = class {
19195
+ ast;
19196
+ lifelines = [];
19197
+ colOf = /* @__PURE__ */ new Map();
19198
+ llById = /* @__PURE__ */ new Map();
19199
+ x = [];
19200
+ headW = [];
19201
+ y = 0;
19202
+ open = /* @__PURE__ */ new Map();
19203
+ colAccStack = [];
19204
+ messages = [];
19205
+ activations = [];
19206
+ fragments = [];
19207
+ refs = [];
19208
+ notes = [];
19209
+ dividers = [];
19210
+ invariants = [];
19211
+ destroys = [];
19212
+ warnings = [];
19213
+ autoCounter = null;
19214
+ contentRight = 0;
19215
+ constructor(ast) {
19216
+ this.ast = ast;
19217
+ }
19218
+ run() {
19219
+ this.buildColumns();
19220
+ if (this.ast.autonumber) this.autoCounter = this.ast.autonumber.start;
19221
+ const headBottom = SEQ_CONST.TOP_PAD + SEQ_CONST.HEAD_H;
19222
+ this.y = headBottom + SEQ_CONST.HEAD_TO_FIRST - SEQ_CONST.EVENT_GAP;
19223
+ this.walk(this.ast.statements, 0);
19224
+ const bottomY = this.y + SEQ_CONST.EVENT_GAP;
19225
+ for (const [id, stack] of this.open) {
19226
+ while (stack.length) {
19227
+ const b = stack.pop();
19228
+ this.activations.push({ id, x: b.x, yTop: b.yTop, yBottom: bottomY, level: b.level });
19229
+ }
19230
+ }
19231
+ const bodyBottom = bottomY + SEQ_CONST.BOTTOM_PAD;
19232
+ for (const ll of this.lifelines) {
19233
+ if (!ll.destroyed) ll.axisBottom = bodyBottom;
19234
+ }
19235
+ const lastCenter = this.x[this.x.length - 1] ?? SEQ_CONST.LEFT_MARGIN;
19236
+ const lastHalf = (this.headW[this.headW.length - 1] ?? SEQ_CONST.HEAD_W_MIN) / 2;
19237
+ this.contentRight = Math.max(this.contentRight, lastCenter + lastHalf);
19238
+ const width = Math.round(this.contentRight + SEQ_CONST.RIGHT_PAD);
19239
+ const height = Math.round(bodyBottom);
19240
+ for (const d of this.dividers) d.width = width;
19241
+ const result = {
19242
+ width,
19243
+ height,
19244
+ lifelines: this.lifelines,
19245
+ messages: this.messages,
19246
+ activations: this.activations,
19247
+ fragments: this.fragments,
19248
+ refs: this.refs,
19249
+ notes: this.notes,
19250
+ dividers: this.dividers,
19251
+ invariants: this.invariants,
19252
+ destroys: this.destroys,
19253
+ warnings: this.warnings.concat(this.ast.warnings),
19254
+ ast: this.ast
19255
+ };
19256
+ if (this.ast.title) result.title = this.ast.title;
19257
+ return result;
19258
+ }
19259
+ // ── horizontal pass ──────────────────────────────────────────
19260
+ buildColumns() {
19261
+ const ps = this.ast.participants;
19262
+ this.headW = ps.map(
19263
+ (p) => Math.max(SEQ_CONST.HEAD_W_MIN, Math.ceil(textWidth(p.name, HEAD_TEXT_SIZE)) + SEQ_CONST.HEAD_PAD_X * 2)
19264
+ );
19265
+ ps.forEach((p, i) => this.colOf.set(p.id, i));
19266
+ const n = ps.length;
19267
+ const gaps = new Array(Math.max(0, n - 1)).fill(SEQ_CONST.LIFELINE_GAP);
19268
+ for (let k = 0; k < gaps.length; k++) {
19269
+ gaps[k] = Math.max(gaps[k], this.headW[k] / 2 + this.headW[k + 1] / 2 + 28);
19270
+ }
19271
+ const msgs = collectMessages(this.ast.statements);
19272
+ for (const m of msgs) {
19273
+ const label = m.label ?? "";
19274
+ const w = textWidth(label, LABEL_SIZE) + SEQ_CONST.LABEL_GAP_PAD;
19275
+ const cf = this.colOf.get(m.from);
19276
+ const ct = this.colOf.get(m.to);
19277
+ if (cf === void 0 && ct === void 0) continue;
19278
+ if (cf === void 0 || ct === void 0) continue;
19279
+ if (cf === ct) {
19280
+ if (cf < gaps.length) gaps[cf] = Math.max(gaps[cf], SEQ_CONST.SELF_LOOP_W + w);
19281
+ continue;
19282
+ }
19283
+ const i = Math.min(cf, ct);
19284
+ const j = Math.max(cf, ct);
19285
+ if (j === i + 1) {
19286
+ gaps[i] = Math.max(gaps[i], w);
19287
+ } else {
19288
+ let span = 0;
19289
+ for (let k = i; k < j; k++) span += gaps[k];
19290
+ if (span < w) {
19291
+ const add = (w - span) / (j - i);
19292
+ for (let k = i; k < j; k++) gaps[k] += add;
19293
+ }
19294
+ }
19295
+ }
19296
+ this.x = new Array(n);
19297
+ let cx = SEQ_CONST.LEFT_MARGIN + (this.headW[0] ?? SEQ_CONST.HEAD_W_MIN) / 2;
19298
+ for (let i = 0; i < n; i++) {
19299
+ this.x[i] = cx;
19300
+ if (i < gaps.length) cx += gaps[i];
19301
+ }
19302
+ ps.forEach((p, i) => {
19303
+ const created = p.createdInline === true;
19304
+ const headY = created ? -1 : SEQ_CONST.TOP_PAD;
19305
+ const ll = {
19306
+ participant: p,
19307
+ index: i,
19308
+ x: this.x[i],
19309
+ headX: this.x[i] - this.headW[i] / 2,
19310
+ headY,
19311
+ headW: this.headW[i],
19312
+ headH: SEQ_CONST.HEAD_H,
19313
+ axisTop: created ? -1 : SEQ_CONST.TOP_PAD + SEQ_CONST.HEAD_H,
19314
+ axisBottom: 0,
19315
+ destroyed: false
19316
+ };
19317
+ this.lifelines.push(ll);
19318
+ this.llById.set(p.id, ll);
19319
+ });
19320
+ }
19321
+ // ── column accounting (for fragment extents) ─────────────────
19322
+ touch(col) {
19323
+ if (col === void 0) return;
19324
+ for (const acc of this.colAccStack) {
19325
+ if (col < acc.min) acc.min = col;
19326
+ if (col > acc.max) acc.max = col;
19327
+ }
19328
+ }
19329
+ noteRight(x, w) {
19330
+ this.contentRight = Math.max(this.contentRight, x + w);
19331
+ }
19332
+ // ── activation bars ──────────────────────────────────────────
19333
+ openBar(id) {
19334
+ const col = this.colOf.get(id);
19335
+ if (col === void 0) return;
19336
+ const stack = this.open.get(id) ?? [];
19337
+ const level = stack.length;
19338
+ const x = this.x[col] - SEQ_CONST.ACT_W / 2 + level * SEQ_CONST.ACT_NEST_DX;
19339
+ stack.push({ x, yTop: this.y, level });
19340
+ this.open.set(id, stack);
19341
+ }
19342
+ closeBar(id) {
19343
+ const stack = this.open.get(id);
19344
+ if (!stack || stack.length === 0) {
19345
+ this.warnings.push(`deactivate '${id}' with no matching activation`);
19346
+ return;
19347
+ }
19348
+ const b = stack.pop();
19349
+ this.activations.push({ id, x: b.x, yTop: b.yTop, yBottom: this.y, level: b.level });
19350
+ }
19351
+ faceEdge(id, col, towardRight, extraLevel = 0) {
19352
+ const stack = this.open.get(id) ?? [];
19353
+ const levels = stack.length + extraLevel;
19354
+ if (levels <= 0) return this.x[col];
19355
+ if (!towardRight) return this.x[col] - SEQ_CONST.ACT_W / 2;
19356
+ return this.x[col] + SEQ_CONST.ACT_W / 2 + (levels - 1) * SEQ_CONST.ACT_NEST_DX;
19357
+ }
19358
+ // ── vertical walk ────────────────────────────────────────────
19359
+ walk(stmts, depth) {
19360
+ for (const s of stmts) {
19361
+ switch (s.kind) {
19362
+ case "message":
19363
+ this.placeMessage(s);
19364
+ break;
19365
+ case "activate":
19366
+ this.y += SEQ_CONST.ACT_STEP;
19367
+ this.openBar(s.id);
19368
+ this.touch(this.colOf.get(s.id));
19369
+ break;
19370
+ case "deactivate":
19371
+ this.y += SEQ_CONST.ACT_STEP;
19372
+ this.closeBar(s.id);
19373
+ this.touch(this.colOf.get(s.id));
19374
+ break;
19375
+ case "note":
19376
+ this.placeNote(s);
19377
+ break;
19378
+ case "ref":
19379
+ this.placeRef(s.ids, s.text);
19380
+ break;
19381
+ case "divider":
19382
+ this.y += SEQ_CONST.DIV_GAP_BEFORE;
19383
+ this.dividers.push({ text: s.text, y: this.y + SEQ_CONST.DIV_H / 2, width: 0 });
19384
+ this.y += SEQ_CONST.DIV_H;
19385
+ break;
19386
+ case "invariant":
19387
+ this.placeInvariant(s.id, s.text);
19388
+ break;
19389
+ case "destroy":
19390
+ this.placeDestroy(s.id);
19391
+ break;
19392
+ case "fragment":
19393
+ this.placeFragment(s.op, s.operands, depth, s.messageSet);
19394
+ break;
19395
+ }
19396
+ }
19397
+ }
19398
+ nextNumber() {
19399
+ if (this.autoCounter === null || !this.ast.autonumber) return void 0;
19400
+ const n = this.autoCounter;
19401
+ this.autoCounter += this.ast.autonumber.step;
19402
+ return n;
19403
+ }
19404
+ placeMessage(m) {
19405
+ this.y += SEQ_CONST.EVENT_GAP;
19406
+ const y = this.y;
19407
+ const cf = this.colOf.get(m.from);
19408
+ const ct = this.colOf.get(m.to);
19409
+ const self = m.from !== "" && m.from === m.to;
19410
+ let x1;
19411
+ let x2;
19412
+ if (m.arrow === "found") {
19413
+ const c = ct;
19414
+ x2 = this.faceEdge(m.to, c, false);
19415
+ x1 = x2 - SEQ_CONST.LOST_LEN;
19416
+ } else if (m.arrow === "lost") {
19417
+ const c = cf;
19418
+ x1 = this.faceEdge(m.from, c, true);
19419
+ x2 = x1 + SEQ_CONST.LOST_LEN;
19420
+ } else if (self) {
19421
+ const c = cf;
19422
+ x1 = this.faceEdge(m.from, c, true);
19423
+ x2 = x1 + SEQ_CONST.SELF_LOOP_W;
19424
+ } else {
19425
+ const fromRight = (ct ?? 0) > (cf ?? 0);
19426
+ x1 = this.faceEdge(m.from, cf, fromRight);
19427
+ if (m.create) {
19428
+ const halfW = this.headW[ct] / 2;
19429
+ x2 = fromRight ? this.x[ct] - halfW : this.x[ct] + halfW;
19430
+ } else {
19431
+ x2 = this.faceEdge(m.to, ct, !fromRight, m.activateTarget ? 1 : 0);
19432
+ }
19433
+ }
19434
+ const row = { message: m, y, x1, x2, self };
19435
+ const num = this.nextNumber();
19436
+ if (num !== void 0) row.number = num;
19437
+ if (self) {
19438
+ row.selfBottomY = y + SEQ_CONST.SELF_GAP;
19439
+ this.y = row.selfBottomY;
19440
+ }
19441
+ this.messages.push(row);
19442
+ this.contentRight = Math.max(this.contentRight, x1, x2);
19443
+ this.touch(cf);
19444
+ this.touch(ct);
19445
+ if (m.create && ct !== void 0) {
19446
+ const ll = this.llById.get(m.to);
19447
+ ll.headY = y - SEQ_CONST.HEAD_H / 2;
19448
+ ll.axisTop = ll.headY + SEQ_CONST.HEAD_H;
19449
+ }
19450
+ if (m.activateTarget && ct !== void 0) this.openBar(m.to);
19451
+ if (m.deactivateSource && cf !== void 0) this.closeBar(m.from);
19452
+ }
19453
+ placeNote(note) {
19454
+ this.y += SEQ_CONST.NOTE_GAP_BEFORE;
19455
+ const lines = note.text.split(/<br\s*\/?>|\\n/);
19456
+ const textW = lines.reduce((mx, l) => Math.max(mx, textWidth(l, LABEL_SIZE)), 0);
19457
+ const w = Math.max(SEQ_CONST.NOTE_MIN_W, Math.ceil(textW) + SEQ_CONST.NOTE_PAD * 2);
19458
+ const h = lines.length * SEQ_CONST.NOTE_LINE_H + SEQ_CONST.NOTE_PAD * 2;
19459
+ const top = this.y;
19460
+ const cols = note.ids.map((id) => this.colOf.get(id)).filter((c) => c !== void 0);
19461
+ cols.forEach((c) => this.touch(c));
19462
+ let x;
19463
+ let boxW = w;
19464
+ if (note.placement === "over" && cols.length >= 2) {
19465
+ const a = this.x[Math.min(...cols)];
19466
+ const b = this.x[Math.max(...cols)];
19467
+ const span = b - a + this.headW[Math.min(...cols)] / 2 + this.headW[Math.max(...cols)] / 2;
19468
+ boxW = Math.max(w, span);
19469
+ x = (a + b) / 2 - boxW / 2;
19470
+ } else if (note.placement === "left" && cols.length) {
19471
+ x = this.x[cols[0]] - SEQ_CONST.NOTE_SIDE_GAP - w;
19472
+ } else if (note.placement === "right" && cols.length) {
19473
+ x = this.x[cols[0]] + SEQ_CONST.NOTE_SIDE_GAP;
19474
+ } else {
19475
+ const c = cols[0] ?? 0;
19476
+ x = this.x[c] - w / 2;
19477
+ }
19478
+ this.notes.push({ note, x, y: top, width: boxW, height: h });
19479
+ this.noteRight(x, boxW);
19480
+ this.y = top + h;
19481
+ }
19482
+ placeRef(ids, text2) {
19483
+ this.y += SEQ_CONST.REF_GAP_BEFORE;
19484
+ const cols = ids.map((id) => this.colOf.get(id)).filter((c) => c !== void 0);
19485
+ cols.forEach((c) => this.touch(c));
19486
+ const minC = cols.length ? Math.min(...cols) : 0;
19487
+ const maxC = cols.length ? Math.max(...cols) : 0;
19488
+ const left = this.x[minC] - SEQ_CONST.FRAG_PAD_X;
19489
+ const right = this.x[maxC] + SEQ_CONST.FRAG_PAD_X;
19490
+ const top = this.y;
19491
+ this.refs.push({ text: text2, x: left, y: top, width: right - left, height: SEQ_CONST.REF_H });
19492
+ this.noteRight(left, right - left);
19493
+ this.y = top + SEQ_CONST.REF_H;
19494
+ }
19495
+ placeInvariant(id, text2) {
19496
+ this.y += SEQ_CONST.INV_GAP_BEFORE;
19497
+ const col = this.colOf.get(id);
19498
+ this.touch(col);
19499
+ const w = Math.ceil(textWidth(text2, LABEL_SIZE)) + SEQ_CONST.INV_PAD * 2;
19500
+ const cx = col !== void 0 ? this.x[col] : SEQ_CONST.LEFT_MARGIN;
19501
+ const top = this.y;
19502
+ this.invariants.push({ text: text2, cx, y: top, width: w, height: SEQ_CONST.INV_H });
19503
+ this.noteRight(cx - w / 2, w);
19504
+ this.y = top + SEQ_CONST.INV_H;
19505
+ }
19506
+ placeDestroy(id) {
19507
+ this.y += SEQ_CONST.EVENT_GAP / 2;
19508
+ const ll = this.llById.get(id);
19509
+ const col = this.colOf.get(id);
19510
+ if (ll && col !== void 0) {
19511
+ ll.destroyed = true;
19512
+ ll.axisBottom = this.y;
19513
+ this.destroys.push({ x: this.x[col], y: this.y });
19514
+ this.touch(col);
19515
+ }
19516
+ }
19517
+ placeFragment(op, operands, depth, messageSet) {
19518
+ const frameTop = this.y + SEQ_CONST.FRAG_GAP_BEFORE;
19519
+ const acc = { min: Number.POSITIVE_INFINITY, max: Number.NEGATIVE_INFINITY };
19520
+ this.colAccStack.push(acc);
19521
+ const operandGeom = [];
19522
+ this.y = frameTop + SEQ_CONST.FRAG_LABEL_H + SEQ_CONST.FRAG_PAD_TOP - SEQ_CONST.EVENT_GAP;
19523
+ const firstGeom = {};
19524
+ if (operands[0]?.guard) firstGeom.guard = operands[0].guard;
19525
+ operandGeom.push(firstGeom);
19526
+ this.walk(operands[0]?.statements ?? [], depth + 1);
19527
+ for (let oi = 1; oi < operands.length; oi++) {
19528
+ const sepY = this.y + SEQ_CONST.FRAG_OPERAND_GAP;
19529
+ const geom = { sepY };
19530
+ if (operands[oi].guard) geom.guard = operands[oi].guard;
19531
+ operandGeom.push(geom);
19532
+ this.y = sepY + SEQ_CONST.FRAG_PAD_TOP - SEQ_CONST.EVENT_GAP;
19533
+ this.walk(operands[oi].statements, depth + 1);
19534
+ }
19535
+ const frameBottom = this.y + SEQ_CONST.FRAG_PAD_BOTTOM;
19536
+ this.colAccStack.pop();
19537
+ let minC = acc.min;
19538
+ let maxC = acc.max;
19539
+ if (!isFinite(minC)) {
19540
+ minC = 0;
19541
+ maxC = Math.max(0, this.lifelines.length - 1);
19542
+ }
19543
+ const inset = depth * SEQ_CONST.FRAG_NEST_INSET;
19544
+ let left = this.x[minC] - SEQ_CONST.FRAG_PAD_X + inset;
19545
+ let right = this.x[maxC] + SEQ_CONST.FRAG_PAD_X - inset;
19546
+ if (right - left < 40) {
19547
+ const mid = (left + right) / 2;
19548
+ left = mid - 20;
19549
+ right = mid + 20;
19550
+ }
19551
+ const frame = {
19552
+ op,
19553
+ x: left,
19554
+ y: frameTop,
19555
+ width: right - left,
19556
+ height: frameBottom - frameTop,
19557
+ operands: operandGeom
19558
+ };
19559
+ if (messageSet && messageSet.length) frame.messageSet = messageSet;
19560
+ this.fragments.push(frame);
19561
+ this.noteRight(left, right - left);
19562
+ this.y = frameBottom;
19563
+ }
19564
+ };
19565
+ function collectMessages(stmts) {
19566
+ const out = [];
19567
+ for (const s of stmts) {
19568
+ if (s.kind === "message") out.push(s);
19569
+ else if (s.kind === "fragment") {
19570
+ for (const op of s.operands) out.push(...collectMessages(op.statements));
19571
+ }
19572
+ }
19573
+ return out;
19574
+ }
19575
+ function layoutSequence(ast) {
19576
+ return new SequenceLayout(ast).run();
19577
+ }
19578
+
19579
+ // src/diagrams/sequence/renderer.ts
19580
+ var HEAD = "#e8f0fb";
19581
+ var HEAD_STROKE = "#5b85c0";
19582
+ function buildCss7(t) {
19583
+ return `
19584
+ .sx-seq { font-family: system-ui, -apple-system, sans-serif; }
19585
+ .sx-seq-axis { stroke: ${t.neutral}; stroke-width: 1; stroke-dasharray: 4 4; }
19586
+ .sx-seq-head rect, .sx-seq-head path { fill: ${HEAD}; stroke: ${HEAD_STROKE}; stroke-width: 1.4; }
19587
+ .sx-seq-head-name { font: 600 12.5px sans-serif; fill: ${t.text}; }
19588
+ .sx-seq-head-stereo { font: italic 10px sans-serif; fill: ${t.textMuted}; }
19589
+ .sx-seq-actor line, .sx-seq-actor circle { stroke: ${t.stroke}; stroke-width: 1.6; fill: none; stroke-linecap: round; }
19590
+ .sx-seq-actor-head { fill: ${t.bg}; }
19591
+ .sx-seq-icon { fill: ${t.bg}; stroke: ${HEAD_STROKE}; stroke-width: 1.6; }
19592
+ .sx-seq-icon-line { stroke: ${HEAD_STROKE}; stroke-width: 1.6; fill: none; stroke-linecap: round; }
19593
+ .sx-seq-icon-fill { fill: ${HEAD_STROKE}; stroke: none; }
19594
+ .sx-seq-act { fill: ${t.bg}; stroke: ${HEAD_STROKE}; stroke-width: 1.2; }
19595
+ .sx-seq-msg { stroke: ${t.stroke}; stroke-width: 1.5; fill: none; }
19596
+ .sx-seq-msg-reply { stroke: ${t.stroke}; stroke-width: 1.4; fill: none; stroke-dasharray: 6 4; }
19597
+ .sx-seq-msg-label { font: 11px sans-serif; fill: ${t.text}; }
19598
+ .sx-seq-msg-num { font: 600 10px sans-serif; fill: ${t.textMuted}; }
19599
+ .sx-seq-endpoint { fill: ${t.stroke}; }
19600
+ .sx-seq-frame { fill: none; stroke: ${t.neutral}; stroke-width: 1.2; }
19601
+ .sx-seq-frame-neg { fill: ${t.negative}; fill-opacity: 0.06; }
19602
+ .sx-seq-frame-sep { stroke: ${t.neutral}; stroke-width: 1; stroke-dasharray: 5 4; }
19603
+ .sx-seq-frame-tab { fill: ${t.fillMuted}; stroke: ${t.neutral}; stroke-width: 1.2; }
19604
+ .sx-seq-frame-op { font: 700 11px sans-serif; fill: ${t.text}; }
19605
+ .sx-seq-guard { font: italic 10.5px sans-serif; fill: ${t.textMuted}; }
19606
+ .sx-seq-ref-name { font: 600 12px sans-serif; fill: ${t.text}; }
19607
+ .sx-seq-note rect { fill: #fdf6da; stroke: #d9c97e; stroke-width: 1.1; }
19608
+ .sx-seq-note path { fill: #efe2a6; stroke: #d9c97e; stroke-width: 1.1; }
19609
+ .sx-seq-note-text { font: 11px sans-serif; fill: ${t.text}; }
19610
+ .sx-seq-div line { stroke: ${t.neutral}; stroke-width: 1; }
19611
+ .sx-seq-div rect { fill: ${t.fillMuted}; stroke: ${t.neutral}; stroke-width: 1; }
19612
+ .sx-seq-div-text { font: 600 11px sans-serif; fill: ${t.textMuted}; }
19613
+ .sx-seq-inv rect { fill: ${t.bg}; stroke: ${t.neutral}; stroke-width: 1.1; }
19614
+ .sx-seq-inv-text { font: italic 10.5px sans-serif; fill: ${t.textMuted}; }
19615
+ .sx-seq-destroy { stroke: ${t.negative}; stroke-width: 2; }
19616
+ .sx-seq-title { font: 700 16px sans-serif; fill: ${t.text}; }
19617
+ `.trim();
19618
+ }
19619
+ function markers3(t) {
19620
+ return defs([
19621
+ el(
19622
+ "marker",
19623
+ { id: "sx-seq-filled", viewBox: "0 0 12 10", refX: 10, refY: 5, markerWidth: 11, markerHeight: 9, orient: "auto" },
19624
+ [el("polygon", { points: "0,0 11,5 0,10", fill: t.stroke })]
19625
+ ),
19626
+ el(
19627
+ "marker",
19628
+ { id: "sx-seq-open", viewBox: "0 0 12 10", refX: 10, refY: 5, markerWidth: 12, markerHeight: 10, orient: "auto" },
19629
+ [el("polyline", { points: "0,0 10,5 0,10", fill: "none", stroke: t.stroke, "stroke-width": 1.5 })]
19630
+ )
19631
+ ]);
19632
+ }
19633
+ var CHAR_W2 = 6;
19634
+ function renderLifeline(ll) {
19635
+ const parts = [];
19636
+ parts.push(line({ class: "sx-seq-axis", x1: ll.x, y1: ll.axisTop, x2: ll.x, y2: ll.axisBottom }));
19637
+ parts.push(renderHead(ll));
19638
+ return group({ class: "sx-seq-lifeline", "data-id": ll.participant.id, "data-kind": ll.participant.kind }, parts);
19639
+ }
19640
+ function renderHead(ll) {
19641
+ const p = ll.participant;
19642
+ const cx = ll.x;
19643
+ const stereo = p.stereotype ? `\xAB${p.stereotype}\xBB` : null;
19644
+ if (p.kind === "actor") {
19645
+ const topY = ll.headY;
19646
+ const fig = [];
19647
+ if (stereo) {
19648
+ fig.push(text({ class: "sx-seq-head-stereo", x: cx, y: topY - 4, "text-anchor": "middle" }, stereo));
19649
+ }
19650
+ fig.push(
19651
+ circle({ class: "sx-seq-actor-head", cx, cy: topY + 6, r: 4.5 }),
19652
+ line({ x1: cx, y1: topY + 10, x2: cx, y2: topY + 22 }),
19653
+ line({ x1: cx - 8, y1: topY + 14, x2: cx + 8, y2: topY + 14 }),
19654
+ line({ x1: cx, y1: topY + 22, x2: cx - 7, y2: topY + 32 }),
19655
+ line({ x1: cx, y1: topY + 22, x2: cx + 7, y2: topY + 32 }),
19656
+ text({ class: "sx-seq-head-name", x: cx, y: topY + 44, "text-anchor": "middle" }, p.name)
19657
+ );
19658
+ return group({ class: "sx-seq-actor sx-seq-head" }, fig);
19659
+ }
19660
+ if (p.kind === "boundary" || p.kind === "control" || p.kind === "entity") {
19661
+ return renderRobustnessIcon(ll, stereo);
19662
+ }
19663
+ if (p.kind === "database") {
19664
+ const w = ll.headW;
19665
+ const h = ll.headH;
19666
+ const x = ll.headX;
19667
+ const y = ll.headY;
19668
+ const ry = 5;
19669
+ const d = `M ${x} ${y + ry} a ${w / 2} ${ry} 0 0 1 ${w} 0 v ${h - 2 * ry} a ${w / 2} ${ry} 0 0 1 ${-w} 0 Z M ${x} ${y + ry} a ${w / 2} ${ry} 0 0 0 ${w} 0`;
19670
+ return group({ class: "sx-seq-head" }, [
19671
+ path({ d }),
19672
+ text({ class: "sx-seq-head-name", x: cx, y: y + h / 2 + 6, "text-anchor": "middle" }, p.name)
19673
+ ]);
19674
+ }
19675
+ const parts = [
19676
+ rect({ x: ll.headX, y: ll.headY, width: ll.headW, height: ll.headH, rx: 3, ry: 3 })
19677
+ ];
19678
+ const stereoText = stereo ?? (p.kind === "collections" || p.kind === "queue" ? `\xAB${p.kind}\xBB` : null);
19679
+ if (stereoText) {
19680
+ parts.push(
19681
+ text({ class: "sx-seq-head-stereo", x: cx, y: ll.headY + 14, "text-anchor": "middle" }, stereoText)
19682
+ );
19683
+ parts.push(
19684
+ text({ class: "sx-seq-head-name", x: cx, y: ll.headY + 28, "text-anchor": "middle" }, p.name)
19685
+ );
19686
+ } else {
19687
+ parts.push(
19688
+ text({ class: "sx-seq-head-name", x: cx, y: ll.headY + ll.headH / 2 + 5, "text-anchor": "middle" }, p.name)
19689
+ );
19690
+ }
19691
+ return group({ class: "sx-seq-head" }, parts);
19692
+ }
19693
+ function renderRobustnessIcon(ll, stereo) {
19694
+ const p = ll.participant;
19695
+ const cx = ll.x;
19696
+ const R = 11;
19697
+ const cy = ll.headY + 14;
19698
+ const parts = [];
19699
+ if (stereo) {
19700
+ parts.push(text({ class: "sx-seq-head-stereo", x: cx, y: ll.headY - 2, "text-anchor": "middle" }, stereo));
19701
+ }
19702
+ parts.push(circle({ class: "sx-seq-icon", cx, cy, r: R }));
19703
+ if (p.kind === "boundary") {
19704
+ const bx = cx - R - 9;
19705
+ parts.push(line({ class: "sx-seq-icon-line", x1: bx, y1: cy - R, x2: bx, y2: cy + R }));
19706
+ parts.push(line({ class: "sx-seq-icon-line", x1: bx, y1: cy, x2: cx - R, y2: cy }));
19707
+ } else if (p.kind === "entity") {
19708
+ parts.push(line({ class: "sx-seq-icon-line", x1: cx - R - 2, y1: cy + R + 1, x2: cx + R + 2, y2: cy + R + 1 }));
19709
+ } else {
19710
+ parts.push(
19711
+ polygon({ class: "sx-seq-icon-fill", points: `${cx - 2},${cy - R - 6} ${cx + 5},${cy - R - 1} ${cx - 3},${cy - R + 2}` })
19712
+ );
19713
+ }
19714
+ parts.push(text({ class: "sx-seq-head-name", x: cx, y: ll.headY + 44, "text-anchor": "middle" }, p.name));
19715
+ return group({ class: "sx-seq-head sx-seq-icon-head", "data-icon": p.kind }, parts);
19716
+ }
19717
+ function renderActivation(a) {
19718
+ const h = Math.max(6, a.yBottom - a.yTop);
19719
+ return rect({
19720
+ class: "sx-seq-act",
19721
+ "data-id": a.id,
19722
+ x: a.x,
19723
+ y: a.yTop,
19724
+ width: 10,
19725
+ height: h
19726
+ });
19727
+ }
19728
+ function renderMessage(m) {
19729
+ const k = m.message.arrow;
19730
+ const lineClass2 = k === "reply" ? "sx-seq-msg-reply" : "sx-seq-msg";
19731
+ const markerEnd = k === "async" || k === "reply" ? "url(#sx-seq-open)" : "url(#sx-seq-filled)";
19732
+ const parts = [];
19733
+ if (m.self) {
19734
+ const bottom = m.selfBottomY ?? m.y + 28;
19735
+ const right = m.x2;
19736
+ const d = `M ${m.x1} ${m.y} H ${right} V ${bottom} H ${m.x1}`;
19737
+ parts.push(path({ class: lineClass2, d, "marker-end": markerEnd }));
19738
+ if (m.message.label) {
19739
+ parts.push(
19740
+ text(
19741
+ { class: "sx-seq-msg-label", x: right + 6, y: (m.y + bottom) / 2 + 3 },
19742
+ numbered(m, m.message.label)
19743
+ )
19744
+ );
19745
+ }
19746
+ } else {
19747
+ parts.push(line({ class: lineClass2, x1: m.x1, y1: m.y, x2: m.x2, y2: m.y, "marker-end": markerEnd }));
19748
+ if (k === "lost") parts.push(circle({ class: "sx-seq-endpoint", cx: m.x2, cy: m.y, r: 4 }));
19749
+ if (k === "found") parts.push(circle({ class: "sx-seq-endpoint", cx: m.x1, cy: m.y, r: 4 }));
19750
+ if (m.message.label) {
19751
+ const mid = (m.x1 + m.x2) / 2;
19752
+ parts.push(
19753
+ text(
19754
+ { class: "sx-seq-msg-label", x: mid, y: m.y - 6, "text-anchor": "middle" },
19755
+ numbered(m, m.message.label)
19756
+ )
19757
+ );
19758
+ }
19759
+ }
19760
+ return group(
19761
+ {
19762
+ class: "sx-seq-message",
19763
+ "data-kind": k,
19764
+ "data-from": m.message.from,
19765
+ "data-to": m.message.to
19766
+ },
19767
+ parts
19768
+ );
19769
+ }
19770
+ function numbered(m, label) {
19771
+ return m.number !== void 0 ? `${m.number}. ${label}` : label;
19772
+ }
19773
+ function tabWidth(f) {
19774
+ return Math.max(40, f.op.length * 8 + 22);
19775
+ }
19776
+ function renderFragmentBox(f) {
19777
+ const frameClass = f.op === "neg" ? "sx-seq-frame sx-seq-frame-neg" : "sx-seq-frame";
19778
+ const parts = [
19779
+ rect({ class: frameClass, x: f.x, y: f.y, width: f.width, height: f.height, rx: 2, ry: 2 })
19780
+ ];
19781
+ for (const op of f.operands) {
19782
+ if (op.sepY !== void 0) {
19783
+ parts.push(line({ class: "sx-seq-frame-sep", x1: f.x, y1: op.sepY, x2: f.x + f.width, y2: op.sepY }));
19784
+ }
19785
+ }
19786
+ return group({ class: "sx-seq-fragment", "data-op": f.op }, parts);
19787
+ }
19788
+ function renderFragmentTab(f) {
19789
+ const tabW = tabWidth(f);
19790
+ const tabH = 18;
19791
+ const fold = 6;
19792
+ const tx = f.x;
19793
+ const ty = f.y;
19794
+ const tab = `M ${tx} ${ty} H ${tx + tabW} V ${ty + tabH - fold} L ${tx + tabW - fold} ${ty + tabH} H ${tx} Z`;
19795
+ const parts = [
19796
+ path({ class: "sx-seq-frame-tab", d: tab }),
19797
+ text({ class: "sx-seq-frame-op", x: tx + 8, y: ty + 13 }, f.op)
19798
+ ];
19799
+ if (f.messageSet && f.messageSet.length) {
19800
+ parts.push(
19801
+ text({ class: "sx-seq-guard", x: tx + tabW + 8, y: ty + 13 }, `{${f.messageSet.join(", ")}}`)
19802
+ );
19803
+ }
19804
+ f.operands.forEach((op, i) => {
19805
+ if (!op.guard) return;
19806
+ const gx = i === 0 ? f.x + tabW + 8 : f.x + 8;
19807
+ const gy = i === 0 ? f.y + 13 : (op.sepY ?? f.y) + 14;
19808
+ parts.push(text({ class: "sx-seq-guard", x: gx, y: gy }, `[${op.guard}]`));
19809
+ });
19810
+ return group({ class: "sx-seq-fragment-tab-g", "data-op": f.op }, parts);
19811
+ }
19812
+ function renderRef(r) {
19813
+ const tabW = 40;
19814
+ const tabH = 18;
19815
+ const fold = 6;
19816
+ const tab = `M ${r.x} ${r.y} H ${r.x + tabW} V ${r.y + tabH - fold} L ${r.x + tabW - fold} ${r.y + tabH} H ${r.x} Z`;
19817
+ return group({ class: "sx-seq-fragment", "data-op": "ref" }, [
19818
+ rect({ class: "sx-seq-frame", x: r.x, y: r.y, width: r.width, height: r.height, rx: 2, ry: 2 }),
19819
+ path({ class: "sx-seq-frame-tab", d: tab }),
19820
+ text({ class: "sx-seq-frame-op", x: r.x + 8, y: r.y + 13 }, "ref"),
19821
+ text(
19822
+ { class: "sx-seq-ref-name", x: r.x + r.width / 2, y: r.y + r.height / 2 + 8, "text-anchor": "middle" },
19823
+ r.text
19824
+ )
19825
+ ]);
19826
+ }
19827
+ function renderNote2(nb) {
19828
+ const fold = 8;
19829
+ const x = nb.x;
19830
+ const y = nb.y;
19831
+ const w = nb.width;
19832
+ const h = nb.height;
19833
+ const body = `M ${x} ${y} H ${x + w - fold} L ${x + w} ${y + fold} V ${y + h} H ${x} Z`;
19834
+ const corner = `M ${x + w - fold} ${y} V ${y + fold} H ${x + w} Z`;
19835
+ const lines = nb.note.text.split(/<br\s*\/?>|\\n/);
19836
+ const startY = y + h / 2 - (lines.length - 1) * 15 / 2 + 4;
19837
+ const texts = lines.map(
19838
+ (l, i) => text({ class: "sx-seq-note-text", x: x + w / 2, y: startY + i * 15, "text-anchor": "middle" }, l)
19839
+ );
19840
+ return group({ class: "sx-seq-note" }, [path({ d: body }), path({ d: corner }), ...texts]);
19841
+ }
19842
+ function renderDivider(d) {
19843
+ const labelW = Math.max(60, d.text.length * CHAR_W2 + 24);
19844
+ const cx = d.width / 2;
19845
+ const parts = [
19846
+ line({ x1: 8, y1: d.y, x2: cx - labelW / 2, y2: d.y }),
19847
+ line({ x1: cx + labelW / 2, y1: d.y, x2: d.width - 8, y2: d.y }),
19848
+ rect({ x: cx - labelW / 2, y: d.y - 11, width: labelW, height: 22, rx: 4, ry: 4 }),
19849
+ text({ class: "sx-seq-div-text", x: cx, y: d.y + 4, "text-anchor": "middle" }, d.text)
19850
+ ];
19851
+ return group({ class: "sx-seq-div" }, parts);
19852
+ }
19853
+ function renderInvariant(iv) {
19854
+ return group({ class: "sx-seq-inv" }, [
19855
+ rect({ x: iv.cx - iv.width / 2, y: iv.y, width: iv.width, height: iv.height, rx: iv.height / 2, ry: iv.height / 2 }),
19856
+ text({ class: "sx-seq-inv-text", x: iv.cx, y: iv.y + iv.height / 2 + 4, "text-anchor": "middle" }, `{${iv.text}}`)
19857
+ ]);
19858
+ }
19859
+ function renderDestroy(d) {
19860
+ const r = 7;
19861
+ return group({ class: "sx-seq-destroy-g" }, [
19862
+ line({ class: "sx-seq-destroy", x1: d.x - r, y1: d.y - r, x2: d.x + r, y2: d.y + r }),
19863
+ line({ class: "sx-seq-destroy", x1: d.x - r, y1: d.y + r, x2: d.x + r, y2: d.y - r })
19864
+ ]);
19865
+ }
19866
+ function renderSequenceLayout(layout, config) {
19867
+ const t = resolveBaseTheme(config?.theme ?? "default");
19868
+ const children = [];
19869
+ const nMsg = layout.messages.length;
19870
+ const nFrag = layout.fragments.length;
19871
+ children.push(title(`Sequence Diagram${layout.title ? " \u2014 " + layout.title : ""}`));
19872
+ children.push(
19873
+ desc(
19874
+ `${layout.lifelines.length} participants, ${nMsg} messages, ${nFrag} combined fragments.`
19875
+ )
19876
+ );
19877
+ children.push(el("style", {}, buildCss7(t)));
19878
+ children.push(markers3(t));
19879
+ const titleBand = layout.title ? 32 : 0;
19880
+ if (layout.title) {
19881
+ children.push(
19882
+ text({ x: layout.width / 2, y: 22, class: "sx-seq-title", "text-anchor": "middle" }, layout.title)
19883
+ );
19884
+ }
19885
+ const body = [];
19886
+ body.push(group({ class: "sx-seq-lifelines" }, layout.lifelines.map(renderLifeline)));
19887
+ body.push(group({ class: "sx-seq-frames" }, layout.fragments.map(renderFragmentBox)));
19888
+ body.push(group({ class: "sx-seq-acts" }, layout.activations.map(renderActivation)));
19889
+ body.push(group({ class: "sx-seq-frame-tabs" }, layout.fragments.map(renderFragmentTab)));
19890
+ body.push(group({ class: "sx-seq-refs" }, layout.refs.map(renderRef)));
19891
+ body.push(group({ class: "sx-seq-messages" }, layout.messages.map(renderMessage)));
19892
+ body.push(group({ class: "sx-seq-notes" }, layout.notes.map(renderNote2)));
19893
+ body.push(group({ class: "sx-seq-divs" }, layout.dividers.map(renderDivider)));
19894
+ body.push(group({ class: "sx-seq-invs" }, layout.invariants.map(renderInvariant)));
19895
+ body.push(group({ class: "sx-seq-destroys" }, layout.destroys.map(renderDestroy)));
19896
+ children.push(
19897
+ titleBand ? group({ transform: `translate(0, ${titleBand})` }, body) : group({}, body)
19898
+ );
19899
+ const height = layout.height + titleBand;
19900
+ return svgRoot(
19901
+ {
19902
+ class: "sx-seq",
19903
+ role: "img",
19904
+ "aria-label": escapeXml(layout.title ?? "UML sequence diagram"),
19905
+ width: layout.width,
19906
+ height,
19907
+ viewBox: `0 0 ${layout.width} ${height}`,
19908
+ "data-diagram-type": "sequence"
19909
+ },
19910
+ children
19911
+ );
19912
+ }
19913
+ function renderSequence(textOrAst, config) {
19914
+ const ast = typeof textOrAst === "string" ? parseSequence(textOrAst) : textOrAst;
19915
+ const layout = layoutSequence(ast);
19916
+ return renderSequenceLayout(layout, config);
19917
+ }
19918
+
19919
+ // src/diagrams/sequence/index.ts
19920
+ var sequence = {
19921
+ type: "sequence",
19922
+ detect(text2) {
19923
+ for (const raw of text2.split(/\r?\n/)) {
19924
+ const t = raw.trim();
19925
+ if (!t) continue;
19926
+ if (t.startsWith("#") || t.startsWith("//")) continue;
19927
+ return /^sequence\b/i.test(t);
19928
+ }
19929
+ return false;
19930
+ },
19931
+ parse: parseSequence,
19932
+ render(text2, config) {
19933
+ return renderSequence(text2, config);
19934
+ }
19935
+ };
19936
+
18616
19937
  // src/core/api.ts
18617
19938
  var plugins = [
18618
19939
  genogram,
@@ -18644,7 +19965,8 @@ var plugins = [
18644
19965
  sfc,
18645
19966
  prisma,
18646
19967
  usecase,
18647
- pert
19968
+ pert,
19969
+ sequence
18648
19970
  ];
18649
19971
  function detectPlugin(text2, config) {
18650
19972
  if (config?.type) {
@@ -18655,7 +19977,7 @@ function detectPlugin(text2, config) {
18655
19977
  if (plugin.detect(text2)) return plugin;
18656
19978
  }
18657
19979
  throw new Error(
18658
- "Cannot detect diagram type. Start your text with 'genogram', 'ecomap', 'pedigree', 'phylo', 'sociogram', 'timing', 'logic', 'circuit', 'blockdiagram', 'ladder', 'sld', 'entity-structure', 'fishbone', 'venn', 'flowchart', 'mindmap', 'matrix', 'orgchart', 'state', 'pid', 'erd', 'breadboard', 'bpmn', 'fbd', 'sfc', 'prisma', 'usecase', or 'pert'."
19980
+ "Cannot detect diagram type. Start your text with 'genogram', 'ecomap', 'pedigree', 'phylo', 'sociogram', 'timing', 'logic', 'circuit', 'blockdiagram', 'ladder', 'sld', 'entity-structure', 'fishbone', 'venn', 'flowchart', 'mindmap', 'matrix', 'orgchart', 'state', 'pid', 'erd', 'breadboard', 'bpmn', 'fbd', 'sfc', 'prisma', 'usecase', 'pert', or 'sequence'."
18659
19981
  );
18660
19982
  }
18661
19983
  function preprocess8(text2) {
@@ -18680,9 +20002,68 @@ function parse(text2, config) {
18680
20002
  `Diagram type '${plugin.type}' does not yet expose a parse() method.`
18681
20003
  );
18682
20004
  }
20005
+ function parseResult(text2, config) {
20006
+ let plugin;
20007
+ try {
20008
+ const prepared = preprocess8(text2);
20009
+ plugin = detectPlugin(prepared, config);
20010
+ if (!plugin.parse) {
20011
+ throw new Error(
20012
+ `Diagram type '${plugin.type}' does not yet expose a parse() method.`
20013
+ );
20014
+ }
20015
+ return {
20016
+ ok: true,
20017
+ status: "valid",
20018
+ type: plugin.type,
20019
+ ast: plugin.parse(prepared),
20020
+ diagnostics: []
20021
+ };
20022
+ } catch (err) {
20023
+ return {
20024
+ ok: false,
20025
+ status: "invalid",
20026
+ type: plugin?.type ?? config?.type ?? null,
20027
+ diagnostics: [diagnosticFromError(err)]
20028
+ };
20029
+ }
20030
+ }
18683
20031
  function render(text2, config) {
20032
+ if (config?.mode === "preview") return renderResult(text2, config).svg;
18684
20033
  const prepared = preprocess8(text2);
18685
20034
  const plugin = detectPlugin(prepared, config);
20035
+ return renderWithPlugin(prepared, plugin, config);
20036
+ }
20037
+ function renderResult(text2, config) {
20038
+ let plugin;
20039
+ try {
20040
+ const prepared = preprocess8(text2);
20041
+ plugin = detectPlugin(prepared, config);
20042
+ return {
20043
+ ok: true,
20044
+ status: "valid",
20045
+ type: plugin.type,
20046
+ svg: renderWithPlugin(prepared, plugin, config),
20047
+ diagnostics: []
20048
+ };
20049
+ } catch (err) {
20050
+ const type = plugin?.type ?? config?.type ?? null;
20051
+ const diagnostics = [diagnosticFromError(err)];
20052
+ return {
20053
+ ok: false,
20054
+ status: "invalid",
20055
+ type,
20056
+ svg: renderDiagnosticSvg(diagnostics, type, {
20057
+ fontFamily: config?.fontFamily
20058
+ }),
20059
+ diagnostics
20060
+ };
20061
+ }
20062
+ }
20063
+ function renderPreview(text2, config) {
20064
+ return renderResult(text2, config).svg;
20065
+ }
20066
+ function renderWithPlugin(prepared, plugin, config) {
18686
20067
  const renderConfig = {
18687
20068
  fontFamily: config?.fontFamily ?? "system-ui, -apple-system, sans-serif",
18688
20069
  fontSize: 12,
@@ -18692,6 +20073,6 @@ function render(text2, config) {
18692
20073
  return plugin.render(prepared, renderConfig);
18693
20074
  }
18694
20075
 
18695
- export { decisiontree, parse, pert, pid, prisma, render, state, timeline, usecase };
18696
- //# sourceMappingURL=chunk-GTDQAN2Z.js.map
18697
- //# sourceMappingURL=chunk-GTDQAN2Z.js.map
20076
+ export { decisiontree, parse, parseResult, pert, pid, prisma, render, renderPreview, renderResult, state, timeline, usecase };
20077
+ //# sourceMappingURL=chunk-OK5ZS3LU.js.map
20078
+ //# sourceMappingURL=chunk-OK5ZS3LU.js.map