@pixerate/editor 0.55.0 → 0.56.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/dist/agent/index.cjs +18 -17
  2. package/dist/agent/index.cjs.map +1 -1
  3. package/dist/agent/index.js +3 -2
  4. package/dist/agent/index.js.map +1 -1
  5. package/dist/canvas/index.cjs +2105 -172
  6. package/dist/canvas/index.cjs.map +1 -1
  7. package/dist/canvas/index.d.cts +319 -23
  8. package/dist/canvas/index.d.ts +319 -23
  9. package/dist/canvas/index.js +2081 -148
  10. package/dist/canvas/index.js.map +1 -1
  11. package/dist/chart/index.cjs +32 -30
  12. package/dist/chart/index.cjs.map +1 -1
  13. package/dist/chart/index.d.cts +4 -2
  14. package/dist/chart/index.d.ts +4 -2
  15. package/dist/chart/index.js +20 -18
  16. package/dist/chart/index.js.map +1 -1
  17. package/dist/{chunk-C3JHII3M.cjs → chunk-3I6V7PI4.cjs} +45 -45
  18. package/dist/{chunk-C3JHII3M.cjs.map → chunk-3I6V7PI4.cjs.map} +1 -1
  19. package/dist/{chunk-P43HUQRX.cjs → chunk-AHCENCU4.cjs} +12 -10
  20. package/dist/chunk-AHCENCU4.cjs.map +1 -0
  21. package/dist/chunk-II77MLHN.cjs +11106 -0
  22. package/dist/chunk-II77MLHN.cjs.map +1 -0
  23. package/dist/{chunk-OIKYP7XC.js → chunk-LMUDHBWR.js} +2 -2
  24. package/dist/{chunk-VODBAO32.js → chunk-OEFCLWZ3.js} +4 -1425
  25. package/dist/chunk-OEFCLWZ3.js.map +1 -0
  26. package/dist/{chunk-NK3WL5TJ.cjs → chunk-P2CTDJNF.cjs} +27 -1448
  27. package/dist/chunk-P2CTDJNF.cjs.map +1 -0
  28. package/dist/chunk-TKPPIVW7.cjs +1443 -0
  29. package/dist/chunk-TKPPIVW7.cjs.map +1 -0
  30. package/dist/chunk-WJSCGBJ2.js +11106 -0
  31. package/dist/chunk-WJSCGBJ2.js.map +1 -0
  32. package/dist/{chunk-RIXTW3C4.js → chunk-WLVZ235X.js} +5 -3
  33. package/dist/{chunk-RIXTW3C4.js.map → chunk-WLVZ235X.js.map} +1 -1
  34. package/dist/chunk-ZOH6X3VR.js +1443 -0
  35. package/dist/chunk-ZOH6X3VR.js.map +1 -0
  36. package/dist/{controller-DscWQbjO.d.ts → controller-D2rj5umx.d.ts} +2 -362
  37. package/dist/{controller-CX0QfSv0.d.cts → controller-R2biKk_E.d.cts} +2 -362
  38. package/dist/diagram/index.cjs +1457 -47
  39. package/dist/diagram/index.cjs.map +1 -1
  40. package/dist/diagram/index.d.cts +1734 -15
  41. package/dist/diagram/index.d.ts +1734 -15
  42. package/dist/diagram/index.js +1436 -26
  43. package/dist/diagram/index.js.map +1 -1
  44. package/dist/extensions/index.cjs +5 -4
  45. package/dist/extensions/index.cjs.map +1 -1
  46. package/dist/extensions/index.d.cts +4 -3
  47. package/dist/extensions/index.d.ts +4 -3
  48. package/dist/extensions/index.js +4 -3
  49. package/dist/{index-DIWB6xMf.d.cts → index-BcHyG0Wq.d.cts} +2 -1
  50. package/dist/{index-CALDD35B.d.ts → index-CTCc3m3C.d.ts} +2 -1
  51. package/dist/index.cjs +10 -9
  52. package/dist/index.cjs.map +1 -1
  53. package/dist/index.d.cts +4 -3
  54. package/dist/index.d.ts +4 -3
  55. package/dist/index.js +4 -3
  56. package/dist/index.js.map +1 -1
  57. package/dist/types-BRp-6zkY.d.cts +362 -0
  58. package/dist/types-BRp-6zkY.d.ts +362 -0
  59. package/dist/{types-BULrFyuQ.d.cts → types-DYkjhzdz.d.cts} +1 -1
  60. package/dist/{types-BULrFyuQ.d.ts → types-DYkjhzdz.d.ts} +1 -1
  61. package/package.json +1 -1
  62. package/dist/chunk-H5K77C7Y.cjs +0 -3848
  63. package/dist/chunk-H5K77C7Y.cjs.map +0 -1
  64. package/dist/chunk-NK3WL5TJ.cjs.map +0 -1
  65. package/dist/chunk-P43HUQRX.cjs.map +0 -1
  66. package/dist/chunk-VODBAO32.js.map +0 -1
  67. package/dist/chunk-WWJNC7SX.js +0 -3848
  68. package/dist/chunk-WWJNC7SX.js.map +0 -1
  69. /package/dist/{chunk-OIKYP7XC.js.map → chunk-LMUDHBWR.js.map} +0 -0
@@ -1,3848 +0,0 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/diagram/source/lines.ts
2
- var HEADER_PATTERNS = [
3
- [/^\s*(flowchart|graph)(?:-elk)?\b/i, "flowchart"],
4
- [/^\s*stateDiagram(?:-v2)?\b/i, "state"],
5
- [/^\s*classDiagram(?:-v2)?\b/i, "class"],
6
- [/^\s*erDiagram\b/i, "er"],
7
- [/^\s*requirementDiagram\b/i, "requirement"],
8
- [/^\s*mindmap\b/i, "mindmap"],
9
- [/^\s*sequenceDiagram\b/i, "sequence"],
10
- [/^\s*gantt\b/i, "gantt"],
11
- [/^\s*pie\b/i, "pie"],
12
- [/^\s*journey\b/i, "journey"],
13
- [/^\s*timeline\b/i, "timeline"],
14
- [/^\s*gitGraph\b/i, "gitGraph"],
15
- [/^\s*C4(Context|Container|Component|Dynamic|Deployment)\b/, "c4"],
16
- [/^\s*quadrantChart\b/i, "quadrant"],
17
- [/^\s*sankey(?:-beta)?\b/i, "sankey"],
18
- [/^\s*xychart(?:-beta)?\b/i, "xychart"],
19
- [/^\s*block(?:-beta)?\b/i, "block"],
20
- [/^\s*architecture(?:-beta)?\b/i, "architecture"],
21
- [/^\s*packet(?:-beta)?\b/i, "packet"],
22
- [/^\s*kanban\b/i, "kanban"],
23
- [/^\s*radar(?:-beta)?\b/i, "radar"],
24
- [/^\s*treemap(?:-beta)?\b/i, "treemap"],
25
- [/^\s*info\b/i, "info"]
26
- ];
27
- function detectFamilyFromHeader(header) {
28
- for (const [re, family] of HEADER_PATTERNS) {
29
- if (re.test(header)) return family;
30
- }
31
- return "unknown";
32
- }
33
- function isCommentLine(line) {
34
- const t = line.trim();
35
- return t.startsWith("%%") && !t.startsWith("%%{");
36
- }
37
- function isDirectiveLine(line) {
38
- return /^\s*%%\{.*\}%%\s*$/.test(line);
39
- }
40
- function splitSource(source) {
41
- const eol = source.includes("\r\n") ? "\r\n" : "\n";
42
- const rawLines = source.split(/\r\n|\n/);
43
- let end = rawLines.length;
44
- while (end > 0 && rawLines[end - 1].trim() === "") end--;
45
- const trailingLines = rawLines.slice(end);
46
- const trailing = trailingLines.length ? eol + trailingLines.join(eol) : "";
47
- const lines = rawLines.slice(0, end);
48
- const preambleLines = [];
49
- let i = 0;
50
- let frontmatter;
51
- if (lines[0] !== void 0 && /^---\s*$/.test(lines[0])) {
52
- preambleLines.push(lines[0]);
53
- i = 1;
54
- const fm = [];
55
- while (i < lines.length && !/^---\s*$/.test(lines[i])) {
56
- fm.push(lines[i]);
57
- preambleLines.push(lines[i]);
58
- i++;
59
- }
60
- if (i < lines.length) {
61
- preambleLines.push(lines[i]);
62
- i++;
63
- }
64
- frontmatter = parseSimpleYaml(fm);
65
- }
66
- while (i < lines.length) {
67
- const line = lines[i];
68
- if (line.trim() === "" || isDirectiveLine(line) || isCommentLine(line)) {
69
- preambleLines.push(line);
70
- i++;
71
- continue;
72
- }
73
- break;
74
- }
75
- const headerIndex = i;
76
- const header = _nullishCoalesce(lines[i], () => ( ""));
77
- const bodyLines = lines.slice(i + 1);
78
- return {
79
- eol,
80
- preamble: { lines: preambleLines, frontmatter },
81
- header,
82
- headerIndex,
83
- bodyLines,
84
- trailing
85
- };
86
- }
87
- function parseSimpleYaml(lines) {
88
- const out = {};
89
- let currentKey = null;
90
- let nested = null;
91
- for (const raw of lines) {
92
- if (raw.trim() === "" || raw.trim().startsWith("#")) continue;
93
- const indent = raw.length - raw.trimStart().length;
94
- const m = /^([A-Za-z_][\w-]*)\s*:\s*(.*)$/.exec(raw.trim());
95
- if (!m) continue;
96
- const [, key, valueRaw] = m;
97
- const value = parseYamlScalar(valueRaw);
98
- if (indent === 0) {
99
- currentKey = key;
100
- if (valueRaw.trim() === "") {
101
- nested = {};
102
- out[key] = nested;
103
- } else {
104
- nested = null;
105
- out[key] = value;
106
- }
107
- } else if (nested && currentKey) {
108
- nested[key] = value;
109
- }
110
- }
111
- return out;
112
- }
113
- function parseYamlScalar(v) {
114
- const t = v.trim();
115
- if (t === "") return "";
116
- if (t.startsWith("{") || t.startsWith("[")) {
117
- try {
118
- return JSON.parse(t);
119
- } catch (e2) {
120
- return t;
121
- }
122
- }
123
- if (/^(true|false)$/i.test(t)) return t.toLowerCase() === "true";
124
- if (/^-?\d+(\.\d+)?$/.test(t)) return Number(t);
125
- if (t.startsWith('"') && t.endsWith('"') || t.startsWith("'") && t.endsWith("'")) {
126
- return t.slice(1, -1);
127
- }
128
- return t;
129
- }
130
- function splitStatements(line) {
131
- const parts = [];
132
- let depth = 0;
133
- let quote = null;
134
- let cur = "";
135
- for (let i = 0; i < line.length; i++) {
136
- const ch = line[i];
137
- if (quote) {
138
- cur += ch;
139
- if (ch === quote) quote = null;
140
- continue;
141
- }
142
- if (ch === '"' || ch === "`") {
143
- quote = ch;
144
- cur += ch;
145
- continue;
146
- }
147
- if (ch === "[" || ch === "(" || ch === "{") depth++;
148
- else if (ch === "]" || ch === ")" || ch === "}") depth = Math.max(0, depth - 1);
149
- if (ch === ";" && depth === 0) {
150
- parts.push(cur);
151
- cur = "";
152
- continue;
153
- }
154
- cur += ch;
155
- }
156
- parts.push(cur);
157
- return parts;
158
- }
159
-
160
- // src/diagram/source/metadata.ts
161
- var META_COMMENT_PREFIX = "%% @pixerate ";
162
- var META_FRONTMATTER_KEY = "pixerate";
163
- var LEGACY_FRONTMATTER_KEY = "ursula";
164
- var META_LINE = /^\s*%%\s*@(?:pixerate|ursula)\s+(\{.*\})\s*$/;
165
- var LEGACY_LAYOUT_LINE = /^\s*%%\s*@layout\b\s*(.*?)\s*$/;
166
- function emptyMeta() {
167
- return { v: 1 };
168
- }
169
- function extractMetaFromBody(bodyLines) {
170
- let meta = null;
171
- let legacy = null;
172
- const rest = [];
173
- for (const line of bodyLines) {
174
- const m = META_LINE.exec(line);
175
- if (m) {
176
- const parsed = safeParseMeta(m[1]);
177
- if (parsed) meta = mergeMeta(_nullishCoalesce(meta, () => ( emptyMeta())), parsed);
178
- continue;
179
- }
180
- const lm = LEGACY_LAYOUT_LINE.exec(line);
181
- if (lm) {
182
- const parsed = safeParseMeta(`{"layout":${lm[1] || "null"}}`);
183
- if (parsed) legacy = mergeMeta(_nullishCoalesce(legacy, () => ( emptyMeta())), parsed);
184
- continue;
185
- }
186
- rest.push(line);
187
- }
188
- if (legacy) meta = meta ? mergeMeta(legacy, meta) : legacy;
189
- return { bodyLines: rest, meta };
190
- }
191
- function extractMetaFromFrontmatter(preamble) {
192
- const value = _nullishCoalesce(_optionalChain([preamble, 'access', _ => _.frontmatter, 'optionalAccess', _2 => _2[META_FRONTMATTER_KEY]]), () => ( _optionalChain([preamble, 'access', _3 => _3.frontmatter, 'optionalAccess', _4 => _4[LEGACY_FRONTMATTER_KEY]])));
193
- if (!value) return null;
194
- if (typeof value === "string") return safeParseMeta(value);
195
- if (typeof value === "object") return normaliseMeta(value);
196
- return null;
197
- }
198
- function safeParseMeta(json) {
199
- try {
200
- const value = JSON.parse(json);
201
- return normaliseMeta(value);
202
- } catch (e3) {
203
- return null;
204
- }
205
- }
206
- function normaliseMeta(value) {
207
- const meta = { v: 1 };
208
- if (value.layout && typeof value.layout === "object") {
209
- const layout = {};
210
- for (const [id, pos] of Object.entries(value.layout)) {
211
- if (Array.isArray(pos) && pos.length === 2 && pos.every((n) => typeof n === "number")) {
212
- layout[id] = [pos[0], pos[1]];
213
- }
214
- }
215
- meta.layout = layout;
216
- }
217
- if (value.sizes && typeof value.sizes === "object") {
218
- const sizes = {};
219
- for (const [id, size] of Object.entries(value.sizes)) {
220
- if (Array.isArray(size) && size.length === 2 && size.every((n) => typeof n === "number")) {
221
- sizes[id] = [size[0], size[1]];
222
- }
223
- }
224
- meta.sizes = sizes;
225
- }
226
- if (value.viewport && typeof value.viewport === "object") {
227
- const vp = value.viewport;
228
- if (typeof vp.x === "number" && typeof vp.y === "number" && typeof vp.zoom === "number") {
229
- meta.viewport = { x: vp.x, y: vp.y, zoom: vp.zoom };
230
- }
231
- }
232
- if (value.ext && typeof value.ext === "object") meta.ext = value.ext;
233
- return meta;
234
- }
235
- function mergeMeta(a, b) {
236
- return {
237
- v: 1,
238
- layout: a.layout || b.layout ? { ...a.layout, ...b.layout } : void 0,
239
- sizes: a.sizes || b.sizes ? { ...a.sizes, ...b.sizes } : void 0,
240
- viewport: _nullishCoalesce(b.viewport, () => ( a.viewport)),
241
- ext: a.ext || b.ext ? { ...a.ext, ...b.ext } : void 0
242
- };
243
- }
244
- function isMetaEmpty(meta) {
245
- const hasLayout = !!meta.layout && Object.keys(meta.layout).length > 0;
246
- const hasSizes = !!meta.sizes && Object.keys(meta.sizes).length > 0;
247
- const hasExt = !!meta.ext && Object.keys(meta.ext).length > 0;
248
- return !hasLayout && !hasSizes && !meta.viewport && !hasExt;
249
- }
250
- function serializeMeta(meta) {
251
- const out = { v: 1 };
252
- if (meta.layout && Object.keys(meta.layout).length) {
253
- const layout = {};
254
- for (const id of Object.keys(meta.layout).sort()) {
255
- const [x, y] = meta.layout[id];
256
- layout[id] = [Math.round(x), Math.round(y)];
257
- }
258
- out.layout = layout;
259
- }
260
- if (meta.sizes && Object.keys(meta.sizes).length) {
261
- const sizes = {};
262
- for (const id of Object.keys(meta.sizes).sort()) {
263
- const [w, h] = meta.sizes[id];
264
- sizes[id] = [Math.round(w), Math.round(h)];
265
- }
266
- out.sizes = sizes;
267
- }
268
- if (meta.viewport) {
269
- out.viewport = {
270
- x: Math.round(meta.viewport.x),
271
- y: Math.round(meta.viewport.y),
272
- zoom: Math.round(meta.viewport.zoom * 1e3) / 1e3
273
- };
274
- }
275
- if (meta.ext && Object.keys(meta.ext).length) out.ext = meta.ext;
276
- return JSON.stringify(out);
277
- }
278
- function metaCommentLine(meta, indent = " ") {
279
- return `${indent}${META_COMMENT_PREFIX}${serializeMeta(meta)}`;
280
- }
281
- function writeMetaToPreamble(preamble, meta) {
282
- const lines = [...preamble.lines];
283
- const hasFm = lines[0] !== void 0 && /^---\s*$/.test(lines[0]);
284
- const entry = meta && !isMetaEmpty(meta) ? `${META_FRONTMATTER_KEY}: ${serializeMeta(meta)}` : null;
285
- if (!hasFm) {
286
- if (!entry) return lines;
287
- return ["---", entry, "---", ...lines];
288
- }
289
- const close = lines.findIndex((l, i) => i > 0 && /^---\s*$/.test(l));
290
- const fmEnd = close === -1 ? lines.length : close;
291
- const existing = lines.findIndex(
292
- (l, i) => i > 0 && i < fmEnd && new RegExp(`^(?:${META_FRONTMATTER_KEY}|${LEGACY_FRONTMATTER_KEY})\\s*:`).test(l)
293
- );
294
- if (existing !== -1) {
295
- if (entry) lines[existing] = entry;
296
- else lines.splice(existing, 1);
297
- } else if (entry) {
298
- lines.splice(fmEnd, 0, entry);
299
- }
300
- if (!entry) {
301
- const close2 = lines.findIndex((l, i) => i > 0 && /^---\s*$/.test(l));
302
- if (close2 === 1) lines.splice(0, 2);
303
- }
304
- return lines;
305
- }
306
- var FRONTMATTER_META_FAMILIES = /* @__PURE__ */ new Set(["requirement"]);
307
- function defaultCarrierFor(family) {
308
- return FRONTMATTER_META_FAMILIES.has(family) ? "frontmatter" : "comment";
309
- }
310
-
311
- // src/diagram/flowchart/edges.ts
312
- var START_HEADS = {
313
- "<": "arrow_point",
314
- x: "arrow_cross",
315
- o: "arrow_circle"
316
- };
317
- var END_HEADS = {
318
- ">": "arrow_point",
319
- x: "arrow_cross",
320
- o: "arrow_circle"
321
- };
322
- var EDGE_ID = /^([A-Za-z0-9_À-￿-]+)@(?=[<xo]?[-=~.])/;
323
- var PLAIN = /^([<xo](?=[-=~]))?(-{2,}|={2,}|-\.+-|~{3,})([>xo])?/;
324
- var TEXT_OPEN = /^([<xo](?=[-=]))?(--|-\.|==)(?=\s)/;
325
- var TEXT_CLOSE = /\s+(-{2,}|\.+-|={2,})([>xo])?(?=$|\s|\||[A-Za-z0-9_À-￿([{>"`&])/;
326
- function patternOf(body) {
327
- if (body.startsWith("~")) return "invisible";
328
- if (body.startsWith("=")) return "thick";
329
- if (body.includes(".")) return "dotted";
330
- return "solid";
331
- }
332
- function lengthOf(body, hasEndHead) {
333
- if (body.startsWith("~")) return Math.max(1, body.length - 2);
334
- if (body.includes(".")) return Math.max(1, (_nullishCoalesce(body.match(/\./g), () => ( []))).length);
335
- return Math.max(1, body.length - (hasEndHead ? 1 : 2));
336
- }
337
- function closerLength(closer, hasEndHead) {
338
- if (closer.includes(".")) return Math.max(1, (_nullishCoalesce(closer.match(/\./g), () => ( []))).length);
339
- return Math.max(1, closer.length - (hasEndHead ? 1 : 2));
340
- }
341
- function parseLink(input) {
342
- let pos = 0;
343
- let id;
344
- const idm = EDGE_ID.exec(input);
345
- if (idm) {
346
- id = idm[1];
347
- pos += idm[0].length;
348
- }
349
- const rest = input.slice(pos);
350
- const tm = TEXT_OPEN.exec(rest);
351
- if (tm) {
352
- const afterOpen = rest.slice(tm[0].length);
353
- const cm = TEXT_CLOSE.exec(afterOpen);
354
- if (cm && cm.index > 0) {
355
- const label = afterOpen.slice(0, cm.index).trim();
356
- if (label && !/^[-=.>|]/.test(label)) {
357
- const closer = cm[1];
358
- const endHead2 = cm[2];
359
- const consumed2 = pos + tm[0].length + cm.index + cm[0].length;
360
- const body2 = tm[2];
361
- const result2 = {
362
- id,
363
- pattern: patternOf(body2 === "-." ? "-.-" : body2),
364
- arrowStart: tm[1] ? START_HEADS[tm[1]] : "none",
365
- arrowEnd: endHead2 ? END_HEADS[endHead2] : "none",
366
- length: closerLength(closer, !!endHead2),
367
- label: unquoteLabel(label),
368
- labelStyle: "inline",
369
- consumed: consumed2,
370
- raw: input.slice(0, consumed2)
371
- };
372
- return withPipeLabel(input, result2);
373
- }
374
- }
375
- }
376
- const pm = PLAIN.exec(rest);
377
- if (!pm) return null;
378
- const body = pm[2];
379
- const endHead = pm[3];
380
- const consumed = pos + pm[0].length;
381
- const result = {
382
- id,
383
- pattern: patternOf(body),
384
- arrowStart: pm[1] ? START_HEADS[pm[1]] : "none",
385
- arrowEnd: endHead ? END_HEADS[endHead] : "none",
386
- length: lengthOf(body, !!endHead),
387
- consumed,
388
- raw: input.slice(0, consumed)
389
- };
390
- return withPipeLabel(input, result);
391
- }
392
- function withPipeLabel(input, link) {
393
- const after = input.slice(link.consumed);
394
- const m = _nullishCoalesce(/^\s*\|(\s*"[^"]*"\s*)\|/.exec(after), () => ( /^\s*\|([^|]*)\|/.exec(after)));
395
- if (!m) return link;
396
- const consumed = link.consumed + m[0].length;
397
- return {
398
- ...link,
399
- label: unquoteLabel(m[1].trim()),
400
- labelStyle: link.label ? link.labelStyle : "pipe",
401
- consumed,
402
- raw: input.slice(0, consumed)
403
- };
404
- }
405
- function unquoteLabel(text) {
406
- const t = text.trim();
407
- if (t.length >= 2 && t.startsWith('"') && t.endsWith('"')) return t.slice(1, -1);
408
- return t;
409
- }
410
- var NEEDS_QUOTE = /[[\]{}()|<>"#;&%]|^\s|\s$|^-|^=|^\./;
411
- function quoteLabelIfNeeded(label) {
412
- if (label === "") return '""';
413
- if (label.startsWith("`") && label.endsWith("`")) return `"${label}"`;
414
- if (NEEDS_QUOTE.test(label)) {
415
- return `"${label.replace(/"/g, "#quot;")}"`;
416
- }
417
- return label;
418
- }
419
- var START_CHAR = {
420
- arrow_point: "<",
421
- arrow_cross: "x",
422
- arrow_circle: "o"
423
- };
424
- var END_CHAR = {
425
- arrow_point: ">",
426
- arrow_cross: "x",
427
- arrow_circle: "o"
428
- };
429
- function formatLink(spec) {
430
- const start = _nullishCoalesce(START_CHAR[spec.arrowStart], () => ( ""));
431
- const end = _nullishCoalesce(END_CHAR[spec.arrowEnd], () => ( ""));
432
- const len = Math.max(1, spec.length);
433
- const label = _optionalChain([spec, 'access', _5 => _5.label, 'optionalAccess', _6 => _6.trim, 'call', _7 => _7()]);
434
- const body = (closing) => {
435
- switch (spec.pattern) {
436
- case "invisible":
437
- return "~".repeat(len + 2);
438
- case "thick":
439
- return "=".repeat(end ? len + 1 : len + 2);
440
- case "dotted":
441
- return closing ? `${".".repeat(len)}-` : `-${".".repeat(len)}-`;
442
- default:
443
- return "-".repeat(end ? len + 1 : len + 2);
444
- }
445
- };
446
- const prefix = spec.id ? `${spec.id}@` : "";
447
- if (label && spec.labelStyle === "inline" && spec.pattern !== "invisible") {
448
- const open = spec.pattern === "thick" ? "==" : spec.pattern === "dotted" ? "-." : "--";
449
- return `${prefix}${start}${open} ${quoteLabelIfNeeded(label)} ${body(true)}${end}`;
450
- }
451
- const token = `${prefix}${start}${body(false)}${end}`;
452
- if (label) return `${token}|${quoteLabelIfNeeded(label)}|`;
453
- return token;
454
- }
455
-
456
- // src/diagram/flowchart/shapes.ts
457
- var FLOWCHART_SHAPES = [
458
- {
459
- name: "rect",
460
- title: "Rectangle",
461
- aliases: ["rectangle", "proc", "process", "squareRect", "square"],
462
- bracket: { open: "[", close: "]" },
463
- category: "basic"
464
- },
465
- {
466
- name: "rounded",
467
- title: "Rounded rectangle",
468
- aliases: ["rounded-rectangle", "event", "roundedRect", "round"],
469
- bracket: { open: "(", close: ")" },
470
- category: "basic"
471
- },
472
- {
473
- name: "stadium",
474
- title: "Stadium",
475
- aliases: ["pill", "terminal"],
476
- bracket: { open: "([", close: "])" },
477
- category: "basic"
478
- },
479
- {
480
- name: "subproc",
481
- title: "Subprocess",
482
- aliases: ["subprocess", "subroutine", "framed-rectangle", "fr-rect"],
483
- bracket: { open: "[[", close: "]]" },
484
- category: "process"
485
- },
486
- {
487
- name: "cyl",
488
- title: "Cylinder (database)",
489
- aliases: ["cylinder", "database", "db"],
490
- bracket: { open: "[(", close: ")]" },
491
- category: "data"
492
- },
493
- {
494
- name: "circle",
495
- title: "Circle",
496
- aliases: ["circ"],
497
- bracket: { open: "((", close: "))" },
498
- category: "basic"
499
- },
500
- {
501
- name: "odd",
502
- title: "Asymmetric",
503
- aliases: ["asymmetric", "rect_left_inv_arrow"],
504
- bracket: { open: ">", close: "]" },
505
- category: "misc"
506
- },
507
- {
508
- name: "diam",
509
- title: "Diamond (decision)",
510
- aliases: ["diamond", "decision", "question"],
511
- bracket: { open: "{", close: "}" },
512
- category: "control"
513
- },
514
- {
515
- name: "hex",
516
- title: "Hexagon (prepare)",
517
- aliases: ["hexagon", "prepare"],
518
- bracket: { open: "{{", close: "}}" },
519
- category: "process"
520
- },
521
- {
522
- name: "lean-r",
523
- title: "Parallelogram (lean right)",
524
- aliases: ["lean-right", "in-out", "lean_right"],
525
- bracket: { open: "[/", close: "/]" },
526
- category: "data"
527
- },
528
- {
529
- name: "lean-l",
530
- title: "Parallelogram (lean left)",
531
- aliases: ["lean-left", "out-in", "lean_left"],
532
- bracket: { open: "[\\", close: "\\]" },
533
- category: "data"
534
- },
535
- {
536
- name: "trap-b",
537
- title: "Trapezoid (base bottom)",
538
- aliases: ["trapezoid-bottom", "priority", "trapezoid"],
539
- bracket: { open: "[/", close: "\\]" },
540
- category: "process"
541
- },
542
- {
543
- name: "trap-t",
544
- title: "Trapezoid (base top)",
545
- aliases: ["trapezoid-top", "manual", "inv_trapezoid"],
546
- bracket: { open: "[\\", close: "/]" },
547
- category: "process"
548
- },
549
- {
550
- name: "dbl-circ",
551
- title: "Double circle",
552
- aliases: ["double-circle", "doublecircle"],
553
- bracket: { open: "(((", close: ")))" },
554
- category: "basic"
555
- },
556
- // Data-syntax-only shapes
557
- { name: "text", title: "Text", aliases: [], category: "misc" },
558
- {
559
- name: "card",
560
- title: "Card (notched rectangle)",
561
- aliases: ["notched-rectangle", "notch-rect"],
562
- category: "misc"
563
- },
564
- {
565
- name: "lin-rect",
566
- title: "Lined rectangle (shaded process)",
567
- aliases: ["lined-rectangle", "lin-proc", "lined-process", "shaded-process"],
568
- category: "process"
569
- },
570
- {
571
- name: "sm-circ",
572
- title: "Small circle (start)",
573
- aliases: ["small-circle", "start"],
574
- category: "control"
575
- },
576
- {
577
- name: "fr-circ",
578
- title: "Framed circle (stop)",
579
- aliases: ["framed-circle", "stop"],
580
- category: "control"
581
- },
582
- { name: "fork", title: "Fork / join", aliases: ["join"], category: "control" },
583
- { name: "hourglass", title: "Hourglass (collate)", aliases: ["collate"], category: "process" },
584
- {
585
- name: "brace",
586
- title: "Comment (left brace)",
587
- aliases: ["brace-l", "comment"],
588
- category: "misc"
589
- },
590
- { name: "brace-r", title: "Comment (right brace)", aliases: [], category: "misc" },
591
- { name: "braces", title: "Comment (both braces)", aliases: [], category: "misc" },
592
- {
593
- name: "bolt",
594
- title: "Lightning bolt (com link)",
595
- aliases: ["com-link", "lightning-bolt"],
596
- category: "misc"
597
- },
598
- { name: "doc", title: "Document", aliases: ["document"], category: "data" },
599
- {
600
- name: "delay",
601
- title: "Delay (half-rounded rectangle)",
602
- aliases: ["half-rounded-rectangle"],
603
- category: "process"
604
- },
605
- {
606
- name: "h-cyl",
607
- title: "Horizontal cylinder (direct access)",
608
- aliases: ["das", "horizontal-cylinder"],
609
- category: "data"
610
- },
611
- {
612
- name: "lin-cyl",
613
- title: "Lined cylinder (disk storage)",
614
- aliases: ["disk", "lined-cylinder"],
615
- category: "data"
616
- },
617
- {
618
- name: "curv-trap",
619
- title: "Curved trapezoid (display)",
620
- aliases: ["curved-trapezoid", "display"],
621
- category: "misc"
622
- },
623
- {
624
- name: "div-rect",
625
- title: "Divided rectangle",
626
- aliases: ["div-proc", "divided-process", "divided-rectangle"],
627
- category: "process"
628
- },
629
- {
630
- name: "tri",
631
- title: "Triangle (extract)",
632
- aliases: ["extract", "triangle"],
633
- category: "process"
634
- },
635
- {
636
- name: "win-pane",
637
- title: "Window pane (internal storage)",
638
- aliases: ["internal-storage", "window-pane"],
639
- category: "data"
640
- },
641
- {
642
- name: "f-circ",
643
- title: "Filled circle (junction)",
644
- aliases: ["filled-circle", "junction"],
645
- category: "control"
646
- },
647
- { name: "lin-doc", title: "Lined document", aliases: ["lined-document"], category: "data" },
648
- { name: "notch-rect", title: "Notched rectangle (card)", aliases: [], category: "misc" },
649
- { name: "flag", title: "Flag (paper tape)", aliases: ["paper-tape"], category: "data" },
650
- {
651
- name: "docs",
652
- title: "Stacked documents",
653
- aliases: ["documents", "st-doc", "stacked-document"],
654
- category: "data"
655
- },
656
- {
657
- name: "st-rect",
658
- title: "Stacked rectangles",
659
- aliases: ["processes", "procs", "stacked-rectangle"],
660
- category: "process"
661
- },
662
- {
663
- name: "bow-rect",
664
- title: "Bow-tie rectangle (stored data)",
665
- aliases: ["bow-tie-rectangle", "stored-data"],
666
- category: "data"
667
- },
668
- {
669
- name: "cross-circ",
670
- title: "Crossed circle (summary)",
671
- aliases: ["crossed-circle", "summary"],
672
- category: "process"
673
- },
674
- { name: "tag-doc", title: "Tagged document", aliases: ["tagged-document"], category: "data" },
675
- {
676
- name: "tag-rect",
677
- title: "Tagged rectangle",
678
- aliases: ["tag-proc", "tagged-process", "tagged-rectangle"],
679
- category: "process"
680
- },
681
- {
682
- name: "notch-pent",
683
- title: "Notched pentagon (loop limit)",
684
- aliases: ["loop-limit", "notched-pentagon"],
685
- category: "control"
686
- },
687
- {
688
- name: "flip-tri",
689
- title: "Flipped triangle (manual file)",
690
- aliases: ["flipped-triangle", "manual-file"],
691
- category: "data"
692
- },
693
- {
694
- name: "sl-rect",
695
- title: "Sloped rectangle (manual input)",
696
- aliases: ["manual-input", "sloped-rectangle"],
697
- category: "data"
698
- },
699
- { name: "icon", title: "Icon", aliases: [], category: "misc" },
700
- { name: "image", title: "Image", aliases: ["img"], category: "misc" },
701
- { name: "anchor", title: "Anchor (invisible)", aliases: [], category: "misc" }
702
- ];
703
- var BY_NAME = /* @__PURE__ */ new Map();
704
- for (const def of FLOWCHART_SHAPES) {
705
- BY_NAME.set(def.name, def);
706
- for (const alias of def.aliases) BY_NAME.set(alias, def);
707
- }
708
- function resolveShape(name) {
709
- if (!name) return void 0;
710
- return _nullishCoalesce(BY_NAME.get(name), () => ( BY_NAME.get(name.toLowerCase())));
711
- }
712
- function canonicalShape(name) {
713
- if (!name) return "rect";
714
- return _nullishCoalesce(_optionalChain([resolveShape, 'call', _8 => _8(name), 'optionalAccess', _9 => _9.name]), () => ( name));
715
- }
716
- var BRACKET_OPENERS = Array.from(
717
- new Set(FLOWCHART_SHAPES.filter((s) => s.bracket).map((s) => s.bracket.open))
718
- ).sort((a, b) => b.length - a.length);
719
- function closersFor(open) {
720
- return FLOWCHART_SHAPES.filter((s) => _optionalChain([s, 'access', _10 => _10.bracket, 'optionalAccess', _11 => _11.open]) === open).map((s) => s.bracket.close).sort((a, b) => b.length - a.length);
721
- }
722
- function shapeForBracket(open, close) {
723
- return FLOWCHART_SHAPES.find((s) => _optionalChain([s, 'access', _12 => _12.bracket, 'optionalAccess', _13 => _13.open]) === open && s.bracket.close === close);
724
- }
725
- var DEFAULT_SHAPE = "rect";
726
-
727
- // src/diagram/flowchart/statements.ts
728
- function readId(input, pos) {
729
- let i = pos;
730
- while (i < input.length) {
731
- const ch = input[i];
732
- const next = input[i + 1];
733
- if (/[A-Za-z0-9_À-￿!#$%*+?/\\'`]/.test(ch)) {
734
- i++;
735
- continue;
736
- }
737
- if (ch === "." && next !== "-") {
738
- i++;
739
- continue;
740
- }
741
- if (ch === "-" && next !== ">" && next !== "-" && next !== "." && next !== void 0 && !/\s/.test(next)) {
742
- i++;
743
- continue;
744
- }
745
- if (ch === "=" && next !== "=") {
746
- i++;
747
- continue;
748
- }
749
- break;
750
- }
751
- return input.slice(pos, i);
752
- }
753
- function findCloser(input, pos, closers) {
754
- let quote = null;
755
- for (let i = pos; i < input.length; i++) {
756
- const ch = input[i];
757
- if (quote) {
758
- if (ch === quote) quote = null;
759
- continue;
760
- }
761
- if (ch === '"') {
762
- quote = ch;
763
- continue;
764
- }
765
- for (const closer of closers) {
766
- if (input.startsWith(closer, i)) return { index: i, closer };
767
- }
768
- }
769
- return null;
770
- }
771
- function readBraceBlock(input, pos) {
772
- let depth = 0;
773
- let quote = null;
774
- for (let i = pos; i < input.length; i++) {
775
- const ch = input[i];
776
- if (quote) {
777
- if (ch === quote) quote = null;
778
- continue;
779
- }
780
- if (ch === '"' || ch === "'") {
781
- quote = ch;
782
- continue;
783
- }
784
- if (ch === "{") depth++;
785
- else if (ch === "}") {
786
- depth--;
787
- if (depth === 0) return i + 1;
788
- }
789
- }
790
- return -1;
791
- }
792
- function parseShapeData(inner) {
793
- const out = {};
794
- const parts = [];
795
- let cur = "";
796
- let quote = null;
797
- for (const ch of inner) {
798
- if (quote) {
799
- cur += ch;
800
- if (ch === quote) quote = null;
801
- continue;
802
- }
803
- if (ch === '"' || ch === "'") {
804
- quote = ch;
805
- cur += ch;
806
- continue;
807
- }
808
- if (ch === "," || ch === "\n") {
809
- parts.push(cur);
810
- cur = "";
811
- continue;
812
- }
813
- cur += ch;
814
- }
815
- parts.push(cur);
816
- for (const part of parts) {
817
- const m = /^\s*([A-Za-z_][\w-]*)\s*:\s*([\s\S]*?)\s*$/.exec(part);
818
- if (m) out[m[1]] = m[2];
819
- }
820
- return out;
821
- }
822
- function unquoteData(value) {
823
- if (value === void 0) return void 0;
824
- const t = value.trim();
825
- if (t.startsWith('"') && t.endsWith('"') || t.startsWith("'") && t.endsWith("'")) {
826
- return t.slice(1, -1);
827
- }
828
- return t;
829
- }
830
- function formatShapeData(data) {
831
- const entries = Object.entries(data).map(([k, v]) => `${k}: ${v}`);
832
- return `@{ ${entries.join(", ")} }`;
833
- }
834
- function readNode(input, pos) {
835
- const id = readId(input, pos);
836
- if (!id) return null;
837
- let i = pos + id.length;
838
- const node = { id, classes: [] };
839
- if (input[i] === "@" && input[i + 1] === "{") {
840
- const end = readBraceBlock(input, i + 1);
841
- if (end !== -1) {
842
- const inner = input.slice(i + 2, end - 1);
843
- const data = parseShapeData(inner);
844
- node.form = "data";
845
- if (data.shape !== void 0) {
846
- node.shape = canonicalShape(unquoteData(data.shape));
847
- delete data.shape;
848
- }
849
- if (data.label !== void 0) {
850
- node.label = unquoteData(data.label);
851
- node.labelQuoted = /^\s*["']/.test(data.label);
852
- delete data.label;
853
- }
854
- if ("img" in data) node.shape = "image";
855
- else if ("icon" in data && node.shape === void 0) node.shape = "icon";
856
- node.data = data;
857
- i = end;
858
- }
859
- } else {
860
- for (const open of BRACKET_OPENERS) {
861
- if (!input.startsWith(open, i)) continue;
862
- const closers = closersFor(open);
863
- const found = findCloser(input, i + open.length, closers);
864
- if (!found) break;
865
- const shapeDef = shapeForBracket(open, found.closer);
866
- if (!shapeDef) break;
867
- const rawLabel = input.slice(i + open.length, found.index);
868
- node.shape = shapeDef.name;
869
- node.form = "bracket";
870
- node.label = unquoteLabel(rawLabel);
871
- node.labelQuoted = rawLabel.trim().startsWith('"');
872
- i = found.index + found.closer.length;
873
- break;
874
- }
875
- }
876
- while (input.startsWith(":::", i)) {
877
- const cls = readId(input, i + 3);
878
- if (!cls) break;
879
- node.classes.push(cls);
880
- i += 3 + cls.length;
881
- }
882
- return { node, end: i };
883
- }
884
- function skipWs(input, pos) {
885
- let i = pos;
886
- while (i < input.length && /\s/.test(input[i])) i++;
887
- return i;
888
- }
889
- function parseChain(text) {
890
- const groups = [];
891
- const links = [];
892
- let pos = skipWs(text, 0);
893
- let group = [];
894
- const first = readNode(text, pos);
895
- if (!first) return null;
896
- group.push(first.node);
897
- pos = skipWs(text, first.end);
898
- while (pos < text.length) {
899
- if (text[pos] === "&") {
900
- pos = skipWs(text, pos + 1);
901
- const n = readNode(text, pos);
902
- if (!n) return null;
903
- group.push(n.node);
904
- pos = skipWs(text, n.end);
905
- continue;
906
- }
907
- const link = parseLink(text.slice(pos));
908
- if (link) {
909
- groups.push(group);
910
- group = [];
911
- links.push({
912
- id: link.id,
913
- pattern: link.pattern,
914
- arrowStart: link.arrowStart,
915
- arrowEnd: link.arrowEnd,
916
- length: link.length,
917
- label: link.label,
918
- labelStyle: link.labelStyle
919
- });
920
- pos = skipWs(text, pos + link.consumed);
921
- const n = readNode(text, pos);
922
- if (!n) return null;
923
- group.push(n.node);
924
- pos = skipWs(text, n.end);
925
- continue;
926
- }
927
- return null;
928
- }
929
- groups.push(group);
930
- return { groups, links };
931
- }
932
- function splitStyles(text) {
933
- return text.split(",").map((s) => s.trim()).filter(Boolean);
934
- }
935
- function parseStatement(line) {
936
- const indent = line.match(/^\s*/)[0];
937
- const text = line.trim();
938
- if (text === "" || text.startsWith("%%")) return { kind: "raw", raw: line };
939
- let m;
940
- if (/^end\s*$/i.test(text)) return { kind: "end", raw: line, indent };
941
- if (m = /^direction\s+(TB|TD|BT|LR|RL)\s*$/i.exec(text)) {
942
- return { kind: "direction", raw: line, indent, direction: m[1].toUpperCase() };
943
- }
944
- if (m = /^subgraph\s+(.*)$/i.exec(text)) {
945
- const rest = m[1].trim();
946
- let sm;
947
- if (sm = /^([^\s["]+)\s*\[(.*)\]\s*$/.exec(rest)) {
948
- return {
949
- kind: "subgraph",
950
- raw: line,
951
- indent,
952
- id: sm[1],
953
- title: unquoteLabel(sm[2]),
954
- titleForm: "bracket"
955
- };
956
- }
957
- if (sm = /^"(.*)"\s*$/.exec(rest)) {
958
- return { kind: "subgraph", raw: line, indent, id: sm[1], title: sm[1], titleForm: "bare" };
959
- }
960
- if (/\s/.test(rest)) {
961
- return { kind: "subgraph", raw: line, indent, id: rest, title: rest, titleForm: "bare" };
962
- }
963
- return { kind: "subgraph", raw: line, indent, id: rest, titleForm: "none" };
964
- }
965
- if (m = /^classDef\s+([^\s]+)\s+(.*)$/.exec(text)) {
966
- return {
967
- kind: "classDef",
968
- raw: line,
969
- indent,
970
- names: m[1].split(","),
971
- styles: splitStyles(m[2])
972
- };
973
- }
974
- if (m = /^class\s+([^\s]+)\s+([^\s]+)\s*$/.exec(text)) {
975
- return { kind: "class", raw: line, indent, ids: m[1].split(","), className: m[2] };
976
- }
977
- if (m = /^style\s+([^\s]+)\s+(.*)$/.exec(text)) {
978
- return { kind: "style", raw: line, indent, id: m[1], styles: splitStyles(m[2]) };
979
- }
980
- if (m = /^linkStyle\s+(default|[\d,\s]+)\s+(.*)$/.exec(text)) {
981
- const targets = m[1] === "default" ? "default" : m[1].split(",").map((s) => Number.parseInt(s.trim(), 10)).filter((n) => !Number.isNaN(n));
982
- return { kind: "linkStyle", raw: line, indent, targets, styles: splitStyles(m[2]) };
983
- }
984
- if (m = /^click\s+([^\s]+)\s+(.*)$/.exec(text)) {
985
- return { kind: "click", raw: line, indent, id: m[1], rest: m[2] };
986
- }
987
- if (/^(accTitle|accDescr)\b/.test(text) || /^title\s/.test(text))
988
- return { kind: "raw", raw: line };
989
- const chain = parseChain(text);
990
- if (chain) return { kind: "chain", raw: line, indent, chain };
991
- return { kind: "raw", raw: line };
992
- }
993
- function formatNode(node) {
994
- let out = node.id;
995
- const shape = node.shape ? resolveShape(node.shape) : void 0;
996
- const useData = node.form === "data" || node.shape && !_optionalChain([shape, 'optionalAccess', _14 => _14.bracket]) || node.data && Object.keys(node.data).length;
997
- if (useData && (node.shape || node.label !== void 0 || node.data && Object.keys(node.data).length)) {
998
- const data = {};
999
- const implied = node.shape === "image" && node.data && "img" in node.data || node.shape === "icon" && node.data && "icon" in node.data;
1000
- if (node.shape && !implied) data.shape = node.shape;
1001
- if (node.label !== void 0) data.label = JSON.stringify(node.label);
1002
- Object.assign(data, _nullishCoalesce(node.data, () => ( {})));
1003
- out += formatShapeData(data);
1004
- } else if (_optionalChain([shape, 'optionalAccess', _15 => _15.bracket]) && (node.label !== void 0 || node.shape !== "rect" || node.form === "bracket")) {
1005
- const label = _nullishCoalesce(node.label, () => ( node.id));
1006
- const text = node.labelQuoted ? `"${label.replace(/"/g, "#quot;")}"` : quoteLabelIfNeeded(label);
1007
- out += `${shape.bracket.open}${text}${shape.bracket.close}`;
1008
- } else if (node.label !== void 0 && node.label !== node.id) {
1009
- out += `[${quoteLabelIfNeeded(node.label)}]`;
1010
- }
1011
- for (const cls of node.classes) out += `:::${cls}`;
1012
- return out;
1013
- }
1014
- function formatChain(chain) {
1015
- const parts = [];
1016
- chain.groups.forEach((group, i) => {
1017
- parts.push(group.map(formatNode).join(" & "));
1018
- const link = chain.links[i];
1019
- if (link) parts.push(formatLink(link));
1020
- });
1021
- return parts.join(" ");
1022
- }
1023
- function formatStatement(stmt) {
1024
- if (stmt.kind === "raw" || stmt.kind === "end") return stmt.raw;
1025
- if (!stmt.dirty) return stmt.raw;
1026
- switch (stmt.kind) {
1027
- case "chain":
1028
- return stmt.indent + formatChain(stmt.chain);
1029
- case "subgraph": {
1030
- if (stmt.titleForm === "none" || stmt.title === void 0)
1031
- return `${stmt.indent}subgraph ${stmt.id}`;
1032
- if (stmt.titleForm === "bare")
1033
- return `${stmt.indent}subgraph ${stmt.title.includes(" ") || stmt.title !== stmt.id ? `"${stmt.title}"` : stmt.title}`;
1034
- return `${stmt.indent}subgraph ${stmt.id} [${quoteLabelIfNeeded(stmt.title)}]`;
1035
- }
1036
- case "direction":
1037
- return `${stmt.indent}direction ${stmt.direction}`;
1038
- case "classDef":
1039
- return `${stmt.indent}classDef ${stmt.names.join(",")} ${stmt.styles.join(",")}`;
1040
- case "class":
1041
- return `${stmt.indent}class ${stmt.ids.join(",")} ${stmt.className}`;
1042
- case "style":
1043
- return `${stmt.indent}style ${stmt.id} ${stmt.styles.join(",")}`;
1044
- case "linkStyle":
1045
- return `${stmt.indent}linkStyle ${stmt.targets === "default" ? "default" : stmt.targets.join(",")} ${stmt.styles.join(",")}`;
1046
- case "click":
1047
- return `${stmt.indent}click ${stmt.id} ${stmt.rest}`;
1048
- }
1049
- }
1050
- function joinLogicalLines(lines) {
1051
- const out = [];
1052
- let i = 0;
1053
- while (i < lines.length) {
1054
- let cur = lines[i];
1055
- const at = cur.indexOf("@{");
1056
- if (at !== -1 && readBraceBlock(cur, at + 1) === -1) {
1057
- let j = i + 1;
1058
- while (j < lines.length) {
1059
- cur += "\n" + lines[j];
1060
- j++;
1061
- if (readBraceBlock(cur, at + 1) !== -1) break;
1062
- }
1063
- out.push(cur);
1064
- i = j;
1065
- continue;
1066
- }
1067
- out.push(cur);
1068
- i++;
1069
- }
1070
- return out;
1071
- }
1072
-
1073
- // src/diagram/flowchart/parse.ts
1074
- function autoEdgeId(source, target, ordinal) {
1075
- return `L_${source}_${target}_${ordinal}`;
1076
- }
1077
- var HEADER_DIRECTION = /^\s*(?:flowchart|graph)(?:-elk)?\s*(TB|TD|BT|LR|RL)?\s*;?\s*$/i;
1078
- function headerDirection(header) {
1079
- const m = HEADER_DIRECTION.exec(header);
1080
- return (_nullishCoalesce(_optionalChain([m, 'optionalAccess', _16 => _16[1]]), () => ( "TB"))).toUpperCase();
1081
- }
1082
- function tokenizeBody(bodyLines) {
1083
- const statements = [];
1084
- for (const logical of joinLogicalLines(bodyLines)) {
1085
- if (logical.includes("@{") || !logical.includes(";")) {
1086
- statements.push(parseStatement(logical));
1087
- continue;
1088
- }
1089
- const segments = splitStatements(logical);
1090
- const nonEmpty = segments.filter((s) => s.trim() !== "");
1091
- if (nonEmpty.length <= 1) {
1092
- const stmt = parseStatement(_nullishCoalesce(nonEmpty[0], () => ( logical)));
1093
- stmt.raw = logical;
1094
- statements.push(stmt);
1095
- continue;
1096
- }
1097
- const parsed = nonEmpty.map((seg, i) => parseStatement(i === 0 ? seg : seg.trimStart()));
1098
- statements.push(...withCompoundMarker(parsed, logical));
1099
- }
1100
- return statements;
1101
- }
1102
- var COMPOUND = /* @__PURE__ */ Symbol("compound");
1103
- function withCompoundMarker(parsed, raw) {
1104
- parsed.forEach((stmt, i) => markCompound(stmt, parsed, i === 0 ? raw : ""));
1105
- return parsed;
1106
- }
1107
- function markCompound(stmt, members, raw) {
1108
- stmt[COMPOUND] = { members, raw };
1109
- }
1110
- function compoundInfo(stmt) {
1111
- return stmt[COMPOUND];
1112
- }
1113
- function buildGraph(statements, direction, title) {
1114
- const nodes = /* @__PURE__ */ new Map();
1115
- const groups = /* @__PURE__ */ new Map();
1116
- const edges = [];
1117
- const classDefs = {};
1118
- const diagnostics = [];
1119
- const stack = [];
1120
- const membership = /* @__PURE__ */ new Map();
1121
- const classAssignments = [];
1122
- const styleAssignments = [];
1123
- const clicks = [];
1124
- const linkStyles = [];
1125
- const dataOnly = [];
1126
- let ordinal = 0;
1127
- const touch = (ref) => {
1128
- let node = nodes.get(ref.id);
1129
- if (!node) {
1130
- node = { id: ref.id, label: ref.id, shape: DEFAULT_SHAPE, classes: [], styles: [] };
1131
- nodes.set(ref.id, node);
1132
- }
1133
- if (ref.label !== void 0) node.label = ref.label;
1134
- if (ref.shape) node.shape = ref.shape;
1135
- for (const cls of ref.classes) if (!node.classes.includes(cls)) node.classes.push(cls);
1136
- if (ref.data && Object.keys(ref.data).length) {
1137
- node.data = { ..._nullishCoalesce(node.data, () => ( {})), ...stripQuotes(ref.data) };
1138
- }
1139
- const current = stack[stack.length - 1];
1140
- if (current) membership.get(current).add(ref.id);
1141
- return node;
1142
- };
1143
- statements.forEach((stmt, index) => {
1144
- switch (stmt.kind) {
1145
- case "subgraph": {
1146
- const parent = stack[stack.length - 1];
1147
- if (groups.has(stmt.id)) {
1148
- diagnostics.push({
1149
- severity: "warning",
1150
- message: `Duplicate subgraph id "${stmt.id}"`,
1151
- line: index + 1,
1152
- source: "pixerate"
1153
- });
1154
- }
1155
- groups.set(stmt.id, {
1156
- id: stmt.id,
1157
- label: _nullishCoalesce(stmt.title, () => ( stmt.id)),
1158
- parentId: parent,
1159
- classes: [],
1160
- styles: []
1161
- });
1162
- membership.set(stmt.id, /* @__PURE__ */ new Set());
1163
- if (parent) membership.get(parent).add(stmt.id);
1164
- stack.push(stmt.id);
1165
- break;
1166
- }
1167
- case "end":
1168
- if (!stack.length) {
1169
- diagnostics.push({
1170
- severity: "warning",
1171
- message: "Stray `end` without a subgraph",
1172
- line: index + 1,
1173
- source: "pixerate"
1174
- });
1175
- }
1176
- stack.pop();
1177
- break;
1178
- case "direction": {
1179
- const current = stack[stack.length - 1];
1180
- if (current) groups.get(current).direction = stmt.direction;
1181
- break;
1182
- }
1183
- case "chain": {
1184
- const { groups: ngroups, links } = stmt.chain;
1185
- if (ngroups.length === 1 && ngroups[0].length === 1 && links.length === 0) {
1186
- const ref = ngroups[0];
1187
- const only = ref[0];
1188
- if (only.form === "data" && only.data && !only.shape && only.label === void 0 && ("animate" in only.data || "animation" in only.data)) {
1189
- dataOnly.push({ id: only.id, data: only.data });
1190
- break;
1191
- }
1192
- }
1193
- for (const group of ngroups) for (const ref of group) touch(ref);
1194
- links.forEach((link, i) => {
1195
- const from = ngroups[i];
1196
- const to = ngroups[i + 1];
1197
- for (const s of from) {
1198
- for (const t of to) {
1199
- const id = _nullishCoalesce(link.id, () => ( autoEdgeId(s.id, t.id, ordinal)));
1200
- edges.push({
1201
- id,
1202
- source: s.id,
1203
- target: t.id,
1204
- label: link.label,
1205
- pattern: link.pattern,
1206
- arrowStart: link.arrowStart,
1207
- arrowEnd: link.arrowEnd,
1208
- length: link.length,
1209
- classes: [],
1210
- styles: [],
1211
- userDefinedId: !!link.id
1212
- });
1213
- ordinal++;
1214
- }
1215
- }
1216
- });
1217
- break;
1218
- }
1219
- case "classDef":
1220
- for (const name of stmt.names) classDefs[name] = [...stmt.styles];
1221
- break;
1222
- case "class":
1223
- classAssignments.push({ ids: stmt.ids, className: stmt.className });
1224
- break;
1225
- case "style":
1226
- styleAssignments.push({ id: stmt.id, styles: stmt.styles });
1227
- break;
1228
- case "linkStyle":
1229
- linkStyles.push({ targets: stmt.targets, styles: stmt.styles });
1230
- break;
1231
- case "click":
1232
- clicks.push({ id: stmt.id, rest: stmt.rest });
1233
- break;
1234
- default:
1235
- break;
1236
- }
1237
- });
1238
- if (stack.length) {
1239
- diagnostics.push({
1240
- severity: "warning",
1241
- message: `${stack.length} subgraph(s) missing \`end\``,
1242
- source: "pixerate"
1243
- });
1244
- }
1245
- const parentOf2 = /* @__PURE__ */ new Map();
1246
- for (const [groupId, members] of membership) {
1247
- for (const member of members) parentOf2.set(member, groupId);
1248
- }
1249
- for (const node of nodes.values()) {
1250
- const parent = parentOf2.get(node.id);
1251
- if (parent && groups.has(parent)) node.parentId = parent;
1252
- }
1253
- for (const group of groups.values()) {
1254
- const parent = parentOf2.get(group.id);
1255
- if (parent && parent !== group.id && groups.has(parent)) group.parentId = parent;
1256
- }
1257
- for (const { ids, className } of classAssignments) {
1258
- for (const id of ids) {
1259
- const node = nodes.get(id);
1260
- const group = groups.get(id);
1261
- const target = _nullishCoalesce(node, () => ( group));
1262
- if (target && !target.classes.includes(className)) target.classes.push(className);
1263
- }
1264
- }
1265
- for (const { id, styles } of styleAssignments) {
1266
- const target = _nullishCoalesce(nodes.get(id), () => ( groups.get(id)));
1267
- if (target) target.styles.push(...styles);
1268
- }
1269
- for (const { id, rest } of clicks) {
1270
- const node = nodes.get(id);
1271
- if (!node) continue;
1272
- const parsed = parseClick(rest);
1273
- if (parsed.href) {
1274
- node.link = parsed.href;
1275
- node.linkTarget = parsed.target;
1276
- }
1277
- if (parsed.tooltip) node.tooltip = parsed.tooltip;
1278
- if (parsed.callback) node.data = { ..._nullishCoalesce(node.data, () => ( {})), callback: parsed.callback };
1279
- }
1280
- for (const { targets, styles } of linkStyles) {
1281
- if (targets === "default") {
1282
- for (const edge of edges) edge.styles.push(...styles);
1283
- } else {
1284
- for (const idx of targets) {
1285
- const edge = edges[idx];
1286
- if (edge) edge.styles.push(...styles);
1287
- else
1288
- diagnostics.push({
1289
- severity: "warning",
1290
- message: `linkStyle index ${idx} has no edge`,
1291
- source: "pixerate"
1292
- });
1293
- }
1294
- }
1295
- }
1296
- for (const { id, data } of dataOnly) {
1297
- const edge = edges.find((e) => e.id === id);
1298
- if (edge) {
1299
- if (data.animate !== void 0) edge.animate = data.animate.trim() === "true";
1300
- if (data.animation !== void 0) {
1301
- const a = data.animation.trim();
1302
- if (a === "fast" || a === "slow") edge.animation = a;
1303
- }
1304
- } else {
1305
- const node = {
1306
- id,
1307
- label: id,
1308
- shape: DEFAULT_SHAPE,
1309
- classes: [],
1310
- styles: [],
1311
- data: stripQuotes(data)
1312
- };
1313
- nodes.set(id, node);
1314
- }
1315
- }
1316
- return {
1317
- graph: {
1318
- direction,
1319
- nodes: [...nodes.values()],
1320
- edges,
1321
- groups: [...groups.values()],
1322
- classDefs,
1323
- title
1324
- },
1325
- diagnostics
1326
- };
1327
- }
1328
- function stripQuotes(data) {
1329
- const out = {};
1330
- for (const [k, v] of Object.entries(data)) {
1331
- const t = v.trim();
1332
- if (t.startsWith('"') && t.endsWith('"') || t.startsWith("'") && t.endsWith("'"))
1333
- out[k] = t.slice(1, -1);
1334
- else if (t === "true" || t === "false") out[k] = t === "true";
1335
- else if (/^-?\d+(\.\d+)?$/.test(t)) out[k] = Number(t);
1336
- else out[k] = t;
1337
- }
1338
- return out;
1339
- }
1340
- function parseClick(rest) {
1341
- const out = {};
1342
- const strings = [...rest.matchAll(/"([^"]*)"/g)].map((m) => m[1]);
1343
- const words = rest.replace(/"[^"]*"/g, "").trim().split(/\s+/).filter(Boolean);
1344
- const targetWord = words.find((w) => /^_(blank|self|parent|top)$/.test(w));
1345
- if (targetWord) out.target = targetWord;
1346
- if (words[0] === "href") {
1347
- out.href = strings[0];
1348
- out.tooltip = strings[1];
1349
- } else if (words[0] === "call" || words[0] === "callback") {
1350
- out.callback = words[0] === "callback" ? words[1] : rest.replace(/^call\s+/, "").replace(/"[^"]*"/g, "").trim();
1351
- out.tooltip = strings[0];
1352
- } else if (strings.length && /^https?:|^\/|^#|^mailto:/.test(strings[0])) {
1353
- out.href = strings[0];
1354
- out.tooltip = strings[1];
1355
- } else if (words.length) {
1356
- out.callback = words[0];
1357
- out.tooltip = strings[0];
1358
- }
1359
- return out;
1360
- }
1361
- function parseFlowchart(_source, ctx) {
1362
- const statements = tokenizeBody(ctx.bodyLines);
1363
- const direction = headerDirection(ctx.header);
1364
- const title = typeof _optionalChain([ctx, 'access', _17 => _17.preamble, 'access', _18 => _18.frontmatter, 'optionalAccess', _19 => _19.title]) === "string" ? ctx.preamble.frontmatter.title : void 0;
1365
- const { graph, diagnostics } = buildGraph(statements, direction, title);
1366
- return {
1367
- family: "flowchart",
1368
- tier: "editable",
1369
- source: ctx.source,
1370
- preamble: ctx.preamble,
1371
- header: ctx.header,
1372
- trailing: ctx.trailing,
1373
- eol: ctx.eol,
1374
- graph,
1375
- meta: ctx.meta,
1376
- metaCarrier: ctx.metaCarrier,
1377
- body: { statements },
1378
- diagnostics,
1379
- dirty: false
1380
- };
1381
- }
1382
-
1383
- // src/diagram/flowchart/serialize.ts
1384
- function serializeStatements(statements) {
1385
- const out = [];
1386
- const emitted = /* @__PURE__ */ new Set();
1387
- const present = new Set(statements);
1388
- for (const stmt of statements) {
1389
- if (emitted.has(stmt)) continue;
1390
- const compound = compoundInfo(stmt);
1391
- if (compound) {
1392
- const members = compound.members.filter((m) => present.has(m));
1393
- const complete = members.length === compound.members.length;
1394
- const anyDirty = members.some((m) => "dirty" in m && m.dirty);
1395
- if (complete && !anyDirty) {
1396
- out.push(compound.raw);
1397
- for (const member of compound.members) emitted.add(member);
1398
- continue;
1399
- }
1400
- const indent = "indent" in compound.members[0] ? compound.members[0].indent : "";
1401
- for (const member of members) {
1402
- const text = formatStatement(member);
1403
- if (text.trim() === "") continue;
1404
- out.push(text.startsWith(indent) ? text : indent + text.trimStart());
1405
- }
1406
- for (const member of compound.members) emitted.add(member);
1407
- continue;
1408
- }
1409
- out.push(formatStatement(stmt));
1410
- emitted.add(stmt);
1411
- }
1412
- return out;
1413
- }
1414
- function detectIndent(statements) {
1415
- for (const stmt of statements) {
1416
- if ("indent" in stmt && stmt.indent) return stmt.indent;
1417
- }
1418
- return " ";
1419
- }
1420
- function assembleDocument(doc, bodyLines, indent) {
1421
- const meta = isMetaEmpty(doc.meta) ? null : doc.meta;
1422
- const preambleLines = doc.metaCarrier === "frontmatter" ? writeMetaToPreamble(doc.preamble, meta) : [...doc.preamble.lines];
1423
- const lines = [...preambleLines];
1424
- if (doc.header) lines.push(doc.header);
1425
- if (meta && doc.metaCarrier === "comment") lines.push(metaCommentLine(meta, indent));
1426
- lines.push(...bodyLines);
1427
- return lines.join(doc.eol) + doc.trailing;
1428
- }
1429
- function serializeFlowchart(doc) {
1430
- const bodyLines = serializeStatements(doc.body.statements);
1431
- return assembleDocument(doc, bodyLines, detectIndent(doc.body.statements));
1432
- }
1433
-
1434
- // src/diagram/flowchart/edit.ts
1435
- function applyFlowchartEdit(doc, op) {
1436
- if (op.type === "removeEdges" && op.ids.length > 1) return removeEdgesOneByOne(doc, op.ids);
1437
- const statements = cloneStatements(doc.body.statements);
1438
- const work = {
1439
- ...doc,
1440
- body: { statements },
1441
- meta: { ...doc.meta, layout: { ...doc.meta.layout }, sizes: { ...doc.meta.sizes } }
1442
- };
1443
- const indent = detectIndent(statements);
1444
- switch (op.type) {
1445
- case "moveNodes":
1446
- for (const { id, position } of op.moves) work.meta.layout[id] = position;
1447
- return reparse(work, false);
1448
- case "resizeNode":
1449
- if (op.size) work.meta.sizes[op.id] = op.size;
1450
- else delete work.meta.sizes[op.id];
1451
- return reparse(work, false);
1452
- case "setViewport":
1453
- work.meta.viewport = op.viewport;
1454
- return reparse(work, false);
1455
- case "setMetaExt":
1456
- work.meta.ext = { ..._nullishCoalesce(work.meta.ext, () => ( {})), [op.key]: op.value };
1457
- if (op.value === void 0) delete work.meta.ext[op.key];
1458
- return reparse(work, false);
1459
- case "setDirection":
1460
- work.header = setHeaderDirection(work.header, op.direction);
1461
- return reparse(work, true);
1462
- case "setTitle":
1463
- work.preamble = {
1464
- ...work.preamble,
1465
- lines: setFrontmatterTitle(work.preamble.lines, op.title)
1466
- };
1467
- return reparse(work, true);
1468
- case "replaceSource":
1469
- return parseFlowchartSource(op.source, work.metaCarrier);
1470
- default:
1471
- break;
1472
- }
1473
- switch (op.type) {
1474
- case "addNode": {
1475
- const ref = {
1476
- id: op.node.id,
1477
- label: _nullishCoalesce(op.node.label, () => ( op.node.id)),
1478
- shape: canonicalShape(_nullishCoalesce(op.node.shape, () => ( "rect"))),
1479
- form: "bracket",
1480
- classes: [..._nullishCoalesce(op.node.classes, () => ( []))]
1481
- };
1482
- const data = shapeDataFor(ref.shape, encodeData(op.node.data));
1483
- if (Object.keys(data).length) {
1484
- ref.form = "data";
1485
- ref.data = data;
1486
- }
1487
- const stmt = {
1488
- kind: "chain",
1489
- raw: "",
1490
- indent,
1491
- chain: { groups: [[ref]], links: [] },
1492
- dirty: true
1493
- };
1494
- insertIntoGroup(statements, stmt, op.node.parentId, indent);
1495
- if (op.position) work.meta.layout[op.node.id] = op.position;
1496
- if (_optionalChain([op, 'access', _20 => _20.node, 'access', _21 => _21.styles, 'optionalAccess', _22 => _22.length])) {
1497
- statements.push({
1498
- kind: "style",
1499
- raw: "",
1500
- indent,
1501
- id: op.node.id,
1502
- styles: [...op.node.styles],
1503
- dirty: true
1504
- });
1505
- }
1506
- break;
1507
- }
1508
- case "removeNodes": {
1509
- const ids = new Set(op.ids.filter((id) => !doc.graph.groups.some((g) => g.id === id)));
1510
- for (const gid of op.ids.filter((id) => doc.graph.groups.some((g) => g.id === id))) {
1511
- const range = groupRange(statements, gid);
1512
- if (!range) continue;
1513
- statements.splice(range.end, 1);
1514
- statements.splice(range.start, 1);
1515
- delete work.meta.layout[gid];
1516
- delete work.meta.sizes[gid];
1517
- }
1518
- const removedEdgeOrdinals = edgeOrdinalsTouching(
1519
- doc.graph.edges,
1520
- (e) => ids.has(e.source) || ids.has(e.target)
1521
- );
1522
- removeNodesFromStatements(statements, ids);
1523
- dropRedundantBareMentions(statements);
1524
- filterInPlace(statements, (s) => {
1525
- if (s.kind === "style" || s.kind === "click") return !ids.has(s.id);
1526
- if (s.kind === "class") {
1527
- s.ids = s.ids.filter((id) => !ids.has(id));
1528
- if (!s.ids.length) return false;
1529
- s.dirty = true;
1530
- return true;
1531
- }
1532
- return true;
1533
- });
1534
- adjustLinkStyles(statements, removedEdgeOrdinals);
1535
- for (const id of ids) {
1536
- delete work.meta.layout[id];
1537
- delete work.meta.sizes[id];
1538
- }
1539
- break;
1540
- }
1541
- case "renameNode": {
1542
- const ref = _nullishCoalesce(declaringRef(statements, op.id, "label"), () => ( firstRef(statements, op.id)));
1543
- if (!ref) break;
1544
- const node = doc.graph.nodes.find((n) => n.id === op.id);
1545
- if (ref.ref.label === void 0) {
1546
- ref.ref.shape = _nullishCoalesce(_nullishCoalesce(ref.ref.shape, () => ( _optionalChain([node, 'optionalAccess', _23 => _23.shape]))), () => ( "rect"));
1547
- ref.ref.form = _nullishCoalesce(ref.ref.form, () => ( "bracket"));
1548
- }
1549
- ref.ref.label = op.label;
1550
- ref.ref.labelQuoted = void 0;
1551
- ref.stmt.dirty = true;
1552
- break;
1553
- }
1554
- case "setNodeShape": {
1555
- const shape = canonicalShape(op.shape);
1556
- const ref = _nullishCoalesce(declaringRef(statements, op.id, "shape"), () => ( firstRef(statements, op.id)));
1557
- if (!ref) break;
1558
- const node = doc.graph.nodes.find((n) => n.id === op.id);
1559
- ref.ref.shape = shape;
1560
- if (ref.ref.label === void 0) ref.ref.label = _nullishCoalesce(_optionalChain([node, 'optionalAccess', _24 => _24.label]), () => ( op.id));
1561
- ref.ref.form = _nullishCoalesce(ref.ref.form, () => ( "bracket"));
1562
- const data = shapeDataFor(shape, _nullishCoalesce(ref.ref.data, () => ( {})));
1563
- if (Object.keys(data).length) ref.ref.form = "data";
1564
- ref.ref.data = Object.keys(data).length ? data : void 0;
1565
- ref.stmt.dirty = true;
1566
- break;
1567
- }
1568
- case "setNodeClasses": {
1569
- for (const s of statements) {
1570
- if (s.kind === "chain") {
1571
- for (const g of s.chain.groups) {
1572
- for (const r of g) {
1573
- if (r.id === op.id && r.classes.length) {
1574
- r.classes = [];
1575
- s.dirty = true;
1576
- }
1577
- }
1578
- }
1579
- }
1580
- }
1581
- filterInPlace(statements, (s) => {
1582
- if (s.kind !== "class") return true;
1583
- if (!s.ids.includes(op.id)) return true;
1584
- s.ids = s.ids.filter((id) => id !== op.id);
1585
- s.dirty = true;
1586
- return s.ids.length > 0;
1587
- });
1588
- const [first, ...rest] = op.classes;
1589
- if (first) {
1590
- const ref = _nullishCoalesce(declaringRef(statements, op.id, "label"), () => ( firstRef(statements, op.id)));
1591
- if (ref) {
1592
- ref.ref.classes = [first];
1593
- ref.stmt.dirty = true;
1594
- }
1595
- }
1596
- for (const cls of rest)
1597
- statements.push({
1598
- kind: "class",
1599
- raw: "",
1600
- indent,
1601
- ids: [op.id],
1602
- className: cls,
1603
- dirty: true
1604
- });
1605
- break;
1606
- }
1607
- case "setNodeStyles": {
1608
- filterInPlace(statements, (s) => !(s.kind === "style" && s.id === op.id));
1609
- if (op.styles.length)
1610
- statements.push({
1611
- kind: "style",
1612
- raw: "",
1613
- indent,
1614
- id: op.id,
1615
- styles: [...op.styles],
1616
- dirty: true
1617
- });
1618
- break;
1619
- }
1620
- case "setNodeLink": {
1621
- filterInPlace(statements, (s) => !(s.kind === "click" && s.id === op.id));
1622
- if (op.link) {
1623
- const parts = [`href "${op.link}"`];
1624
- if (op.tooltip) parts.push(`"${op.tooltip}"`);
1625
- if (op.target) parts.push(op.target);
1626
- statements.push({
1627
- kind: "click",
1628
- raw: "",
1629
- indent,
1630
- id: op.id,
1631
- rest: parts.join(" "),
1632
- dirty: true
1633
- });
1634
- }
1635
- break;
1636
- }
1637
- case "setNodeData": {
1638
- const ref = _nullishCoalesce(declaringRef(statements, op.id, "label"), () => ( firstRef(statements, op.id)));
1639
- if (!ref) break;
1640
- const node = doc.graph.nodes.find((n) => n.id === op.id);
1641
- ref.ref.form = "data";
1642
- ref.ref.shape = _nullishCoalesce(_nullishCoalesce(ref.ref.shape, () => ( _optionalChain([node, 'optionalAccess', _25 => _25.shape]))), () => ( "rect"));
1643
- if (ref.ref.label === void 0) ref.ref.label = _nullishCoalesce(_optionalChain([node, 'optionalAccess', _26 => _26.label]), () => ( op.id));
1644
- const data = { ..._nullishCoalesce(ref.ref.data, () => ( {})) };
1645
- for (const [k, v] of Object.entries(op.data)) {
1646
- if (v === void 0 || v === null) delete data[k];
1647
- else data[k] = typeof v === "string" ? JSON.stringify(v) : String(v);
1648
- }
1649
- ref.ref.data = data;
1650
- ref.stmt.dirty = true;
1651
- break;
1652
- }
1653
- case "addEdge": {
1654
- const link = {
1655
- id: op.edge.userDefinedId ? op.edge.id : void 0,
1656
- pattern: _nullishCoalesce(op.edge.pattern, () => ( "solid")),
1657
- arrowStart: _nullishCoalesce(op.edge.arrowStart, () => ( "none")),
1658
- arrowEnd: _nullishCoalesce(op.edge.arrowEnd, () => ( "arrow_point")),
1659
- length: _nullishCoalesce(op.edge.length, () => ( 1)),
1660
- label: op.edge.label || void 0,
1661
- labelStyle: op.edge.label ? "pipe" : void 0
1662
- };
1663
- const stmt = {
1664
- kind: "chain",
1665
- raw: "",
1666
- indent,
1667
- chain: {
1668
- groups: [[{ id: op.edge.source, classes: [] }], [{ id: op.edge.target, classes: [] }]],
1669
- links: [link]
1670
- },
1671
- dirty: true
1672
- };
1673
- appendAtEnd(statements, stmt);
1674
- if (_optionalChain([op, 'access', _27 => _27.edge, 'access', _28 => _28.styles, 'optionalAccess', _29 => _29.length])) {
1675
- statements.push({
1676
- kind: "linkStyle",
1677
- raw: "",
1678
- indent,
1679
- targets: [doc.graph.edges.length],
1680
- styles: [...op.edge.styles],
1681
- dirty: true
1682
- });
1683
- }
1684
- break;
1685
- }
1686
- case "removeEdges": {
1687
- const ids = new Set(op.ids);
1688
- const removedOrdinals = edgeOrdinalsTouching(doc.graph.edges, (e) => ids.has(e.id));
1689
- for (const edge of doc.graph.edges) {
1690
- if (!ids.has(edge.id)) continue;
1691
- const located = locateEdge(statements, doc.graph.edges, edge.id);
1692
- if (!located) continue;
1693
- removeLinkFromChain(
1694
- statements,
1695
- located.stmt,
1696
- located.linkIndex,
1697
- located.source,
1698
- located.target,
1699
- indent
1700
- );
1701
- }
1702
- adjustLinkStyles(statements, removedOrdinals);
1703
- break;
1704
- }
1705
- case "setEdgeLabel":
1706
- case "setEdgeStyle":
1707
- case "reconnectEdge": {
1708
- const located = locateEdge(statements, doc.graph.edges, op.id);
1709
- if (!located) break;
1710
- const stmt = isolateEdge(
1711
- statements,
1712
- located.stmt,
1713
- located.linkIndex,
1714
- located.source,
1715
- located.target,
1716
- indent
1717
- );
1718
- const link = stmt.chain.links[0];
1719
- if (op.type === "setEdgeLabel") {
1720
- link.label = op.label || void 0;
1721
- if (link.label && !link.labelStyle) link.labelStyle = "pipe";
1722
- } else if (op.type === "setEdgeStyle") {
1723
- if (op.pattern) link.pattern = op.pattern;
1724
- if (op.arrowStart) link.arrowStart = op.arrowStart;
1725
- if (op.arrowEnd) link.arrowEnd = op.arrowEnd;
1726
- if (op.length) link.length = op.length;
1727
- if (op.styles) {
1728
- const ordinal = doc.graph.edges.findIndex((e) => e.id === op.id);
1729
- setLinkStyleFor(statements, ordinal, op.styles, indent);
1730
- }
1731
- } else {
1732
- stmt.chain.groups[0] = [{ id: op.source, classes: [] }];
1733
- stmt.chain.groups[1] = [{ id: op.target, classes: [] }];
1734
- }
1735
- stmt.dirty = true;
1736
- break;
1737
- }
1738
- case "groupNodes": {
1739
- const open = {
1740
- kind: "subgraph",
1741
- raw: "",
1742
- indent,
1743
- id: op.groupId,
1744
- title: op.label,
1745
- titleForm: "bracket",
1746
- dirty: true
1747
- };
1748
- const members = op.nodeIds.map((id) => ({
1749
- kind: "chain",
1750
- raw: "",
1751
- indent: indent + indent,
1752
- chain: { groups: [[{ id, classes: [] }]], links: [] },
1753
- dirty: true
1754
- }));
1755
- const block = [
1756
- open,
1757
- ...members,
1758
- { kind: "end", raw: `${indent}end`, indent }
1759
- ];
1760
- if (op.parentId) insertManyIntoGroup(statements, block, op.parentId, indent);
1761
- else statements.push(...block);
1762
- break;
1763
- }
1764
- case "ungroup": {
1765
- const range = groupRange(statements, op.groupId);
1766
- if (!range) break;
1767
- const openIndent = statements[range.start].indent;
1768
- const inner = openIndent + indent;
1769
- for (let i = range.start + 1; i < range.end; i++) {
1770
- const s = statements[i];
1771
- if (s.kind === "raw" || s.kind === "end") {
1772
- if (s.raw.startsWith(inner))
1773
- s.raw = openIndent + s.raw.slice(inner.length);
1774
- continue;
1775
- }
1776
- if (s.indent.startsWith(inner)) {
1777
- s.indent = openIndent + s.indent.slice(inner.length);
1778
- s.dirty = true;
1779
- }
1780
- }
1781
- statements.splice(range.end, 1);
1782
- statements.splice(range.start, 1);
1783
- for (let i = range.start; i < range.end - 1; i++) {
1784
- const s = statements[i];
1785
- if (s && s.kind === "direction" && depthAt(statements, i) === depthAt(statements, range.start)) {
1786
- statements.splice(i, 1);
1787
- break;
1788
- }
1789
- }
1790
- delete work.meta.layout[op.groupId];
1791
- delete work.meta.sizes[op.groupId];
1792
- break;
1793
- }
1794
- case "renameGroup": {
1795
- const range = groupRange(statements, op.id);
1796
- if (!range) break;
1797
- const open = statements[range.start];
1798
- open.title = op.label;
1799
- if (open.titleForm === "none") open.titleForm = "bracket";
1800
- if (open.titleForm === "bare") {
1801
- open.titleForm = "bracket";
1802
- }
1803
- open.dirty = true;
1804
- break;
1805
- }
1806
- case "setGroupDirection": {
1807
- const range = groupRange(statements, op.id);
1808
- if (!range) break;
1809
- let found = -1;
1810
- for (let i = range.start + 1; i < range.end; i++) {
1811
- const s = statements[i];
1812
- if (s.kind === "direction" && depthAt(statements, i) === depthAt(statements, range.start) + 1) {
1813
- found = i;
1814
- break;
1815
- }
1816
- }
1817
- if (op.direction) {
1818
- if (found !== -1) {
1819
- const s = statements[found];
1820
- s.direction = op.direction;
1821
- s.dirty = true;
1822
- } else {
1823
- const inner = statements[range.start].indent + indent;
1824
- statements.splice(range.start + 1, 0, {
1825
- kind: "direction",
1826
- raw: "",
1827
- indent: inner,
1828
- direction: op.direction,
1829
- dirty: true
1830
- });
1831
- }
1832
- } else if (found !== -1) {
1833
- statements.splice(found, 1);
1834
- }
1835
- break;
1836
- }
1837
- case "setNodeParent": {
1838
- for (const id of op.ids) {
1839
- const bare = statements.map((s, i) => ({ s, i })).filter(
1840
- ({ s }) => s.kind === "chain" && s.chain.links.length === 0 && s.chain.groups[0].length === 1 && s.chain.groups[0][0].id === id
1841
- );
1842
- let decl;
1843
- for (const { s, i } of bare.reverse()) {
1844
- const ref = s.chain.groups[0][0];
1845
- if (ref.label !== void 0 || ref.shape) decl = { ...ref };
1846
- statements.splice(i, 1);
1847
- }
1848
- if (op.parentId) {
1849
- const ref = _nullishCoalesce(decl, () => ( { id, classes: [] }));
1850
- const stmt = {
1851
- kind: "chain",
1852
- raw: "",
1853
- indent,
1854
- chain: { groups: [[ref]], links: [] },
1855
- dirty: true
1856
- };
1857
- insertIntoGroup(statements, stmt, op.parentId, indent);
1858
- } else if (decl) {
1859
- appendAtEnd(statements, {
1860
- kind: "chain",
1861
- raw: "",
1862
- indent,
1863
- chain: { groups: [[decl]], links: [] },
1864
- dirty: true
1865
- });
1866
- }
1867
- }
1868
- break;
1869
- }
1870
- case "setClassDef": {
1871
- let found = false;
1872
- for (const s of statements) {
1873
- if (s.kind !== "classDef") continue;
1874
- if (s.names.length === 1 && s.names[0] === op.name) {
1875
- found = true;
1876
- if (op.styles) {
1877
- s.styles = [...op.styles];
1878
- s.dirty = true;
1879
- }
1880
- } else if (s.names.includes(op.name) && op.styles) {
1881
- s.names = s.names.filter((n) => n !== op.name);
1882
- s.dirty = true;
1883
- }
1884
- }
1885
- if (!op.styles)
1886
- filterInPlace(
1887
- statements,
1888
- (s) => !(s.kind === "classDef" && s.names.length === 1 && s.names[0] === op.name)
1889
- );
1890
- else if (!found)
1891
- statements.push({
1892
- kind: "classDef",
1893
- raw: "",
1894
- indent,
1895
- names: [op.name],
1896
- styles: [...op.styles],
1897
- dirty: true
1898
- });
1899
- break;
1900
- }
1901
- default:
1902
- break;
1903
- }
1904
- return reparse(work, true);
1905
- }
1906
- function cloneStatements(statements) {
1907
- const clones = statements.map(cloneStatement);
1908
- const index = new Map(statements.map((s, i) => [s, i]));
1909
- const done = /* @__PURE__ */ new Set();
1910
- statements.forEach((original) => {
1911
- const info = compoundInfo(original);
1912
- if (!info || done.has(original)) return;
1913
- const members = info.members.map((m) => clones[index.get(m)]);
1914
- info.members.forEach((m, j) => {
1915
- done.add(m);
1916
- markCompound(members[j], members, j === 0 ? info.raw : "");
1917
- });
1918
- });
1919
- return clones;
1920
- }
1921
- function cloneStatement(s) {
1922
- if (s.kind === "chain") {
1923
- return {
1924
- ...s,
1925
- chain: {
1926
- groups: s.chain.groups.map(
1927
- (g) => g.map((r) => ({
1928
- ...r,
1929
- classes: [...r.classes],
1930
- data: r.data ? { ...r.data } : void 0
1931
- }))
1932
- ),
1933
- links: s.chain.links.map((l) => ({ ...l }))
1934
- }
1935
- };
1936
- }
1937
- if (s.kind === "classDef") return { ...s, names: [...s.names], styles: [...s.styles] };
1938
- if (s.kind === "class") return { ...s, ids: [...s.ids] };
1939
- if (s.kind === "style") return { ...s, styles: [...s.styles] };
1940
- if (s.kind === "linkStyle")
1941
- return {
1942
- ...s,
1943
- targets: s.targets === "default" ? "default" : [...s.targets],
1944
- styles: [...s.styles]
1945
- };
1946
- return { ...s };
1947
- }
1948
- function reparse(work, structural) {
1949
- const text = serializeFlowchart(work);
1950
- const next = parseFlowchartSource(text, work.metaCarrier);
1951
- next.dirty = doc_dirty(work, structural);
1952
- return next;
1953
- }
1954
- function doc_dirty(work, structural) {
1955
- return work.dirty || structural;
1956
- }
1957
- function parseFlowchartSource(source, carrier) {
1958
- const split = splitSource(source);
1959
- const fromBody = extractMetaFromBody(split.bodyLines);
1960
- const fromFm = extractMetaFromFrontmatter(split.preamble);
1961
- let meta = emptyMeta();
1962
- if (fromFm) meta = mergeMeta(meta, fromFm);
1963
- if (fromBody.meta) meta = mergeMeta(meta, fromBody.meta);
1964
- return parseFlowchart(source, {
1965
- source,
1966
- eol: split.eol,
1967
- preamble: split.preamble,
1968
- header: split.header,
1969
- bodyLines: fromBody.bodyLines,
1970
- trailing: split.trailing,
1971
- meta,
1972
- metaCarrier: _nullishCoalesce(carrier, () => ( (fromFm && !fromBody.meta ? "frontmatter" : defaultCarrierFor("flowchart")))),
1973
- family: "flowchart"
1974
- });
1975
- }
1976
- function filterInPlace(arr, keep) {
1977
- let j = 0;
1978
- for (let i = 0; i < arr.length; i++) {
1979
- if (keep(arr[i])) arr[j++] = arr[i];
1980
- }
1981
- arr.length = j;
1982
- }
1983
- function setHeaderDirection(header, direction) {
1984
- const m = /^(\s*)(flowchart|graph)(-elk)?\b/i.exec(header);
1985
- if (!m) return header;
1986
- const keyword = `${m[2]}${_nullishCoalesce(m[3], () => ( ""))}`;
1987
- const trailingSemi = /;\s*$/.test(header) ? ";" : "";
1988
- return `${m[1]}${keyword} ${direction}${trailingSemi}`;
1989
- }
1990
- function setFrontmatterTitle(lines, title) {
1991
- const out = [...lines];
1992
- const hasFm = out[0] !== void 0 && /^---\s*$/.test(out[0]);
1993
- if (!hasFm) {
1994
- if (title === void 0) return out;
1995
- return ["---", `title: ${title}`, "---", ...out];
1996
- }
1997
- const close = out.findIndex((l, i) => i > 0 && /^---\s*$/.test(l));
1998
- const end = close === -1 ? out.length : close;
1999
- const idx = out.findIndex((l, i) => i > 0 && i < end && /^title\s*:/.test(l));
2000
- if (title === void 0) {
2001
- if (idx !== -1) out.splice(idx, 1);
2002
- const close2 = out.findIndex((l, i) => i > 0 && /^---\s*$/.test(l));
2003
- if (close2 === 1) out.splice(0, 2);
2004
- return out;
2005
- }
2006
- if (idx !== -1) out[idx] = `title: ${title}`;
2007
- else out.splice(end, 0, `title: ${title}`);
2008
- return out;
2009
- }
2010
- function depthAt(statements, index) {
2011
- let depth = 0;
2012
- for (let i = 0; i < index; i++) {
2013
- const s = statements[i];
2014
- if (s.kind === "subgraph") depth++;
2015
- else if (s.kind === "end") depth = Math.max(0, depth - 1);
2016
- }
2017
- return depth;
2018
- }
2019
- function groupRange(statements, groupId) {
2020
- const start = statements.findIndex((s) => s.kind === "subgraph" && s.id === groupId);
2021
- if (start === -1) return null;
2022
- let depth = 0;
2023
- for (let i = start; i < statements.length; i++) {
2024
- const s = statements[i];
2025
- if (s.kind === "subgraph") depth++;
2026
- else if (s.kind === "end") {
2027
- depth--;
2028
- if (depth === 0) return { start, end: i };
2029
- }
2030
- }
2031
- return { start, end: statements.length };
2032
- }
2033
- function appendAtEnd(statements, stmt) {
2034
- statements.push(stmt);
2035
- }
2036
- function insertIntoGroup(statements, stmt, groupId, indent) {
2037
- insertManyIntoGroup(statements, [stmt], groupId, indent);
2038
- }
2039
- function insertManyIntoGroup(statements, block, groupId, indent) {
2040
- const range = groupId ? groupRange(statements, groupId) : null;
2041
- if (!range) {
2042
- statements.push(...block);
2043
- return;
2044
- }
2045
- const open = statements[range.start];
2046
- const inner = open.indent + indent;
2047
- for (const s of block)
2048
- if ("indent" in s)
2049
- s.indent = inner + s.indent.slice(indent.length);
2050
- statements.splice(range.end, 0, ...block);
2051
- }
2052
- function declaringRef(statements, id, prop) {
2053
- for (const s of statements) {
2054
- if (s.kind !== "chain") continue;
2055
- for (const g of s.chain.groups) {
2056
- for (const r of g) {
2057
- if (r.id === id && r[prop] !== void 0) return { stmt: s, ref: r };
2058
- }
2059
- }
2060
- }
2061
- return null;
2062
- }
2063
- function firstRef(statements, id) {
2064
- for (const s of statements) {
2065
- if (s.kind !== "chain") continue;
2066
- for (const g of s.chain.groups) for (const r of g) if (r.id === id) return { stmt: s, ref: r };
2067
- }
2068
- return null;
2069
- }
2070
- function edgeOrdinalsTouching(edges, predicate) {
2071
- const out = [];
2072
- edges.forEach((e, i) => {
2073
- if (predicate(e)) out.push(i);
2074
- });
2075
- return out;
2076
- }
2077
- function adjustLinkStyles(statements, removedOrdinals) {
2078
- if (!removedOrdinals.length) return;
2079
- const removed = new Set(removedOrdinals);
2080
- filterInPlace(statements, (s) => {
2081
- if (s.kind !== "linkStyle" || s.targets === "default") return true;
2082
- const next = s.targets.filter((t) => !removed.has(t)).map((t) => t - removedOrdinals.filter((r) => r < t).length);
2083
- if (next.length !== s.targets.length || next.some((t, i) => t !== s.targets[i])) {
2084
- s.targets = next;
2085
- s.dirty = true;
2086
- }
2087
- return next.length > 0;
2088
- });
2089
- }
2090
- function setLinkStyleFor(statements, ordinal, styles, indent) {
2091
- if (ordinal < 0) return;
2092
- filterInPlace(statements, (s) => {
2093
- if (s.kind !== "linkStyle" || s.targets === "default") return true;
2094
- if (!s.targets.includes(ordinal)) return true;
2095
- s.targets = s.targets.filter((t) => t !== ordinal);
2096
- s.dirty = true;
2097
- return s.targets.length > 0;
2098
- });
2099
- if (styles.length)
2100
- statements.push({
2101
- kind: "linkStyle",
2102
- raw: "",
2103
- indent,
2104
- targets: [ordinal],
2105
- styles: [...styles],
2106
- dirty: true
2107
- });
2108
- }
2109
- function locateEdge(statements, edges, edgeId) {
2110
- const target = edges.find((e) => e.id === edgeId);
2111
- if (!target) return null;
2112
- const ordinal = edges.indexOf(target);
2113
- let n = 0;
2114
- for (const s of statements) {
2115
- if (s.kind !== "chain") continue;
2116
- const { groups, links } = s.chain;
2117
- if (groups.length === 1 && groups[0].length === 1 && links.length === 0 && isEdgeDataStatement(groups[0][0]))
2118
- continue;
2119
- for (let i = 0; i < links.length; i++) {
2120
- for (const from of groups[i]) {
2121
- for (const to of groups[i + 1]) {
2122
- if (n === ordinal) return { stmt: s, linkIndex: i, source: from.id, target: to.id };
2123
- n++;
2124
- }
2125
- }
2126
- }
2127
- }
2128
- return null;
2129
- }
2130
- function isEdgeDataStatement(ref) {
2131
- return ref.form === "data" && !!ref.data && !ref.shape && ref.label === void 0 && ("animate" in ref.data || "animation" in ref.data);
2132
- }
2133
- function isolateEdge(statements, stmt, linkIndex, source, target, indent) {
2134
- const { groups, links } = stmt.chain;
2135
- const simple = groups.length === 2 && groups[0].length === 1 && groups[1].length === 1;
2136
- if (simple) return stmt;
2137
- const expanded = expandChain(stmt.chain);
2138
- const idx = statements.indexOf(stmt);
2139
- const out = expanded.map((chain) => ({
2140
- kind: "chain",
2141
- raw: "",
2142
- indent: stmt.indent || indent,
2143
- chain,
2144
- dirty: true
2145
- }));
2146
- statements.splice(idx, 1, ...out);
2147
- const found = out.find(
2148
- (s) => s.chain.links.length === 1 && s.chain.groups[0][0].id === source && s.chain.groups[1][0].id === target && sameLink(s.chain.links[0], links[linkIndex])
2149
- );
2150
- return _nullishCoalesce(found, () => ( out[0]));
2151
- }
2152
- function sameLink(a, b) {
2153
- return a.pattern === b.pattern && a.arrowStart === b.arrowStart && a.arrowEnd === b.arrowEnd && a.label === b.label && a.id === b.id && a.length === b.length;
2154
- }
2155
- function expandChain(chain) {
2156
- const out = [];
2157
- const declared = /* @__PURE__ */ new Set();
2158
- const refFor = (r) => {
2159
- if (declared.has(r.id)) return { id: r.id, classes: [] };
2160
- declared.add(r.id);
2161
- return { ...r, classes: [...r.classes] };
2162
- };
2163
- chain.links.forEach((link, i) => {
2164
- for (const from of chain.groups[i]) {
2165
- for (const to of chain.groups[i + 1]) {
2166
- out.push({ groups: [[refFor(from)], [refFor(to)]], links: [{ ...link }] });
2167
- }
2168
- }
2169
- });
2170
- if (!chain.links.length) {
2171
- for (const ref of chain.groups[0]) out.push({ groups: [[refFor(ref)]], links: [] });
2172
- }
2173
- return out;
2174
- }
2175
- function removeLinkFromChain(statements, stmt, linkIndex, source, target, indent) {
2176
- const isolated = isolateEdge(statements, stmt, linkIndex, source, target, indent);
2177
- const idx = statements.indexOf(isolated);
2178
- if (idx === -1) return;
2179
- const [from, to] = [isolated.chain.groups[0][0], isolated.chain.groups[1][0]];
2180
- const keep = [];
2181
- for (const ref of [from, to]) {
2182
- const declares = ref.label !== void 0 || ref.shape || ref.classes.length || ref.data && Object.keys(ref.data).length;
2183
- const mentionedElsewhere = statements.some(
2184
- (s) => s !== isolated && s.kind === "chain" && s.chain.groups.some((g) => g.some((r) => r.id === ref.id))
2185
- );
2186
- if (declares || !mentionedElsewhere) {
2187
- keep.push({
2188
- kind: "chain",
2189
- raw: "",
2190
- indent: isolated.indent || indent,
2191
- chain: { groups: [[ref]], links: [] },
2192
- dirty: true
2193
- });
2194
- }
2195
- }
2196
- statements.splice(idx, 1, ...keep);
2197
- }
2198
- function dropRedundantBareMentions(statements) {
2199
- const mentions = /* @__PURE__ */ new Map();
2200
- for (const s of statements) {
2201
- if (s.kind !== "chain") continue;
2202
- for (const g of s.chain.groups)
2203
- for (const r of g) mentions.set(r.id, (_nullishCoalesce(mentions.get(r.id), () => ( 0))) + 1);
2204
- }
2205
- filterInPlace(statements, (s) => {
2206
- if (s.kind !== "chain" || !s.dirty || s.chain.links.length || s.chain.groups[0].length !== 1)
2207
- return true;
2208
- const ref = s.chain.groups[0][0];
2209
- const bare = ref.label === void 0 && !ref.shape && !ref.classes.length && !(ref.data && Object.keys(ref.data).length);
2210
- if (!bare) return true;
2211
- if ((_nullishCoalesce(mentions.get(ref.id), () => ( 0))) > 1) {
2212
- mentions.set(ref.id, mentions.get(ref.id) - 1);
2213
- return false;
2214
- }
2215
- return true;
2216
- });
2217
- }
2218
- function removeNodesFromStatements(statements, ids) {
2219
- for (let i = 0; i < statements.length; i++) {
2220
- const s = statements[i];
2221
- if (s.kind !== "chain") continue;
2222
- const mentions = s.chain.groups.some((g) => g.some((r) => ids.has(r.id)));
2223
- if (!mentions) continue;
2224
- const pieces = splitChainWithout(s.chain, ids);
2225
- const replacement = pieces.map((chain) => ({
2226
- kind: "chain",
2227
- raw: "",
2228
- indent: s.indent,
2229
- chain,
2230
- dirty: true
2231
- }));
2232
- statements.splice(i, 1, ...replacement);
2233
- i += replacement.length - 1;
2234
- }
2235
- }
2236
- function splitChainWithout(chain, ids) {
2237
- const out = [];
2238
- let cur = { groups: [], links: [] };
2239
- for (let i = 0; i < chain.groups.length; i++) {
2240
- const group = chain.groups[i].filter((r) => !ids.has(r.id));
2241
- if (!group.length) {
2242
- if (cur.groups.length) out.push(cur);
2243
- cur = { groups: [], links: [] };
2244
- continue;
2245
- }
2246
- if (cur.groups.length) cur.links.push({ ...chain.links[i - 1] });
2247
- cur.groups.push(group);
2248
- }
2249
- if (cur.groups.length) out.push(cur);
2250
- return out;
2251
- }
2252
- function removeEdgesOneByOne(doc, ids) {
2253
- const wanted = new Set(ids);
2254
- const targets = doc.graph.edges.map((edge, ordinal) => ({ edge, ordinal })).filter(({ edge }) => wanted.has(edge.id)).map(({ edge, ordinal }) => ({
2255
- ordinal,
2256
- source: edge.source,
2257
- target: edge.target,
2258
- pairIndex: doc.graph.edges.slice(0, ordinal).filter((e) => e.source === edge.source && e.target === edge.target).length
2259
- })).sort((a, b) => b.ordinal - a.ordinal);
2260
- let current = doc;
2261
- for (const t of targets) {
2262
- const match = current.graph.edges.filter((e) => e.source === t.source && e.target === t.target)[t.pairIndex];
2263
- if (match) current = applyFlowchartEdit(current, { type: "removeEdges", ids: [match.id] });
2264
- }
2265
- return current;
2266
- }
2267
- function encodeData(data) {
2268
- const out = {};
2269
- for (const [k, v] of Object.entries(_nullishCoalesce(data, () => ( {})))) {
2270
- if (v === void 0 || v === null) continue;
2271
- out[k] = typeof v === "string" ? JSON.stringify(v) : String(v);
2272
- }
2273
- return out;
2274
- }
2275
- var IMAGE_KEYS = ["img", "pos", "w", "h", "constraint"];
2276
- function shapeDataFor(shape, data) {
2277
- const out = { ...data };
2278
- if (shape === "image") {
2279
- if (!("img" in out)) out.img = '""';
2280
- } else {
2281
- for (const key of IMAGE_KEYS) delete out[key];
2282
- }
2283
- return out;
2284
- }
2285
-
2286
- // src/diagram/flowchart/index.ts
2287
- var flowchartAdapter = {
2288
- family: "flowchart",
2289
- tier: "editable",
2290
- parse: parseFlowchart,
2291
- serialize: serializeFlowchart,
2292
- apply: applyFlowchartEdit
2293
- };
2294
-
2295
- // src/diagram/lines-grammar/engine.ts
2296
- function buildLineGraph(grammar, statements, direction, title) {
2297
- const nodes = /* @__PURE__ */ new Map();
2298
- const groups = /* @__PURE__ */ new Map();
2299
- const edges = [];
2300
- const classDefs = {};
2301
- const diagnostics = [];
2302
- const stack = [];
2303
- const classAssignments = [];
2304
- const styleAssignments = [];
2305
- let ordinal = 0;
2306
- const touch = (decl, role) => {
2307
- if (role !== "decl" && grammar.resolveEndpoint) {
2308
- const resolved = grammar.resolveEndpoint(decl.id, stack, role);
2309
- if (resolved) {
2310
- if (!nodes.has(resolved.id)) {
2311
- nodes.set(resolved.id, {
2312
- id: resolved.id,
2313
- label: resolved.label,
2314
- shape: resolved.shape,
2315
- parentId: stack[stack.length - 1],
2316
- classes: [],
2317
- styles: [],
2318
- data: { synthetic: true }
2319
- });
2320
- }
2321
- return resolved.id;
2322
- }
2323
- }
2324
- let node = nodes.get(decl.id);
2325
- if (!node) {
2326
- node = { id: decl.id, label: decl.id, shape: grammar.defaultShape, classes: [], styles: [] };
2327
- nodes.set(decl.id, node);
2328
- }
2329
- const parent = stack[stack.length - 1];
2330
- if (parent) node.parentId = parent;
2331
- if (decl.label !== void 0) node.label = decl.label;
2332
- if (decl.shape) node.shape = decl.shape;
2333
- for (const cls of decl.classes) if (!node.classes.includes(cls)) node.classes.push(cls);
2334
- if (decl.data) node.data = mergeData(node.data, decl.data);
2335
- return node.id;
2336
- };
2337
- for (const stmt of statements) {
2338
- switch (stmt.kind) {
2339
- case "groupOpen": {
2340
- const parent = stack[stack.length - 1];
2341
- const existing = nodes.get(stmt.id);
2342
- if (existing) nodes.delete(stmt.id);
2343
- groups.set(stmt.id, {
2344
- id: stmt.id,
2345
- label: _nullishCoalesce(_nullishCoalesce(stmt.label, () => ( _optionalChain([existing, 'optionalAccess', _30 => _30.label]))), () => ( stmt.id)),
2346
- parentId: parent,
2347
- classes: _nullishCoalesce(_optionalChain([existing, 'optionalAccess', _31 => _31.classes]), () => ( [])),
2348
- styles: _nullishCoalesce(_optionalChain([existing, 'optionalAccess', _32 => _32.styles]), () => ( [])),
2349
- data: _optionalChain([existing, 'optionalAccess', _33 => _33.data])
2350
- });
2351
- stack.push(stmt.id);
2352
- break;
2353
- }
2354
- case "groupClose":
2355
- if (!stack.length)
2356
- diagnostics.push({
2357
- severity: "warning",
2358
- message: "Unbalanced closing brace",
2359
- source: "pixerate"
2360
- });
2361
- stack.pop();
2362
- break;
2363
- case "direction": {
2364
- const current = stack[stack.length - 1];
2365
- if (current) groups.get(current).direction = stmt.direction;
2366
- break;
2367
- }
2368
- case "node":
2369
- touch(stmt.decl, "decl");
2370
- break;
2371
- case "edge": {
2372
- const s = touch(stmt.source, "source");
2373
- const t = touch(stmt.target, "target");
2374
- edges.push({
2375
- id: `L_${s}_${t}_${ordinal}`,
2376
- source: s,
2377
- target: t,
2378
- label: stmt.label,
2379
- pattern: stmt.pattern,
2380
- arrowStart: stmt.arrowStart,
2381
- arrowEnd: stmt.arrowEnd,
2382
- length: 1,
2383
- classes: [],
2384
- styles: [],
2385
- userDefinedId: false,
2386
- data: stmt.data
2387
- });
2388
- ordinal++;
2389
- break;
2390
- }
2391
- case "classDef":
2392
- for (const name of stmt.names) classDefs[name] = [...stmt.styles];
2393
- break;
2394
- case "class":
2395
- classAssignments.push({ ids: stmt.ids, className: stmt.className });
2396
- break;
2397
- case "style":
2398
- styleAssignments.push({ id: stmt.id, styles: stmt.styles });
2399
- break;
2400
- default:
2401
- break;
2402
- }
2403
- }
2404
- if (stack.length)
2405
- diagnostics.push({
2406
- severity: "warning",
2407
- message: `${stack.length} block(s) not closed`,
2408
- source: "pixerate"
2409
- });
2410
- for (const edge of edges) {
2411
- for (const end of ["source", "target"]) {
2412
- const id = edge[end];
2413
- if (groups.has(id) && nodes.has(id)) nodes.delete(id);
2414
- }
2415
- }
2416
- for (const { ids, className } of classAssignments) {
2417
- for (const id of ids) {
2418
- const target = _nullishCoalesce(nodes.get(id), () => ( groups.get(id)));
2419
- if (target && !target.classes.includes(className)) target.classes.push(className);
2420
- }
2421
- }
2422
- for (const { id, styles } of styleAssignments) {
2423
- const target = _nullishCoalesce(nodes.get(id), () => ( groups.get(id)));
2424
- if (target) target.styles.push(...styles);
2425
- }
2426
- return {
2427
- graph: {
2428
- direction,
2429
- nodes: [...nodes.values()],
2430
- edges,
2431
- groups: [...groups.values()],
2432
- classDefs,
2433
- title
2434
- },
2435
- diagnostics
2436
- };
2437
- }
2438
- function mergeData(a, b) {
2439
- const out = { ..._nullishCoalesce(a, () => ( {})) };
2440
- for (const [k, v] of Object.entries(b)) {
2441
- if (Array.isArray(v) && Array.isArray(out[k])) out[k] = [...out[k], ...v];
2442
- else out[k] = v;
2443
- }
2444
- return out;
2445
- }
2446
- function parseLineDocument(grammar, source, ctx) {
2447
- const statements = grammar.joinLines(ctx.bodyLines).map((line) => grammar.parseLine(line));
2448
- const direction = grammar.headerDirection(ctx.header, statements);
2449
- const title = typeof _optionalChain([ctx, 'access', _34 => _34.preamble, 'access', _35 => _35.frontmatter, 'optionalAccess', _36 => _36.title]) === "string" ? ctx.preamble.frontmatter.title : void 0;
2450
- const { graph, diagnostics } = buildLineGraph(grammar, statements, direction, title);
2451
- return {
2452
- family: grammar.family,
2453
- tier: "editable",
2454
- source,
2455
- preamble: ctx.preamble,
2456
- header: ctx.header,
2457
- trailing: ctx.trailing,
2458
- eol: ctx.eol,
2459
- graph,
2460
- meta: ctx.meta,
2461
- metaCarrier: ctx.metaCarrier,
2462
- body: { statements },
2463
- diagnostics,
2464
- dirty: false
2465
- };
2466
- }
2467
- function serializeLineDocument(grammar, doc) {
2468
- const lines = [];
2469
- for (const stmt of doc.body.statements) {
2470
- if (stmt.kind === "raw") {
2471
- lines.push(stmt.raw);
2472
- continue;
2473
- }
2474
- if (!("dirty" in stmt) || !stmt.dirty) {
2475
- lines.push(stmt.raw);
2476
- if (stmt.kind === "node" && stmt.body) lines.push(...stmt.body);
2477
- continue;
2478
- }
2479
- lines.push(grammar.formatStatement(stmt));
2480
- if (stmt.kind === "node" && stmt.body) lines.push(...stmt.body);
2481
- }
2482
- const indent = detectIndent2(doc.body.statements);
2483
- return assembleDocument(doc, lines, indent);
2484
- }
2485
- function detectIndent2(statements) {
2486
- for (const s of statements) if (s.indent) return s.indent;
2487
- return " ";
2488
- }
2489
- function parseFull(grammar, source, carrier) {
2490
- const split = splitSource(source);
2491
- const fromBody = extractMetaFromBody(split.bodyLines);
2492
- const fromFm = extractMetaFromFrontmatter(split.preamble);
2493
- let meta = emptyMeta();
2494
- if (fromFm) meta = mergeMeta(meta, fromFm);
2495
- if (fromBody.meta) meta = mergeMeta(meta, fromBody.meta);
2496
- return parseLineDocument(grammar, source, {
2497
- source,
2498
- eol: split.eol,
2499
- preamble: split.preamble,
2500
- header: split.header,
2501
- bodyLines: fromBody.bodyLines,
2502
- trailing: split.trailing,
2503
- meta,
2504
- metaCarrier: _nullishCoalesce(carrier, () => ( (fromFm && !fromBody.meta ? "frontmatter" : defaultCarrierFor(grammar.family)))),
2505
- family: grammar.family
2506
- });
2507
- }
2508
- function applyLineEdit(grammar, doc, op) {
2509
- const statements = doc.body.statements.map((s) => ({
2510
- ...s,
2511
- ..."decl" in s ? {
2512
- decl: {
2513
- ...s.decl,
2514
- classes: [...s.decl.classes],
2515
- data: s.decl.data ? { ...s.decl.data } : void 0
2516
- }
2517
- } : {},
2518
- ..."source" in s ? {
2519
- source: { ...s.source, classes: [...s.source.classes] },
2520
- target: { ...s.target, classes: [...s.target.classes] }
2521
- } : {}
2522
- }));
2523
- const work = {
2524
- ...doc,
2525
- body: { statements },
2526
- meta: { ...doc.meta, layout: { ...doc.meta.layout }, sizes: { ...doc.meta.sizes } }
2527
- };
2528
- const indent = detectIndent2(statements);
2529
- const reparse2 = (structural) => {
2530
- const text = serializeLineDocument(grammar, work);
2531
- const next = parseFull(grammar, text, work.metaCarrier);
2532
- next.dirty = doc.dirty || structural;
2533
- return next;
2534
- };
2535
- switch (op.type) {
2536
- case "moveNodes":
2537
- for (const { id, position } of op.moves) work.meta.layout[id] = position;
2538
- return reparse2(false);
2539
- case "resizeNode":
2540
- if (op.size) work.meta.sizes[op.id] = op.size;
2541
- else delete work.meta.sizes[op.id];
2542
- return reparse2(false);
2543
- case "setViewport":
2544
- work.meta.viewport = op.viewport;
2545
- return reparse2(false);
2546
- case "setMetaExt":
2547
- work.meta.ext = { ..._nullishCoalesce(work.meta.ext, () => ( {})), [op.key]: op.value };
2548
- if (op.value === void 0) delete work.meta.ext[op.key];
2549
- return reparse2(false);
2550
- case "replaceSource":
2551
- return parseFull(grammar, op.source, work.metaCarrier);
2552
- case "setTitle": {
2553
- const lines = [...work.preamble.lines];
2554
- work.preamble = { ...work.preamble, lines: setTitle(lines, op.title) };
2555
- return reparse2(true);
2556
- }
2557
- case "setDirection": {
2558
- if (grammar.directionAsStatement) {
2559
- const idx = statements.findIndex(
2560
- (s, i) => s.kind === "direction" && depthAt2(statements, i) === 0
2561
- );
2562
- if (idx !== -1) {
2563
- const s = statements[idx];
2564
- s.direction = op.direction;
2565
- s.dirty = true;
2566
- } else {
2567
- statements.unshift({
2568
- kind: "direction",
2569
- raw: "",
2570
- indent,
2571
- direction: op.direction,
2572
- dirty: true
2573
- });
2574
- }
2575
- } else {
2576
- work.header = work.header.replace(/\s+(TB|TD|BT|LR|RL)\s*$/i, "") + ` ${op.direction}`;
2577
- }
2578
- return reparse2(true);
2579
- }
2580
- case "addNode": {
2581
- const decl = {
2582
- id: op.node.id,
2583
- label: op.node.label,
2584
- shape: op.node.shape,
2585
- classes: [..._nullishCoalesce(op.node.classes, () => ( []))],
2586
- data: op.node.data
2587
- };
2588
- insertIntoGroup2(statements, [grammar.nodeStatement(decl, indent)], op.node.parentId, indent);
2589
- if (op.position) work.meta.layout[op.node.id] = op.position;
2590
- return reparse2(true);
2591
- }
2592
- case "removeNodes": {
2593
- const ids = new Set(op.ids);
2594
- filterInPlace2(statements, (s) => {
2595
- if (s.kind === "node") return !ids.has(s.decl.id);
2596
- if (s.kind === "edge") return !(ids.has(s.source.id) || ids.has(s.target.id));
2597
- if (s.kind === "style") return !ids.has(s.id);
2598
- if (s.kind === "class") {
2599
- s.ids = s.ids.filter((id) => !ids.has(id));
2600
- s.dirty = true;
2601
- return s.ids.length > 0;
2602
- }
2603
- return true;
2604
- });
2605
- for (const id of ids) {
2606
- const range = groupRange2(statements, id);
2607
- if (range) {
2608
- statements.splice(range.end, 1);
2609
- statements.splice(range.start, 1);
2610
- }
2611
- delete work.meta.layout[id];
2612
- delete work.meta.sizes[id];
2613
- }
2614
- return reparse2(true);
2615
- }
2616
- case "renameNode":
2617
- case "setNodeShape":
2618
- case "setNodeClasses":
2619
- case "setNodeData": {
2620
- const id = op.id;
2621
- let decl = findDecl(statements, id);
2622
- if (!decl) {
2623
- const node = doc.graph.nodes.find((n) => n.id === id);
2624
- const stmt = grammar.nodeStatement(
2625
- {
2626
- id,
2627
- label: _optionalChain([node, 'optionalAccess', _37 => _37.label]) !== id ? _optionalChain([node, 'optionalAccess', _38 => _38.label]) : void 0,
2628
- shape: _optionalChain([node, 'optionalAccess', _39 => _39.shape]) !== grammar.defaultShape ? _optionalChain([node, 'optionalAccess', _40 => _40.shape]) : void 0,
2629
- classes: []
2630
- },
2631
- indent
2632
- );
2633
- const first = statements.findIndex(
2634
- (s) => s.kind === "edge" && (s.source.id === id || s.target.id === id)
2635
- );
2636
- statements.splice(first === -1 ? statements.length : first, 0, stmt);
2637
- decl = findDecl(statements, id);
2638
- }
2639
- const target = decl.stmt;
2640
- if (op.type === "renameNode") decl.decl.label = op.label;
2641
- if (op.type === "setNodeShape") decl.decl.shape = op.shape;
2642
- if (op.type === "setNodeClasses") {
2643
- decl.decl.classes = [...op.classes];
2644
- filterInPlace2(statements, (s) => {
2645
- if (s.kind !== "class" || !s.ids.includes(id)) return true;
2646
- s.ids = s.ids.filter((x) => x !== id);
2647
- s.dirty = true;
2648
- return s.ids.length > 0;
2649
- });
2650
- }
2651
- if (op.type === "setNodeData") {
2652
- decl.decl.data = { ..._nullishCoalesce(decl.decl.data, () => ( {})), ...op.data };
2653
- if (target.kind === "node" && ("members" in op.data || "attributes" in op.data)) {
2654
- const fresh = grammar.nodeStatement(decl.decl, target.indent);
2655
- target.body = fresh.kind === "node" ? fresh.body : void 0;
2656
- }
2657
- }
2658
- target.dirty = true;
2659
- return reparse2(true);
2660
- }
2661
- case "setNodeStyles": {
2662
- filterInPlace2(statements, (s) => !(s.kind === "style" && s.id === op.id));
2663
- if (op.styles.length)
2664
- statements.push({
2665
- kind: "style",
2666
- raw: "",
2667
- indent,
2668
- id: op.id,
2669
- styles: [...op.styles],
2670
- dirty: true
2671
- });
2672
- return reparse2(true);
2673
- }
2674
- case "addEdge": {
2675
- const spec = {
2676
- ...grammar.defaultEdge,
2677
- ...op.edge.pattern ? { pattern: op.edge.pattern } : {},
2678
- ...op.edge.arrowStart ? { arrowStart: op.edge.arrowStart } : {},
2679
- ...op.edge.arrowEnd ? { arrowEnd: op.edge.arrowEnd } : {},
2680
- label: op.edge.label,
2681
- data: {
2682
- ..._nullishCoalesce(op.edge.data, () => ( {})),
2683
- synthetic: {
2684
- source: isSyntheticEndpoint(doc, op.edge.source),
2685
- target: isSyntheticEndpoint(doc, op.edge.target)
2686
- }
2687
- }
2688
- };
2689
- const stmt = grammar.edgeStatement(op.edge.source, op.edge.target, spec, indent);
2690
- const sp = parentOf(doc, op.edge.source);
2691
- const tp = parentOf(doc, op.edge.target);
2692
- insertIntoGroup2(statements, [stmt], sp && sp === tp ? sp : void 0, indent);
2693
- return reparse2(true);
2694
- }
2695
- case "removeEdges": {
2696
- const targets = new Set(op.ids.map((id) => edgeOrdinal(doc, id)).filter((n) => n >= 0));
2697
- let ordinal = 0;
2698
- filterInPlace2(statements, (s) => {
2699
- if (s.kind !== "edge") return true;
2700
- const keep = !targets.has(ordinal);
2701
- ordinal++;
2702
- return keep;
2703
- });
2704
- return reparse2(true);
2705
- }
2706
- case "setEdgeLabel":
2707
- case "setEdgeStyle":
2708
- case "reconnectEdge": {
2709
- const stmt = edgeStatementFor(statements, doc, op.id);
2710
- if (!stmt) return doc;
2711
- if (op.type === "setEdgeLabel") stmt.label = op.label || void 0;
2712
- if (op.type === "setEdgeStyle") {
2713
- if (op.pattern) stmt.pattern = op.pattern;
2714
- if (op.arrowStart) stmt.arrowStart = op.arrowStart;
2715
- if (op.arrowEnd) stmt.arrowEnd = op.arrowEnd;
2716
- }
2717
- if (op.type === "reconnectEdge") {
2718
- stmt.source = { id: op.source, classes: [] };
2719
- stmt.target = { id: op.target, classes: [] };
2720
- }
2721
- stmt.dirty = true;
2722
- return reparse2(true);
2723
- }
2724
- case "groupNodes": {
2725
- if (grammar.supportsGroups === false) return doc;
2726
- const { open, close } = grammar.groupStatements(op.groupId, op.label, indent);
2727
- const moved = [];
2728
- const set = new Set(op.nodeIds);
2729
- filterInPlace2(statements, (s) => {
2730
- if (s.kind === "node" && set.has(s.decl.id)) {
2731
- moved.push(reindent(s, indent + indent));
2732
- return false;
2733
- }
2734
- if (s.kind === "edge" && set.has(s.source.id) && set.has(s.target.id)) {
2735
- moved.push(reindent(s, indent + indent));
2736
- return false;
2737
- }
2738
- return true;
2739
- });
2740
- for (const id of op.nodeIds) {
2741
- if (!moved.some((s) => s.kind === "node" && s.decl.id === id)) {
2742
- moved.push(grammar.nodeStatement({ id, classes: [] }, indent + indent));
2743
- }
2744
- }
2745
- insertIntoGroup2(statements, [open, ...moved, close], op.parentId, indent);
2746
- return reparse2(true);
2747
- }
2748
- case "ungroup": {
2749
- const range = groupRange2(statements, op.groupId);
2750
- if (!range) return doc;
2751
- const inner = statements.slice(range.start + 1, range.end).map((s) => reindent(s, statements[range.start].indent));
2752
- statements.splice(
2753
- range.start,
2754
- range.end - range.start + 1,
2755
- ...inner.filter((s) => s.kind !== "direction")
2756
- );
2757
- delete work.meta.layout[op.groupId];
2758
- return reparse2(true);
2759
- }
2760
- case "renameGroup": {
2761
- const range = groupRange2(statements, op.id);
2762
- if (!range) return doc;
2763
- const open = statements[range.start];
2764
- open.label = op.label;
2765
- open.dirty = true;
2766
- return reparse2(true);
2767
- }
2768
- case "setGroupDirection": {
2769
- const range = groupRange2(statements, op.id);
2770
- if (!range) return doc;
2771
- const idx = statements.findIndex(
2772
- (s, i) => i > range.start && i < range.end && s.kind === "direction" && depthAt2(statements, i) === depthAt2(statements, range.start) + 1
2773
- );
2774
- if (op.direction) {
2775
- if (idx !== -1) {
2776
- const s = statements[idx];
2777
- s.direction = op.direction;
2778
- s.dirty = true;
2779
- } else {
2780
- const inner = statements[range.start].indent + indent;
2781
- statements.splice(range.start + 1, 0, {
2782
- kind: "direction",
2783
- raw: "",
2784
- indent: inner,
2785
- direction: op.direction,
2786
- dirty: true
2787
- });
2788
- }
2789
- } else if (idx !== -1) statements.splice(idx, 1);
2790
- return reparse2(true);
2791
- }
2792
- case "setNodeParent": {
2793
- for (const id of op.ids) {
2794
- const found = findDecl(statements, id);
2795
- let stmt;
2796
- if (found) {
2797
- statements.splice(statements.indexOf(found.stmt), 1);
2798
- stmt = found.stmt;
2799
- } else {
2800
- stmt = grammar.nodeStatement({ id, classes: [] }, indent);
2801
- }
2802
- insertIntoGroup2(statements, [stmt], op.parentId, indent);
2803
- }
2804
- return reparse2(true);
2805
- }
2806
- case "setClassDef": {
2807
- let found = false;
2808
- for (const s of statements) {
2809
- if (s.kind !== "classDef") continue;
2810
- if (s.names.length === 1 && s.names[0] === op.name) {
2811
- found = true;
2812
- if (op.styles) {
2813
- s.styles = [...op.styles];
2814
- s.dirty = true;
2815
- }
2816
- }
2817
- }
2818
- if (!op.styles)
2819
- filterInPlace2(
2820
- statements,
2821
- (s) => !(s.kind === "classDef" && s.names.length === 1 && s.names[0] === op.name)
2822
- );
2823
- else if (!found)
2824
- statements.push({
2825
- kind: "classDef",
2826
- raw: "",
2827
- indent,
2828
- names: [op.name],
2829
- styles: [...op.styles],
2830
- dirty: true
2831
- });
2832
- return reparse2(true);
2833
- }
2834
- default:
2835
- return doc;
2836
- }
2837
- }
2838
- function isSyntheticEndpoint(doc, id) {
2839
- const node = doc.graph.nodes.find((n) => n.id === id);
2840
- if (node) return !!_optionalChain([node, 'access', _41 => _41.data, 'optionalAccess', _42 => _42.synthetic]);
2841
- const m = /^(.+)_(start|end)$/.exec(id);
2842
- if (!m) return false;
2843
- return m[1] === "root" || doc.graph.groups.some((g) => g.id === m[1]);
2844
- }
2845
- function reindent(s, indent) {
2846
- const next = { ...s, indent };
2847
- if (s.kind === "raw") return s;
2848
- next.dirty = true;
2849
- if (s.kind === "node" && s.body) {
2850
- const delta = indent.length - s.indent.length;
2851
- next.body = s.body.map(
2852
- (l) => delta >= 0 ? " ".repeat(delta) + l : l.slice(Math.min(-delta, l.length - l.trimStart().length))
2853
- );
2854
- }
2855
- return next;
2856
- }
2857
- function findDecl(statements, id) {
2858
- for (const s of statements) {
2859
- if (s.kind === "node" && s.decl.id === id) return { stmt: s, decl: s.decl };
2860
- }
2861
- for (const s of statements) {
2862
- if (s.kind === "edge") {
2863
- if (s.source.id === id && (s.source.label !== void 0 || s.source.shape || s.source.classes.length))
2864
- return { stmt: s, decl: s.source };
2865
- if (s.target.id === id && (s.target.label !== void 0 || s.target.shape || s.target.classes.length))
2866
- return { stmt: s, decl: s.target };
2867
- }
2868
- }
2869
- return null;
2870
- }
2871
- function parentOf(doc, id) {
2872
- return _nullishCoalesce(_optionalChain([doc, 'access', _43 => _43.graph, 'access', _44 => _44.nodes, 'access', _45 => _45.find, 'call', _46 => _46((n) => n.id === id), 'optionalAccess', _47 => _47.parentId]), () => ( _optionalChain([doc, 'access', _48 => _48.graph, 'access', _49 => _49.groups, 'access', _50 => _50.find, 'call', _51 => _51((g) => g.id === id), 'optionalAccess', _52 => _52.parentId])));
2873
- }
2874
- function edgeOrdinal(doc, edgeId) {
2875
- return doc.graph.edges.findIndex((e) => e.id === edgeId);
2876
- }
2877
- function edgeStatementFor(statements, doc, edgeId) {
2878
- const ordinal = edgeOrdinal(doc, edgeId);
2879
- if (ordinal < 0) return null;
2880
- let n = 0;
2881
- for (const s of statements) {
2882
- if (s.kind !== "edge") continue;
2883
- if (n === ordinal) return s;
2884
- n++;
2885
- }
2886
- return null;
2887
- }
2888
- function depthAt2(statements, index) {
2889
- let depth = 0;
2890
- for (let i = 0; i < index; i++) {
2891
- const s = statements[i];
2892
- if (s.kind === "groupOpen") depth++;
2893
- else if (s.kind === "groupClose") depth = Math.max(0, depth - 1);
2894
- }
2895
- return depth;
2896
- }
2897
- function groupRange2(statements, groupId) {
2898
- const start = statements.findIndex((s) => s.kind === "groupOpen" && s.id === groupId);
2899
- if (start === -1) return null;
2900
- let depth = 0;
2901
- for (let i = start; i < statements.length; i++) {
2902
- const s = statements[i];
2903
- if (s.kind === "groupOpen") depth++;
2904
- else if (s.kind === "groupClose") {
2905
- depth--;
2906
- if (depth === 0) return { start, end: i };
2907
- }
2908
- }
2909
- return { start, end: statements.length };
2910
- }
2911
- function insertIntoGroup2(statements, block, groupId, indent) {
2912
- const range = groupId ? groupRange2(statements, groupId) : null;
2913
- if (!range) {
2914
- statements.push(...block);
2915
- return;
2916
- }
2917
- const open = statements[range.start];
2918
- const inner = open.indent + indent;
2919
- const adjusted = block.map(
2920
- (s) => s.kind === "raw" ? s : reindent(s, inner + s.indent.slice(indent.length))
2921
- );
2922
- statements.splice(range.end, 0, ...adjusted);
2923
- }
2924
- function filterInPlace2(arr, keep) {
2925
- let j = 0;
2926
- for (let i = 0; i < arr.length; i++) if (keep(arr[i])) arr[j++] = arr[i];
2927
- arr.length = j;
2928
- }
2929
- function setTitle(lines, title) {
2930
- const out = [...lines];
2931
- const hasFm = out[0] !== void 0 && /^---\s*$/.test(out[0]);
2932
- if (!hasFm) return title === void 0 ? out : ["---", `title: ${title}`, "---", ...out];
2933
- const close = out.findIndex((l, i) => i > 0 && /^---\s*$/.test(l));
2934
- const end = close === -1 ? out.length : close;
2935
- const idx = out.findIndex((l, i) => i > 0 && i < end && /^title\s*:/.test(l));
2936
- if (title === void 0) {
2937
- if (idx !== -1) out.splice(idx, 1);
2938
- if (out.length >= 2 && /^---\s*$/.test(out[1])) out.splice(0, 2);
2939
- return out;
2940
- }
2941
- if (idx !== -1) out[idx] = `title: ${title}`;
2942
- else out.splice(end, 0, `title: ${title}`);
2943
- return out;
2944
- }
2945
- function setFrontmatterTitle2(lines, title) {
2946
- return setTitle(lines, title);
2947
- }
2948
- function createLineAdapter(grammar) {
2949
- return {
2950
- family: grammar.family,
2951
- tier: "editable",
2952
- parse: (source, ctx) => parseLineDocument(grammar, source, ctx),
2953
- serialize: (doc) => serializeLineDocument(grammar, doc),
2954
- apply: (doc, op) => applyLineEdit(grammar, doc, op)
2955
- };
2956
- }
2957
- function joinBraceBlocks(lines, extraBlock) {
2958
- const out = [];
2959
- let i = 0;
2960
- while (i < lines.length) {
2961
- const line = lines[i];
2962
- if (extraBlock && extraBlock.open.test(line)) {
2963
- let cur = line;
2964
- let j = i + 1;
2965
- while (j < lines.length && !extraBlock.close.test(lines[j])) {
2966
- cur += "\n" + lines[j];
2967
- j++;
2968
- }
2969
- if (j < lines.length) {
2970
- cur += "\n" + lines[j];
2971
- j++;
2972
- }
2973
- out.push(cur);
2974
- i = j;
2975
- continue;
2976
- }
2977
- const opens = (_nullishCoalesce(line.match(/\{/g), () => ( []))).length;
2978
- const closes = (_nullishCoalesce(line.match(/\}/g), () => ( []))).length;
2979
- if (opens > closes && /\{\s*$/.test(line)) {
2980
- let depth = opens - closes;
2981
- let j = i + 1;
2982
- const body = [];
2983
- let isSimpleBody = true;
2984
- while (j < lines.length && depth > 0) {
2985
- const l = lines[j];
2986
- depth += (_nullishCoalesce(l.match(/\{/g), () => ( []))).length - (_nullishCoalesce(l.match(/\}/g), () => ( []))).length;
2987
- if (depth > 0) body.push(l);
2988
- if (/-->|<\|--|\*--|o--|\.\.>|--\|>|\|\|--|\}o--|\}\|--|^\s*(state|class|namespace|note|direction)\b/.test(
2989
- l
2990
- ) && depth > 0)
2991
- isSimpleBody = false;
2992
- j++;
2993
- }
2994
- if (isSimpleBody && depth === 0) {
2995
- out.push([line, ...body, lines[j - 1]].join("\n"));
2996
- i = j;
2997
- continue;
2998
- }
2999
- }
3000
- out.push(line);
3001
- i++;
3002
- }
3003
- return out;
3004
- }
3005
-
3006
- // src/diagram/passthrough.ts
3007
- function createPassthroughAdapter(family, tier = "render-only") {
3008
- const adapter = {
3009
- family,
3010
- tier,
3011
- parse(source, ctx) {
3012
- const title = typeof _optionalChain([ctx, 'access', _53 => _53.preamble, 'access', _54 => _54.frontmatter, 'optionalAccess', _55 => _55.title]) === "string" ? ctx.preamble.frontmatter.title : void 0;
3013
- return {
3014
- family,
3015
- tier,
3016
- source,
3017
- preamble: ctx.preamble,
3018
- header: ctx.header,
3019
- trailing: ctx.trailing,
3020
- eol: ctx.eol,
3021
- graph: { direction: "TB", nodes: [], edges: [], groups: [], classDefs: {}, title },
3022
- meta: ctx.meta,
3023
- metaCarrier: ctx.metaCarrier,
3024
- body: { lines: ctx.bodyLines },
3025
- diagnostics: [],
3026
- dirty: false
3027
- };
3028
- },
3029
- serialize(doc) {
3030
- return assembleDocument(doc, doc.body.lines, " ");
3031
- },
3032
- apply(doc, op) {
3033
- const next = { ...doc, meta: { ...doc.meta } };
3034
- switch (op.type) {
3035
- case "setViewport":
3036
- next.meta.viewport = op.viewport;
3037
- break;
3038
- case "setMetaExt":
3039
- next.meta.ext = { ..._nullishCoalesce(next.meta.ext, () => ( {})), [op.key]: op.value };
3040
- break;
3041
- case "moveNodes":
3042
- next.meta.layout = { ..._nullishCoalesce(next.meta.layout, () => ( {})) };
3043
- for (const { id, position } of op.moves) next.meta.layout[id] = position;
3044
- break;
3045
- case "setTitle":
3046
- next.preamble = {
3047
- ...next.preamble,
3048
- lines: setFrontmatterTitle2(next.preamble.lines, op.title)
3049
- };
3050
- next.dirty = true;
3051
- break;
3052
- default:
3053
- return doc;
3054
- }
3055
- next.source = adapter.serialize(next);
3056
- return next;
3057
- }
3058
- };
3059
- return adapter;
3060
- }
3061
-
3062
- // src/diagram/lines-grammar/state.ts
3063
- var ID = String.raw`[A-Za-z0-9_À-￿.-]+`;
3064
- var TRANSITION = new RegExp(
3065
- String.raw`^(\[\*\]|${ID}(?::::${ID})?)\s*-->\s*(\[\*\]|${ID}(?::::${ID})?)\s*(?::\s*(.*))?$`
3066
- );
3067
- var STATE_SHAPES = [
3068
- { name: "rect", title: "State" },
3069
- { name: "fork", title: "Fork" },
3070
- { name: "join", title: "Join" },
3071
- { name: "choice", title: "Choice" }
3072
- ];
3073
- function splitClasses(token) {
3074
- const [id, ...classes] = token.split(":::");
3075
- return { id, classes };
3076
- }
3077
- var stateGrammar = {
3078
- family: "state",
3079
- defaultShape: "rect",
3080
- directionAsStatement: true,
3081
- defaultEdge: { arrowStart: "none", arrowEnd: "arrow_barb", pattern: "solid" },
3082
- joinLines(lines) {
3083
- return joinBraceBlocks(lines, {
3084
- open: /^\s*note\s+(left|right)\s+of\s+\S+\s*$/i,
3085
- close: /^\s*end\s+note\s*$/i
3086
- }).flatMap((logical) => {
3087
- if (/^\s*state\b.*\{\s*$/.test(logical.split("\n")[0]) && logical.includes("\n"))
3088
- return logical.split("\n");
3089
- return [logical];
3090
- });
3091
- },
3092
- parseLine(line) {
3093
- const indent = line.match(/^\s*/)[0];
3094
- const text = line.trim();
3095
- if (text === "" || text.startsWith("%%") || text.startsWith("note") || text === "--")
3096
- return { kind: "raw", raw: line, indent };
3097
- if (text === "}") return { kind: "groupClose", raw: line, indent };
3098
- let m;
3099
- if (m = /^direction\s+(TB|TD|BT|LR|RL)\s*$/i.exec(text))
3100
- return { kind: "direction", raw: line, indent, direction: m[1].toUpperCase() };
3101
- if (m = /^classDef\s+(\S+)\s+(.*)$/.exec(text))
3102
- return {
3103
- kind: "classDef",
3104
- raw: line,
3105
- indent,
3106
- names: m[1].split(","),
3107
- styles: m[2].split(",").map((s) => s.trim()).filter(Boolean)
3108
- };
3109
- if (m = /^class\s+(\S+)\s+(\S+)\s*$/.exec(text))
3110
- return { kind: "class", raw: line, indent, ids: m[1].split(","), className: m[2] };
3111
- if (m = /^style\s+(\S+)\s+(.*)$/.exec(text))
3112
- return {
3113
- kind: "style",
3114
- raw: line,
3115
- indent,
3116
- id: m[1],
3117
- styles: m[2].split(",").map((s) => s.trim()).filter(Boolean)
3118
- };
3119
- if (m = new RegExp(String.raw`^state\s+(?:"([^"]*)"\s+as\s+)?(${ID})\s*\{\s*$`).exec(text)) {
3120
- return { kind: "groupOpen", raw: line, indent, id: m[2], label: m[1] };
3121
- }
3122
- if (m = new RegExp(
3123
- String.raw`^state\s+(?:"([^"]*)"\s+as\s+)?(${ID})(?::::(${ID}))?(?:\s+<<(fork|join|choice|end)>>)?\s*$`
3124
- ).exec(text)) {
3125
- const decl = { id: m[2], label: m[1], classes: m[3] ? [m[3]] : [] };
3126
- if (m[4]) decl.shape = m[4] === "end" ? "stateEnd" : m[4];
3127
- return { kind: "node", raw: line, indent, decl };
3128
- }
3129
- if (m = TRANSITION.exec(text)) {
3130
- const s = splitClasses(m[1]);
3131
- const t = splitClasses(m[2]);
3132
- return {
3133
- kind: "edge",
3134
- raw: line,
3135
- indent,
3136
- source: { id: s.id, classes: s.classes },
3137
- target: { id: t.id, classes: t.classes },
3138
- label: _optionalChain([m, 'access', _56 => _56[3], 'optionalAccess', _57 => _57.trim, 'call', _58 => _58()]) || void 0,
3139
- arrowStart: "none",
3140
- arrowEnd: "arrow_barb",
3141
- pattern: "solid"
3142
- };
3143
- }
3144
- if (m = new RegExp(String.raw`^(${ID})\s*:\s*(.*)$`).exec(text)) {
3145
- return {
3146
- kind: "node",
3147
- raw: line,
3148
- indent,
3149
- decl: { id: m[1], classes: [], data: { descriptions: [m[2].trim()] } }
3150
- };
3151
- }
3152
- if (m = new RegExp(String.raw`^(${ID})(?::::(${ID}))?\s*$`).exec(text)) {
3153
- return { kind: "node", raw: line, indent, decl: { id: m[1], classes: m[2] ? [m[2]] : [] } };
3154
- }
3155
- return { kind: "raw", raw: line, indent };
3156
- },
3157
- formatStatement(stmt) {
3158
- switch (stmt.kind) {
3159
- case "node": {
3160
- const d = stmt.decl;
3161
- const descriptions = _optionalChain([d, 'access', _59 => _59.data, 'optionalAccess', _60 => _60.descriptions]);
3162
- if (_optionalChain([descriptions, 'optionalAccess', _61 => _61.length]) && d.label === void 0 && !d.shape) {
3163
- return `${stmt.indent}${d.id} : ${descriptions[0]}`;
3164
- }
3165
- let out = `${stmt.indent}state `;
3166
- if (d.label !== void 0 && d.label !== d.id) out += `"${d.label.replace(/"/g, "'")}" as `;
3167
- out += d.id;
3168
- for (const c of d.classes) out += `:::${c}`;
3169
- if (d.shape && d.shape !== "rect")
3170
- out += ` <<${d.shape === "stateEnd" ? "end" : d.shape}>>`;
3171
- return out;
3172
- }
3173
- case "edge": {
3174
- const fmt = (n) => n.id + n.classes.map((c) => `:::${c}`).join("");
3175
- const src = fmt(stmt.source);
3176
- const tgt = fmt(stmt.target);
3177
- return `${stmt.indent}${src} --> ${tgt}${stmt.label ? ` : ${stmt.label}` : ""}`;
3178
- }
3179
- case "groupOpen":
3180
- return `${stmt.indent}state ${stmt.label !== void 0 && stmt.label !== stmt.id ? `"${stmt.label}" as ` : ""}${stmt.id} {`;
3181
- case "groupClose":
3182
- return `${stmt.indent}}`;
3183
- case "direction":
3184
- return `${stmt.indent}direction ${stmt.direction}`;
3185
- case "classDef":
3186
- return `${stmt.indent}classDef ${stmt.names.join(",")} ${stmt.styles.join(",")}`;
3187
- case "class":
3188
- return `${stmt.indent}class ${stmt.ids.join(",")} ${stmt.className}`;
3189
- case "style":
3190
- return `${stmt.indent}style ${stmt.id} ${stmt.styles.join(",")}`;
3191
- default:
3192
- return stmt.raw;
3193
- }
3194
- },
3195
- nodeStatement(decl, indent) {
3196
- return {
3197
- kind: "node",
3198
- raw: "",
3199
- indent,
3200
- decl: { ...decl, classes: [...decl.classes] },
3201
- dirty: true
3202
- };
3203
- },
3204
- edgeStatement(source, target, spec, indent) {
3205
- const synthetic = _nullishCoalesce(_optionalChain([spec, 'access', _62 => _62.data, 'optionalAccess', _63 => _63.synthetic]), () => ( {}));
3206
- const endpoint = (id, isSynthetic) => isSynthetic ? { id: "[*]", classes: [] } : { id, classes: [] };
3207
- return {
3208
- kind: "edge",
3209
- raw: "",
3210
- indent,
3211
- source: endpoint(source, synthetic.source),
3212
- target: endpoint(target, synthetic.target),
3213
- label: spec.label,
3214
- arrowStart: "none",
3215
- arrowEnd: "arrow_barb",
3216
- pattern: "solid",
3217
- dirty: true
3218
- };
3219
- },
3220
- groupStatements(id, label, indent) {
3221
- return {
3222
- open: { kind: "groupOpen", raw: "", indent, id, label, dirty: true },
3223
- close: { kind: "groupClose", raw: `${indent}}`, indent }
3224
- };
3225
- },
3226
- headerDirection(_header, statements) {
3227
- const top = statements.find((s) => s.kind === "direction");
3228
- return top && top.kind === "direction" ? top.direction : "TB";
3229
- },
3230
- resolveEndpoint(id, stack, role) {
3231
- if (id !== "[*]") return null;
3232
- const scope = _nullishCoalesce(stack[stack.length - 1], () => ( "root"));
3233
- return role === "source" ? { id: `${scope}_start`, shape: "stateStart", label: "", synthetic: true } : { id: `${scope}_end`, shape: "stateEnd", label: "", synthetic: true };
3234
- }
3235
- };
3236
-
3237
- // src/diagram/lines-grammar/class.ts
3238
- var ID2 = String.raw`[A-Za-z0-9_À-￿.~-]+`;
3239
- var CLASS_RELATIONS = [
3240
- {
3241
- token: "<|--",
3242
- arrowStart: "extension",
3243
- arrowEnd: "none",
3244
- pattern: "solid",
3245
- title: "Inheritance"
3246
- },
3247
- {
3248
- token: "--|>",
3249
- arrowStart: "none",
3250
- arrowEnd: "extension",
3251
- pattern: "solid",
3252
- title: "Inheritance (reversed)"
3253
- },
3254
- {
3255
- token: "<|..",
3256
- arrowStart: "extension",
3257
- arrowEnd: "none",
3258
- pattern: "dotted",
3259
- title: "Realization"
3260
- },
3261
- {
3262
- token: "..|>",
3263
- arrowStart: "none",
3264
- arrowEnd: "extension",
3265
- pattern: "dotted",
3266
- title: "Realization (reversed)"
3267
- },
3268
- {
3269
- token: "*--",
3270
- arrowStart: "composition",
3271
- arrowEnd: "none",
3272
- pattern: "solid",
3273
- title: "Composition"
3274
- },
3275
- {
3276
- token: "--*",
3277
- arrowStart: "none",
3278
- arrowEnd: "composition",
3279
- pattern: "solid",
3280
- title: "Composition (reversed)"
3281
- },
3282
- {
3283
- token: "o--",
3284
- arrowStart: "aggregation",
3285
- arrowEnd: "none",
3286
- pattern: "solid",
3287
- title: "Aggregation"
3288
- },
3289
- {
3290
- token: "--o",
3291
- arrowStart: "none",
3292
- arrowEnd: "aggregation",
3293
- pattern: "solid",
3294
- title: "Aggregation (reversed)"
3295
- },
3296
- {
3297
- token: "<--",
3298
- arrowStart: "dependency",
3299
- arrowEnd: "none",
3300
- pattern: "solid",
3301
- title: "Association (reversed)"
3302
- },
3303
- {
3304
- token: "-->",
3305
- arrowStart: "none",
3306
- arrowEnd: "dependency",
3307
- pattern: "solid",
3308
- title: "Association"
3309
- },
3310
- {
3311
- token: "<..",
3312
- arrowStart: "dependency",
3313
- arrowEnd: "none",
3314
- pattern: "dotted",
3315
- title: "Dependency (reversed)"
3316
- },
3317
- {
3318
- token: "..>",
3319
- arrowStart: "none",
3320
- arrowEnd: "dependency",
3321
- pattern: "dotted",
3322
- title: "Dependency"
3323
- },
3324
- { token: "()--", arrowStart: "lollipop", arrowEnd: "none", pattern: "solid", title: "Lollipop" },
3325
- {
3326
- token: "--()",
3327
- arrowStart: "none",
3328
- arrowEnd: "lollipop",
3329
- pattern: "solid",
3330
- title: "Lollipop (reversed)"
3331
- },
3332
- { token: "--", arrowStart: "none", arrowEnd: "none", pattern: "solid", title: "Link (solid)" },
3333
- { token: "..", arrowStart: "none", arrowEnd: "none", pattern: "dotted", title: "Link (dashed)" }
3334
- ];
3335
- var REL_TOKENS = CLASS_RELATIONS.map((r) => r.token.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join(
3336
- "|"
3337
- );
3338
- var RELATION = new RegExp(
3339
- String.raw`^(${ID2})(?:\["([^"]*)"\])?(?::::(${ID2}))?\s*(?:"([^"]*)"\s*)?(${REL_TOKENS})\s*(?:"([^"]*)"\s*)?(${ID2})(?:\["([^"]*)"\])?(?::::(${ID2}))?\s*(?::\s*(.*))?$`
3340
- );
3341
- function relationFor(arrowStart, arrowEnd, pattern) {
3342
- return _nullishCoalesce(CLASS_RELATIONS.find(
3343
- (r) => r.arrowStart === arrowStart && r.arrowEnd === arrowEnd && r.pattern === pattern
3344
- ), () => ( CLASS_RELATIONS.find((r) => r.token === "-->")));
3345
- }
3346
- function parseMembers(bodyLines) {
3347
- const out = [];
3348
- for (const line of bodyLines) {
3349
- const t = line.trim();
3350
- if (!t || t === "}" || t.startsWith("%%") || /^<<.*>>$/.test(t)) continue;
3351
- const vis = _optionalChain([/^[+\-#~]/, 'access', _64 => _64.exec, 'call', _65 => _65(t), 'optionalAccess', _66 => _66[0]]);
3352
- out.push({ raw: t, visibility: vis, kind: /\(.*\)/.test(t) ? "method" : "attribute" });
3353
- }
3354
- return out;
3355
- }
3356
- function annotationsOf(bodyLines) {
3357
- return bodyLines.map((l) => l.trim()).filter((t) => /^<<.*>>$/.test(t)).map((t) => t.slice(2, -2));
3358
- }
3359
- var classGrammar = {
3360
- family: "class",
3361
- defaultShape: "classBox",
3362
- directionAsStatement: true,
3363
- defaultEdge: { arrowStart: "none", arrowEnd: "dependency", pattern: "solid" },
3364
- joinLines(lines) {
3365
- return joinBraceBlocks(lines, { open: /^\s*note\s+(for\s+\S+\s+)?"[^"]*$/i, close: /"\s*$/ });
3366
- },
3367
- parseLine(logical) {
3368
- const [line, ...bodyRest] = logical.split("\n");
3369
- const indent = line.match(/^\s*/)[0];
3370
- const text = line.trim();
3371
- if (text === "" || text.startsWith("%%") || /^(note|click|link|callback|<<)/.test(text))
3372
- return { kind: "raw", raw: logical, indent };
3373
- if (text === "}") return { kind: "groupClose", raw: line, indent };
3374
- let m;
3375
- if (m = /^direction\s+(TB|TD|BT|LR|RL)\s*$/i.exec(text))
3376
- return { kind: "direction", raw: line, indent, direction: m[1].toUpperCase() };
3377
- if (m = /^classDef\s+(\S+)\s+(.*)$/.exec(text))
3378
- return {
3379
- kind: "classDef",
3380
- raw: line,
3381
- indent,
3382
- names: m[1].split(","),
3383
- styles: m[2].split(",").map((s) => s.trim()).filter(Boolean)
3384
- };
3385
- if (m = /^cssClass\s+"([^"]+)"\s+(\S+)\s*$/.exec(text))
3386
- return {
3387
- kind: "class",
3388
- raw: line,
3389
- indent,
3390
- ids: m[1].split(",").map((s) => s.trim()),
3391
- className: m[2]
3392
- };
3393
- if (m = /^style\s+(\S+)\s+(.*)$/.exec(text))
3394
- return {
3395
- kind: "style",
3396
- raw: line,
3397
- indent,
3398
- id: m[1],
3399
- styles: m[2].split(",").map((s) => s.trim()).filter(Boolean)
3400
- };
3401
- if (m = new RegExp(String.raw`^namespace\s+(${ID2})\s*\{\s*$`).exec(text))
3402
- return { kind: "groupOpen", raw: line, indent, id: m[1] };
3403
- if (m = new RegExp(
3404
- String.raw`^class\s+(${ID2})(?:\["([^"]*)"\])?(?::::(${ID2}))?\s*(\{)?\s*$`
3405
- ).exec(text)) {
3406
- const decl = { id: m[1], label: m[2], classes: m[3] ? [m[3]] : [] };
3407
- if (m[4] && bodyRest.length) {
3408
- decl.data = { members: parseMembers(bodyRest), annotations: annotationsOf(bodyRest) };
3409
- return { kind: "node", raw: line, indent, decl, body: bodyRest };
3410
- }
3411
- if (m[4] && !bodyRest.length) {
3412
- return { kind: "raw", raw: line, indent };
3413
- }
3414
- return { kind: "node", raw: line, indent, decl };
3415
- }
3416
- if (m = RELATION.exec(text)) {
3417
- const rel = CLASS_RELATIONS.find((r) => r.token === m[5]);
3418
- return {
3419
- kind: "edge",
3420
- raw: line,
3421
- indent,
3422
- source: { id: m[1], label: m[2], classes: m[3] ? [m[3]] : [] },
3423
- target: { id: m[7], label: m[8], classes: m[9] ? [m[9]] : [] },
3424
- label: _optionalChain([m, 'access', _67 => _67[10], 'optionalAccess', _68 => _68.trim, 'call', _69 => _69()]) || void 0,
3425
- arrowStart: rel.arrowStart,
3426
- arrowEnd: rel.arrowEnd,
3427
- pattern: rel.pattern,
3428
- data: { cardinalityStart: m[4], cardinalityEnd: m[6] }
3429
- };
3430
- }
3431
- if (m = new RegExp(String.raw`^(${ID2})\s*:\s*(.+)$`).exec(text)) {
3432
- return {
3433
- kind: "node",
3434
- raw: line,
3435
- indent,
3436
- decl: { id: m[1], classes: [], data: { members: parseMembers([m[2]]) } }
3437
- };
3438
- }
3439
- return { kind: "raw", raw: logical, indent };
3440
- },
3441
- formatStatement(stmt) {
3442
- switch (stmt.kind) {
3443
- case "node": {
3444
- const d = stmt.decl;
3445
- const members = _optionalChain([d, 'access', _70 => _70.data, 'optionalAccess', _71 => _71.members]);
3446
- if (!stmt.body && _optionalChain([members, 'optionalAccess', _72 => _72.length]) === 1 && d.label === void 0 && !d.classes.length && stmt.raw.includes(" : ")) {
3447
- return `${stmt.indent}${d.id} : ${members[0].raw}`;
3448
- }
3449
- let out = `${stmt.indent}class ${d.id}`;
3450
- if (d.label !== void 0 && d.label !== d.id) out += `["${d.label.replace(/"/g, "'")}"]`;
3451
- for (const c of d.classes) out += `:::${c}`;
3452
- if (stmt.body) out += " {";
3453
- return out;
3454
- }
3455
- case "edge": {
3456
- const rel = relationFor(stmt.arrowStart, stmt.arrowEnd, stmt.pattern);
3457
- const cs = _optionalChain([stmt, 'access', _73 => _73.data, 'optionalAccess', _74 => _74.cardinalityStart]);
3458
- const ce = _optionalChain([stmt, 'access', _75 => _75.data, 'optionalAccess', _76 => _76.cardinalityEnd]);
3459
- const fmt = (n) => n.id + (n.label !== void 0 ? `["${n.label}"]` : "") + n.classes.map((c) => `:::${c}`).join("");
3460
- return `${stmt.indent}${fmt(stmt.source)} ${cs ? `"${cs}" ` : ""}${rel.token} ${ce ? `"${ce}" ` : ""}${fmt(stmt.target)}${stmt.label ? ` : ${stmt.label}` : ""}`;
3461
- }
3462
- case "groupOpen":
3463
- return `${stmt.indent}namespace ${stmt.id} {`;
3464
- case "groupClose":
3465
- return `${stmt.indent}}`;
3466
- case "direction":
3467
- return `${stmt.indent}direction ${stmt.direction}`;
3468
- case "classDef":
3469
- return `${stmt.indent}classDef ${stmt.names.join(",")} ${stmt.styles.join(",")}`;
3470
- case "class":
3471
- return `${stmt.indent}cssClass "${stmt.ids.join(",")}" ${stmt.className}`;
3472
- case "style":
3473
- return `${stmt.indent}style ${stmt.id} ${stmt.styles.join(",")}`;
3474
- default:
3475
- return stmt.raw;
3476
- }
3477
- },
3478
- nodeStatement(decl, indent) {
3479
- const members = _optionalChain([decl, 'access', _77 => _77.data, 'optionalAccess', _78 => _78.members]);
3480
- const body = _optionalChain([members, 'optionalAccess', _79 => _79.length]) ? [...members.map((m) => `${indent} ${m.raw}`), `${indent}}`] : void 0;
3481
- return {
3482
- kind: "node",
3483
- raw: "",
3484
- indent,
3485
- decl: { ...decl, classes: [...decl.classes] },
3486
- body,
3487
- dirty: true
3488
- };
3489
- },
3490
- edgeStatement(source, target, spec, indent) {
3491
- return {
3492
- kind: "edge",
3493
- raw: "",
3494
- indent,
3495
- source: { id: source, classes: [] },
3496
- target: { id: target, classes: [] },
3497
- label: spec.label,
3498
- arrowStart: spec.arrowStart,
3499
- arrowEnd: spec.arrowEnd,
3500
- pattern: spec.pattern,
3501
- data: spec.data,
3502
- dirty: true
3503
- };
3504
- },
3505
- groupStatements(id, _label, indent) {
3506
- return {
3507
- open: { kind: "groupOpen", raw: "", indent, id, dirty: true },
3508
- close: { kind: "groupClose", raw: `${indent}}`, indent }
3509
- };
3510
- },
3511
- headerDirection(_header, statements) {
3512
- const top = statements.find((s) => s.kind === "direction");
3513
- return top && top.kind === "direction" ? top.direction : "TB";
3514
- }
3515
- };
3516
-
3517
- // src/diagram/lines-grammar/er.ts
3518
- var ID3 = String.raw`[A-Za-z0-9_À-￿-]+|"[^"]+"`;
3519
- var ER_CARDINALITIES = [
3520
- { token: "|o", head: "zero_or_one", side: "left", title: "Zero or one" },
3521
- { token: "||", head: "only_one", side: "left", title: "Exactly one" },
3522
- { token: "}o", head: "zero_or_more", side: "left", title: "Zero or more" },
3523
- { token: "}|", head: "one_or_more", side: "left", title: "One or more" },
3524
- { token: "o|", head: "zero_or_one", side: "right", title: "Zero or one" },
3525
- { token: "||", head: "only_one", side: "right", title: "Exactly one" },
3526
- { token: "o{", head: "zero_or_more", side: "right", title: "Zero or more" },
3527
- { token: "|{", head: "one_or_more", side: "right", title: "One or more" }
3528
- ];
3529
- var LEFT = {
3530
- "|o": "zero_or_one",
3531
- "||": "only_one",
3532
- "}o": "zero_or_more",
3533
- "}|": "one_or_more"
3534
- };
3535
- var RIGHT = {
3536
- "o|": "zero_or_one",
3537
- "||": "only_one",
3538
- "o{": "zero_or_more",
3539
- "|{": "one_or_more"
3540
- };
3541
- var LEFT_TOKEN = {
3542
- zero_or_one: "|o",
3543
- only_one: "||",
3544
- zero_or_more: "}o",
3545
- one_or_more: "}|"
3546
- };
3547
- var RIGHT_TOKEN = {
3548
- zero_or_one: "o|",
3549
- only_one: "||",
3550
- zero_or_more: "o{",
3551
- one_or_more: "|{"
3552
- };
3553
- var RELATION2 = new RegExp(
3554
- String.raw`^(${ID3})(?:\[([^\]]*)\])?(?::::([\w-]+))?\s+(\|o|\|\||\}o|\}\|)(--|\.\.|\.-|-\.)(o\||\|\||o\{|\|\{)\s+(${ID3})(?:\[([^\]]*)\])?(?::::([\w-]+))?\s*:\s*(.*)$`
3555
- );
3556
- function parseAttributes(bodyLines) {
3557
- const out = [];
3558
- for (const line of bodyLines) {
3559
- const t = line.trim();
3560
- if (!t || t === "}" || t.startsWith("%%")) continue;
3561
- const m = /^(\S+)\s+(\S+)((?:\s+(?:PK|FK|UK)(?:\s*,\s*(?:PK|FK|UK))*)?)\s*(?:"([^"]*)")?\s*$/.exec(t);
3562
- if (m) {
3563
- out.push({
3564
- raw: t,
3565
- type: m[1],
3566
- name: m[2],
3567
- keys: (_nullishCoalesce(m[3], () => ( ""))).split(/[\s,]+/).filter(Boolean),
3568
- comment: m[4]
3569
- });
3570
- } else {
3571
- out.push({ raw: t, type: "", name: t, keys: [] });
3572
- }
3573
- }
3574
- return out;
3575
- }
3576
- function unq(id) {
3577
- return id.startsWith('"') && id.endsWith('"') ? id.slice(1, -1) : id;
3578
- }
3579
- function fmtId(id) {
3580
- return /[\s]/.test(id) ? `"${id}"` : id;
3581
- }
3582
- var erGrammar = {
3583
- family: "er",
3584
- defaultShape: "erBox",
3585
- directionAsStatement: true,
3586
- supportsGroups: false,
3587
- defaultEdge: { arrowStart: "only_one", arrowEnd: "zero_or_more", pattern: "solid", label: "has" },
3588
- joinLines(lines) {
3589
- return joinBraceBlocks(lines);
3590
- },
3591
- parseLine(logical) {
3592
- const [line, ...bodyRest] = logical.split("\n");
3593
- const indent = line.match(/^\s*/)[0];
3594
- const text = line.trim();
3595
- if (text === "" || text.startsWith("%%")) return { kind: "raw", raw: logical, indent };
3596
- let m;
3597
- if (m = /^direction\s+(TB|TD|BT|LR|RL)\s*$/i.exec(text))
3598
- return { kind: "direction", raw: line, indent, direction: m[1].toUpperCase() };
3599
- if (m = /^classDef\s+(\S+)\s+(.*)$/.exec(text))
3600
- return {
3601
- kind: "classDef",
3602
- raw: line,
3603
- indent,
3604
- names: m[1].split(","),
3605
- styles: m[2].split(",").map((s) => s.trim()).filter(Boolean)
3606
- };
3607
- if (m = /^class\s+(\S+)\s+(\S+)\s*$/.exec(text))
3608
- return { kind: "class", raw: line, indent, ids: m[1].split(","), className: m[2] };
3609
- if (m = /^style\s+(\S+)\s+(.*)$/.exec(text))
3610
- return {
3611
- kind: "style",
3612
- raw: line,
3613
- indent,
3614
- id: m[1],
3615
- styles: m[2].split(",").map((s) => s.trim()).filter(Boolean)
3616
- };
3617
- if (m = RELATION2.exec(text)) {
3618
- const line_ = m[5];
3619
- return {
3620
- kind: "edge",
3621
- raw: line,
3622
- indent,
3623
- source: { id: unq(m[1]), label: m[2], classes: m[3] ? [m[3]] : [] },
3624
- target: { id: unq(m[7]), label: m[8], classes: m[9] ? [m[9]] : [] },
3625
- label: unq(m[10].trim()),
3626
- arrowStart: LEFT[m[4]],
3627
- arrowEnd: RIGHT[m[6]],
3628
- pattern: line_ === "--" ? "solid" : "dotted",
3629
- data: { identifying: line_ === "--" }
3630
- };
3631
- }
3632
- if (m = new RegExp(String.raw`^(${ID3})(?:\[([^\]]*)\])?(?::::([\w-]+))?\s*(\{)?\s*$`).exec(text)) {
3633
- const decl = {
3634
- id: unq(m[1]),
3635
- label: m[2] !== void 0 ? unq(m[2]) : void 0,
3636
- classes: m[3] ? [m[3]] : []
3637
- };
3638
- if (m[4]) {
3639
- decl.data = { attributes: parseAttributes(bodyRest) };
3640
- return { kind: "node", raw: line, indent, decl, body: bodyRest };
3641
- }
3642
- return { kind: "node", raw: line, indent, decl };
3643
- }
3644
- return { kind: "raw", raw: logical, indent };
3645
- },
3646
- formatStatement(stmt) {
3647
- switch (stmt.kind) {
3648
- case "node": {
3649
- const d = stmt.decl;
3650
- let out = `${stmt.indent}${fmtId(d.id)}`;
3651
- if (d.label !== void 0 && d.label !== d.id) out += `["${d.label}"]`;
3652
- for (const c of d.classes) out += `:::${c}`;
3653
- if (stmt.body) out += " {";
3654
- return out;
3655
- }
3656
- case "edge": {
3657
- const fmt = (n) => fmtId(n.id) + (n.label !== void 0 ? `["${n.label}"]` : "") + n.classes.map((c) => `:::${c}`).join("");
3658
- const l = _nullishCoalesce(LEFT_TOKEN[stmt.arrowStart], () => ( "||"));
3659
- const r = _nullishCoalesce(RIGHT_TOKEN[stmt.arrowEnd], () => ( "o{"));
3660
- const mid = stmt.pattern === "dotted" ? ".." : "--";
3661
- const label = _nullishCoalesce(stmt.label, () => ( ""));
3662
- return `${stmt.indent}${fmt(stmt.source)} ${l}${mid}${r} ${fmt(stmt.target)} : ${/\s/.test(label) ? `"${label}"` : label || '""'}`;
3663
- }
3664
- case "direction":
3665
- return `${stmt.indent}direction ${stmt.direction}`;
3666
- case "classDef":
3667
- return `${stmt.indent}classDef ${stmt.names.join(",")} ${stmt.styles.join(",")}`;
3668
- case "class":
3669
- return `${stmt.indent}class ${stmt.ids.join(",")} ${stmt.className}`;
3670
- case "style":
3671
- return `${stmt.indent}style ${stmt.id} ${stmt.styles.join(",")}`;
3672
- default:
3673
- return stmt.raw;
3674
- }
3675
- },
3676
- nodeStatement(decl, indent) {
3677
- const attrs = _optionalChain([decl, 'access', _80 => _80.data, 'optionalAccess', _81 => _81.attributes]);
3678
- const body = _optionalChain([attrs, 'optionalAccess', _82 => _82.length]) ? [...attrs.map((a) => `${indent} ${a.raw}`), `${indent}}`] : void 0;
3679
- return {
3680
- kind: "node",
3681
- raw: "",
3682
- indent,
3683
- decl: { ...decl, classes: [...decl.classes] },
3684
- body,
3685
- dirty: true
3686
- };
3687
- },
3688
- edgeStatement(source, target, spec, indent) {
3689
- return {
3690
- kind: "edge",
3691
- raw: "",
3692
- indent,
3693
- source: { id: source, classes: [] },
3694
- target: { id: target, classes: [] },
3695
- label: _nullishCoalesce(spec.label, () => ( "has")),
3696
- arrowStart: spec.arrowStart,
3697
- arrowEnd: spec.arrowEnd,
3698
- pattern: spec.pattern,
3699
- data: spec.data,
3700
- dirty: true
3701
- };
3702
- },
3703
- groupStatements(id, _label, indent) {
3704
- return {
3705
- open: { kind: "raw", raw: `${indent}%% group ${id}`, indent },
3706
- close: { kind: "raw", raw: `${indent}%% end group ${id}`, indent }
3707
- };
3708
- },
3709
- headerDirection(_header, statements) {
3710
- const top = statements.find((s) => s.kind === "direction");
3711
- return top && top.kind === "direction" ? top.direction : "TB";
3712
- }
3713
- };
3714
- var ER_PATTERNS = [
3715
- { pattern: "solid", title: "Identifying" },
3716
- { pattern: "dotted", title: "Non-identifying" }
3717
- ];
3718
-
3719
- // src/diagram/registry.ts
3720
- var adapters = /* @__PURE__ */ new Map();
3721
- function registerDiagramAdapter(adapter) {
3722
- adapters.set(adapter.family, adapter);
3723
- }
3724
- function getDiagramAdapter(family) {
3725
- return _nullishCoalesce(adapters.get(family), () => ( adapters.get("unknown")));
3726
- }
3727
- function supportTierOf(family) {
3728
- return getDiagramAdapter(family).tier;
3729
- }
3730
- registerDiagramAdapter(flowchartAdapter);
3731
- registerDiagramAdapter(createLineAdapter(stateGrammar));
3732
- registerDiagramAdapter(createLineAdapter(classGrammar));
3733
- registerDiagramAdapter(createLineAdapter(erGrammar));
3734
- for (const family of [
3735
- "requirement",
3736
- "mindmap",
3737
- "sequence",
3738
- "gantt",
3739
- "pie",
3740
- "journey",
3741
- "timeline",
3742
- "gitGraph",
3743
- "c4",
3744
- "quadrant",
3745
- "sankey",
3746
- "xychart",
3747
- "block",
3748
- "architecture",
3749
- "packet",
3750
- "kanban",
3751
- "radar",
3752
- "treemap",
3753
- "info",
3754
- "unknown"
3755
- ]) {
3756
- registerDiagramAdapter(createPassthroughAdapter(family));
3757
- }
3758
-
3759
- // src/diagram/document.ts
3760
- function detectFamily(source) {
3761
- return detectFamilyFromHeader(splitSource(source).header);
3762
- }
3763
- function parseMermaid(source, options = {}) {
3764
- const split = splitSource(source);
3765
- const family = detectFamilyFromHeader(split.header);
3766
- const fromBody = extractMetaFromBody(split.bodyLines);
3767
- const fromFm = extractMetaFromFrontmatter(split.preamble);
3768
- let meta = emptyMeta();
3769
- if (fromFm) meta = mergeMeta(meta, fromFm);
3770
- if (fromBody.meta) meta = mergeMeta(meta, fromBody.meta);
3771
- const metaCarrier = _nullishCoalesce(options.metaCarrier, () => ( (fromFm && !fromBody.meta ? "frontmatter" : defaultCarrierFor(family))));
3772
- const adapter = getDiagramAdapter(family);
3773
- const doc = adapter.parse(source, {
3774
- source,
3775
- eol: split.eol,
3776
- preamble: split.preamble,
3777
- header: split.header,
3778
- bodyLines: fromBody.bodyLines,
3779
- trailing: split.trailing,
3780
- meta,
3781
- metaCarrier,
3782
- family
3783
- });
3784
- return doc;
3785
- }
3786
- function serializeMermaid(doc) {
3787
- return getDiagramAdapter(doc.family).serialize(doc);
3788
- }
3789
- function applyEdit(doc, op) {
3790
- if (op.type === "replaceSource") {
3791
- const next2 = parseMermaid(op.source, { metaCarrier: doc.metaCarrier });
3792
- next2.dirty = true;
3793
- return next2;
3794
- }
3795
- const next = getDiagramAdapter(doc.family).apply(doc, op);
3796
- if (next !== doc && next.source === doc.source) {
3797
- next.source = serializeMermaid(next);
3798
- }
3799
- return next;
3800
- }
3801
- function applyEdits(doc, ops) {
3802
- return ops.reduce((d, op) => applyEdit(d, op), doc);
3803
- }
3804
-
3805
-
3806
-
3807
-
3808
-
3809
-
3810
-
3811
-
3812
-
3813
-
3814
-
3815
-
3816
-
3817
-
3818
-
3819
-
3820
-
3821
-
3822
-
3823
-
3824
-
3825
-
3826
-
3827
-
3828
-
3829
-
3830
-
3831
-
3832
-
3833
-
3834
-
3835
-
3836
-
3837
-
3838
-
3839
-
3840
-
3841
-
3842
-
3843
-
3844
-
3845
-
3846
-
3847
- exports.detectFamilyFromHeader = detectFamilyFromHeader; exports.splitSource = splitSource; exports.splitStatements = splitStatements; exports.META_COMMENT_PREFIX = META_COMMENT_PREFIX; exports.META_FRONTMATTER_KEY = META_FRONTMATTER_KEY; exports.emptyMeta = emptyMeta; exports.mergeMeta = mergeMeta; exports.isMetaEmpty = isMetaEmpty; exports.serializeMeta = serializeMeta; exports.parseLink = parseLink; exports.quoteLabelIfNeeded = quoteLabelIfNeeded; exports.formatLink = formatLink; exports.FLOWCHART_SHAPES = FLOWCHART_SHAPES; exports.resolveShape = resolveShape; exports.canonicalShape = canonicalShape; exports.parseChain = parseChain; exports.parseStatement = parseStatement; exports.formatNode = formatNode; exports.formatChain = formatChain; exports.parseFlowchartSource = parseFlowchartSource; exports.flowchartAdapter = flowchartAdapter; exports.createLineAdapter = createLineAdapter; exports.createPassthroughAdapter = createPassthroughAdapter; exports.STATE_SHAPES = STATE_SHAPES; exports.stateGrammar = stateGrammar; exports.CLASS_RELATIONS = CLASS_RELATIONS; exports.relationFor = relationFor; exports.parseMembers = parseMembers; exports.classGrammar = classGrammar; exports.ER_CARDINALITIES = ER_CARDINALITIES; exports.parseAttributes = parseAttributes; exports.erGrammar = erGrammar; exports.ER_PATTERNS = ER_PATTERNS; exports.registerDiagramAdapter = registerDiagramAdapter; exports.getDiagramAdapter = getDiagramAdapter; exports.supportTierOf = supportTierOf; exports.detectFamily = detectFamily; exports.parseMermaid = parseMermaid; exports.serializeMermaid = serializeMermaid; exports.applyEdit = applyEdit; exports.applyEdits = applyEdits;
3848
- //# sourceMappingURL=chunk-H5K77C7Y.cjs.map