@diagrammo/dgmo 0.14.1 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -31,328 +31,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
31
31
  mod
32
32
  ));
33
33
 
34
- // src/diagnostics.ts
35
- function makeDgmoError(line12, message, severity = "error", code) {
36
- return code !== void 0 ? { line: line12, message, severity, code } : { line: line12, message, severity };
37
- }
38
- function formatDgmoError(err) {
39
- return err.line > 0 ? `Line ${err.line}: ${err.message}` : err.message;
40
- }
41
- function levenshtein(a, b) {
42
- const m = a.length;
43
- const n = b.length;
44
- const dp = Array(n + 1).fill(0).map((_, i) => i);
45
- for (let i = 1; i <= m; i++) {
46
- let prev = dp[0];
47
- dp[0] = i;
48
- for (let j = 1; j <= n; j++) {
49
- const tmp = dp[j];
50
- dp[j] = a[i - 1] === b[j - 1] ? prev : 1 + Math.min(prev, dp[j], dp[j - 1]);
51
- prev = tmp;
52
- }
53
- }
54
- return dp[n];
55
- }
56
- function suggest(input, candidates) {
57
- if (!input || candidates.length === 0) return null;
58
- const lower = input.toLowerCase();
59
- const threshold = Math.max(2, Math.floor(lower.length / 3));
60
- let best = null;
61
- let bestDist = Infinity;
62
- for (const c of candidates) {
63
- const dist = levenshtein(lower, c.toLowerCase());
64
- if (dist < bestDist && dist <= threshold && dist > 0) {
65
- bestDist = dist;
66
- best = c;
67
- }
68
- }
69
- return best ? `Did you mean '${best}'?` : null;
70
- }
71
- function nameMergedMessage(args) {
72
- return `merged '${args.incomingDisplay}' (line ${args.incomingLine}) into '${args.existingDisplay}' (line ${args.existingLine}) \u2014 names differ only in case/whitespace`;
73
- }
74
- function akaRemovedMessage() {
75
- return `'aka' is no longer supported \u2014 use the participant name directly`;
76
- }
77
- function tagShorthandRemovedMessage(args) {
78
- return `Bare tag shorthand 'tag ${args.name} ${args.alias}' was removed. Use 'tag ${args.name} as ${args.alias}' instead.`;
79
- }
80
- function vennAliasKeywordRemovedMessage(args) {
81
- return `Venn 'alias' keyword was removed. Use 'as' instead \u2014 '${args.name} as ${args.alias}'.`;
82
- }
83
- var NAME_DIAGNOSTIC_CODES, ALIAS_DIAGNOSTIC_CODES;
84
- var init_diagnostics = __esm({
85
- "src/diagnostics.ts"() {
86
- "use strict";
87
- NAME_DIAGNOSTIC_CODES = {
88
- /**
89
- * Warning: two source-distinct names normalized to the same key
90
- * (case- or whitespace-only difference). The first occurrence wins
91
- * for display; subsequent occurrences fold into it. Suppressible
92
- * per-line via `# allow-merge` annotation when intentional.
93
- *
94
- * Note: the `I_` prefix is intentionally preserved for stability —
95
- * callers may have pinned this string. The diagnostic emits at
96
- * `warning` severity (no `info` severity exists in DgmoError).
97
- */
98
- NAME_MERGED: "I_NAME_MERGED",
99
- /**
100
- * Error: a name contains a reserved character (`|`, `:`, edge
101
- * sigils `-> <- ~> <~ -- ..`, shape brackets `[] () {} <>`,
102
- * leading/trailing whitespace) without being wrapped in `"..."`.
103
- */
104
- NAME_RESERVED_CHAR: "E_NAME_RESERVED_CHAR",
105
- /**
106
- * Error: the removed `aka` keyword was used in a sequence
107
- * participant declaration. Forgiving normalization makes aliasing
108
- * unnecessary; the diagnostic directs users to the new syntax.
109
- */
110
- AKA_REMOVED: "E_AKA_REMOVED"
111
- };
112
- ALIAS_DIAGNOSTIC_CODES = {
113
- /** Alias token used before its declaration (strict-ordering rule). */
114
- ALIAS_BEFORE_DECL: "E_ALIAS_BEFORE_DECL",
115
- /** Same alias bound to two different canonicals. */
116
- ALIAS_COLLISION: "E_ALIAS_COLLISION",
117
- /** Alias literal matches an existing canonical name. */
118
- ALIAS_SHADOWS_NAME: "E_ALIAS_SHADOWS_NAME",
119
- /** Same canonical re-declared with a different alias. */
120
- ALIAS_REBINDING: "E_ALIAS_REBINDING",
121
- /** `pm as p` where `pm` is itself an alias — must alias the canonical. */
122
- ALIAS_OF_ALIAS: "E_ALIAS_OF_ALIAS",
123
- /** Alias matches a reserved keyword (`as`, `is`, chart-type tokens, etc.). */
124
- ALIAS_RESERVED_KEYWORD: "E_ALIAS_RESERVED_KEYWORD",
125
- /** `as` matched but token doesn't fit `[A-Za-z][A-Za-z0-9_]{0,11}`. */
126
- ALIAS_INVALID_FORMAT: "E_ALIAS_INVALID_FORMAT",
127
- /** Canonical name was used plainly before its alias declaration. */
128
- ALIAS_AFTER_CANONICAL: "E_ALIAS_AFTER_CANONICAL",
129
- /** Legacy `tag Name x` shorthand encountered — use `tag Name as x`. */
130
- TAG_SHORTHAND_REMOVED: "E_TAG_SHORTHAND_REMOVED",
131
- /** Legacy venn `Name(color) alias X` encountered — use `as`. */
132
- VENN_ALIAS_KEYWORD_REMOVED: "E_VENN_ALIAS_KEYWORD_REMOVED",
133
- /** Reference token differs from a declared alias only in case. */
134
- ALIAS_CASE_NEAR_MATCH: "W_ALIAS_CASE_NEAR_MATCH",
135
- /** Alias declared but referenced ≤1 time. */
136
- ALIAS_UNDERUSED: "W_ALIAS_UNDERUSED"
137
- };
138
- }
139
- });
140
-
141
- // src/colors.ts
142
- function isRecognizedColorName(name) {
143
- return Object.prototype.hasOwnProperty.call(colorNames, name.toLowerCase());
144
- }
145
- function resolveColor(color, palette) {
146
- if (!color) return null;
147
- if (color.startsWith("#")) return null;
148
- const lower = color.toLowerCase();
149
- if (!isRecognizedColorName(lower)) return null;
150
- if (palette) {
151
- const named = palette.colors[lower];
152
- if (named) return named;
153
- }
154
- return colorNames[lower];
155
- }
156
- function resolveColorWithDiagnostic(color, line12, diagnostics, palette) {
157
- const resolved = resolveColor(color, palette);
158
- if (resolved !== null) return resolved;
159
- const hint = suggest(color, RECOGNIZED_COLOR_NAMES);
160
- const suggestion = hint ? ` ${hint}` : "";
161
- diagnostics.push(
162
- makeDgmoError(
163
- line12,
164
- `Unknown color "${color}". Allowed: ${RECOGNIZED_COLOR_NAMES.join(", ")}.${suggestion}`,
165
- "warning"
166
- )
167
- );
168
- return void 0;
169
- }
170
- var nord, colorNames, RECOGNIZED_COLOR_NAMES, seriesColors;
171
- var init_colors = __esm({
172
- "src/colors.ts"() {
173
- "use strict";
174
- init_diagnostics();
175
- nord = {
176
- // Polar Night (dark)
177
- nord0: "#2e3440",
178
- nord1: "#3b4252",
179
- nord2: "#434c5e",
180
- nord3: "#4c566a",
181
- // Snow Storm (light)
182
- nord4: "#d8dee9",
183
- nord5: "#e5e9f0",
184
- nord6: "#eceff4",
185
- // Frost (accent blues)
186
- nord7: "#8fbcbb",
187
- nord8: "#88c0d0",
188
- nord9: "#81a1c1",
189
- nord10: "#5e81ac",
190
- // Aurora (colors)
191
- nord11: "#bf616a",
192
- // red
193
- nord12: "#d08770",
194
- // orange
195
- nord13: "#ebcb8b",
196
- // yellow
197
- nord14: "#a3be8c",
198
- // green
199
- nord15: "#b48ead"
200
- // purple
201
- };
202
- colorNames = {
203
- red: nord.nord11,
204
- orange: nord.nord12,
205
- yellow: nord.nord13,
206
- green: nord.nord14,
207
- blue: nord.nord10,
208
- purple: nord.nord15,
209
- teal: nord.nord7,
210
- cyan: nord.nord8,
211
- gray: nord.nord3,
212
- black: nord.nord0,
213
- white: nord.nord6
214
- };
215
- RECOGNIZED_COLOR_NAMES = Object.freeze([
216
- "red",
217
- "orange",
218
- "yellow",
219
- "green",
220
- "blue",
221
- "purple",
222
- "teal",
223
- "cyan",
224
- "gray",
225
- "black",
226
- "white"
227
- ]);
228
- seriesColors = [
229
- nord.nord10,
230
- // blue
231
- nord.nord14,
232
- // green
233
- nord.nord13,
234
- // yellow
235
- nord.nord12,
236
- // orange
237
- nord.nord15,
238
- // purple
239
- nord.nord11,
240
- // red
241
- nord.nord7,
242
- // teal
243
- nord.nord8
244
- // light blue
245
- ];
246
- }
247
- });
248
-
249
- // src/utils/arrows.ts
250
- function validateLabelCharacters(label, lineNumber) {
251
- const out = [];
252
- if (label.includes("->") || label.includes("~>")) {
253
- out.push(
254
- makeDgmoError(
255
- lineNumber,
256
- 'Arrow symbols (-> or ~>) are not allowed inside a label. Move the label after the arrow: "A -> B: uses -> to chain". See "In-Arrow Message Labels" \u2192 Forbidden.',
257
- "error",
258
- ARROW_DIAGNOSTIC_CODES.ARROW_SUBSTRING_IN_LABEL
259
- )
260
- );
261
- }
262
- for (const ch of label) {
263
- const cp = ch.codePointAt(0);
264
- const isC0 = cp >= 0 && cp <= 31 && cp !== 9;
265
- const isDel = cp === 127;
266
- if (isC0 || isDel) {
267
- const hex = cp.toString(16).toUpperCase().padStart(4, "0");
268
- out.push(
269
- makeDgmoError(
270
- lineNumber,
271
- `Label contains a control character (U+${hex}). Remove it and use plain text.`,
272
- "error",
273
- ARROW_DIAGNOSTIC_CODES.CONTROL_CHAR_IN_LABEL
274
- )
275
- );
276
- break;
277
- }
278
- }
279
- return out;
280
- }
281
- function parseInArrowLabel(rawLabel, lineNumber) {
282
- const trimmed = rawLabel.trim();
283
- if (trimmed.length === 0) {
284
- return { label: void 0, diagnostics: [] };
285
- }
286
- const diagnostics = validateLabelCharacters(trimmed, lineNumber);
287
- return { label: trimmed, diagnostics };
288
- }
289
- function matchColorParens(content) {
290
- const m = content.match(/^\(([A-Za-z]+)\)$/);
291
- if (!m) return null;
292
- const candidate = m[1].toLowerCase();
293
- if (RECOGNIZED_COLOR_NAMES.includes(candidate)) {
294
- return candidate;
295
- }
296
- return null;
297
- }
298
- function parseArrow(line12) {
299
- if (BIDI_SYNC_RE.test(line12) || BIDI_ASYNC_RE.test(line12)) {
300
- return {
301
- error: "Bidirectional arrows are no longer supported. Use two separate lines: 'A -msg-> B' and 'B -msg-> A'"
302
- };
303
- }
304
- if (RETURN_SYNC_LABELED_RE.test(line12) || RETURN_ASYNC_LABELED_RE.test(line12)) {
305
- const m = line12.match(RETURN_SYNC_LABELED_RE) ?? line12.match(RETURN_ASYNC_LABELED_RE);
306
- const from = m[3];
307
- const to = m[1];
308
- const label = m[2].trim();
309
- return {
310
- error: `Left-pointing arrows are no longer supported. Write '${from} -${label}-> ${to}' instead`
311
- };
312
- }
313
- const patterns = [
314
- { re: SYNC_LABELED_RE, async: false },
315
- { re: ASYNC_LABELED_RE, async: true }
316
- ];
317
- for (const { re, async: isAsync } of patterns) {
318
- const m = line12.match(re);
319
- if (!m) continue;
320
- const label = m[2].trim();
321
- if (!label) return null;
322
- return {
323
- from: m[1],
324
- to: m[3],
325
- label,
326
- async: isAsync
327
- };
328
- }
329
- return null;
330
- }
331
- var ARROW_DIAGNOSTIC_CODES, SYNC_LABELED_RE, ASYNC_LABELED_RE, RETURN_SYNC_LABELED_RE, RETURN_ASYNC_LABELED_RE, BIDI_SYNC_RE, BIDI_ASYNC_RE;
332
- var init_arrows = __esm({
333
- "src/utils/arrows.ts"() {
334
- "use strict";
335
- init_diagnostics();
336
- init_colors();
337
- ARROW_DIAGNOSTIC_CODES = {
338
- /** Active: label contains `->` or `~>` substring (TD-13). */
339
- ARROW_SUBSTRING_IN_LABEL: "E_ARROW_SUBSTRING_IN_LABEL",
340
- /** Active: label contains a forbidden control character (TD-14). */
341
- CONTROL_CHAR_IN_LABEL: "E_CONTROL_CHAR_IN_LABEL",
342
- /** Reserved: not currently emitted by any parser. See JSDoc above. */
343
- TRAILING_ARROW_TEXT: "E_TRAILING_ARROW_TEXT",
344
- /** Reserved: not currently emitted by any parser. See JSDoc above. */
345
- MIXED_ARROW_DELIMITERS: "E_MIXED_ARROW_DELIMITERS"
346
- };
347
- SYNC_LABELED_RE = /^(.+?)\s*-(.+)->\s*(.+)$/;
348
- ASYNC_LABELED_RE = /^(.+?)\s*~(.+)~>\s*(.+)$/;
349
- RETURN_SYNC_LABELED_RE = /^(.+?)\s*<-(.+)-\s*(.+)$/;
350
- RETURN_ASYNC_LABELED_RE = /^(.+?)\s*<~(.+)~\s*(.+)$/;
351
- BIDI_SYNC_RE = /^(.+?)\s*<-(.+)->\s*(.+)$/;
352
- BIDI_ASYNC_RE = /^(.+?)\s*<~(.+)~>\s*(.+)$/;
353
- }
354
- });
355
-
356
34
  // src/fonts.ts
357
35
  var FONT_FAMILY;
358
36
  var init_fonts = __esm({
@@ -695,104 +373,319 @@ var init_time_ticks = __esm({
695
373
  }
696
374
  });
697
375
 
698
- // src/palettes/registry.ts
699
- function isValidHex(value) {
700
- return /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(value);
376
+ // src/diagnostics.ts
377
+ function makeDgmoError(line12, message, severity = "error", code) {
378
+ return code !== void 0 ? { line: line12, message, severity, code } : { line: line12, message, severity };
701
379
  }
702
- function validatePaletteColors(colors, mode, paletteId) {
703
- for (const key of SEMANTIC_KEYS) {
704
- const value = colors[key];
705
- if (typeof value !== "string" || !isValidHex(value)) {
706
- throw new Error(
707
- `Palette "${paletteId}" ${mode}.${key}: invalid hex "${value}"`
708
- );
380
+ function formatDgmoError(err) {
381
+ return err.line > 0 ? `Line ${err.line}: ${err.message}` : err.message;
382
+ }
383
+ function levenshtein(a, b) {
384
+ const m = a.length;
385
+ const n = b.length;
386
+ const dp = Array(n + 1).fill(0).map((_, i) => i);
387
+ for (let i = 1; i <= m; i++) {
388
+ let prev = dp[0];
389
+ dp[0] = i;
390
+ for (let j = 1; j <= n; j++) {
391
+ const tmp = dp[j];
392
+ dp[j] = a[i - 1] === b[j - 1] ? prev : 1 + Math.min(prev, dp[j], dp[j - 1]);
393
+ prev = tmp;
709
394
  }
710
395
  }
711
- for (const key of COLOR_KEYS) {
712
- const value = colors.colors[key];
713
- if (typeof value !== "string" || !isValidHex(value)) {
714
- throw new Error(
715
- `Palette "${paletteId}" ${mode}.colors.${key}: invalid hex "${value}"`
716
- );
396
+ return dp[n];
397
+ }
398
+ function suggest(input, candidates) {
399
+ if (!input || candidates.length === 0) return null;
400
+ const lower = input.toLowerCase();
401
+ const threshold = Math.max(2, Math.floor(lower.length / 3));
402
+ let best = null;
403
+ let bestDist = Infinity;
404
+ for (const c of candidates) {
405
+ const dist = levenshtein(lower, c.toLowerCase());
406
+ if (dist < bestDist && dist <= threshold && dist > 0) {
407
+ bestDist = dist;
408
+ best = c;
717
409
  }
718
410
  }
411
+ return best ? `Did you mean '${best}'?` : null;
719
412
  }
720
- function registerPalette(palette) {
721
- validatePaletteColors(palette.light, "light", palette.id);
722
- validatePaletteColors(palette.dark, "dark", palette.id);
723
- PALETTE_REGISTRY.set(palette.id, palette);
413
+ function nameMergedMessage(args) {
414
+ return `merged '${args.incomingDisplay}' (line ${args.incomingLine}) into '${args.existingDisplay}' (line ${args.existingLine}) \u2014 names differ only in case/whitespace`;
724
415
  }
725
- function getPalette(id) {
726
- return PALETTE_REGISTRY.get(id) ?? PALETTE_REGISTRY.get(DEFAULT_PALETTE_ID);
416
+ function akaRemovedMessage() {
417
+ return `'aka' is no longer supported \u2014 use the participant name directly`;
727
418
  }
728
- function getAvailablePalettes() {
729
- return Array.from(PALETTE_REGISTRY.values()).sort(
730
- (a, b) => a.name.localeCompare(b.name)
731
- );
419
+ function tagShorthandRemovedMessage(args) {
420
+ return `Bare tag shorthand 'tag ${args.name} ${args.alias}' was removed. Use 'tag ${args.name} as ${args.alias}' instead.`;
732
421
  }
733
- var PALETTE_REGISTRY, DEFAULT_PALETTE_ID, COLOR_KEYS, SEMANTIC_KEYS;
734
- var init_registry = __esm({
735
- "src/palettes/registry.ts"() {
422
+ function vennAliasKeywordRemovedMessage(args) {
423
+ return `Venn 'alias' keyword was removed. Use 'as' instead \u2014 '${args.name} as ${args.alias}'.`;
424
+ }
425
+ var NAME_DIAGNOSTIC_CODES, ALIAS_DIAGNOSTIC_CODES;
426
+ var init_diagnostics = __esm({
427
+ "src/diagnostics.ts"() {
736
428
  "use strict";
737
- PALETTE_REGISTRY = /* @__PURE__ */ new Map();
738
- DEFAULT_PALETTE_ID = "nord";
739
- COLOR_KEYS = [
740
- "red",
741
- "orange",
742
- "yellow",
743
- "green",
744
- "blue",
745
- "purple",
746
- "teal",
747
- "cyan",
748
- "gray"
749
- ];
750
- SEMANTIC_KEYS = [
751
- "bg",
752
- "surface",
753
- "overlay",
754
- "border",
755
- "text",
756
- "textMuted",
757
- "primary",
758
- "secondary",
759
- "accent",
760
- "destructive"
761
- ];
429
+ NAME_DIAGNOSTIC_CODES = {
430
+ /**
431
+ * Warning: two source-distinct names normalized to the same key
432
+ * (case- or whitespace-only difference). The first occurrence wins
433
+ * for display; subsequent occurrences fold into it. Suppressible
434
+ * per-line via `# allow-merge` annotation when intentional.
435
+ *
436
+ * Note: the `I_` prefix is intentionally preserved for stability —
437
+ * callers may have pinned this string. The diagnostic emits at
438
+ * `warning` severity (no `info` severity exists in DgmoError).
439
+ */
440
+ NAME_MERGED: "I_NAME_MERGED",
441
+ /**
442
+ * Error: a name contains a reserved character (`|`, `:`, edge
443
+ * sigils `-> <- ~> <~ -- ..`, shape brackets `[] () {} <>`,
444
+ * leading/trailing whitespace) without being wrapped in `"..."`.
445
+ */
446
+ NAME_RESERVED_CHAR: "E_NAME_RESERVED_CHAR",
447
+ /**
448
+ * Error: the removed `aka` keyword was used in a sequence
449
+ * participant declaration. Forgiving normalization makes aliasing
450
+ * unnecessary; the diagnostic directs users to the new syntax.
451
+ */
452
+ AKA_REMOVED: "E_AKA_REMOVED"
453
+ };
454
+ ALIAS_DIAGNOSTIC_CODES = {
455
+ /** Alias token used before its declaration (strict-ordering rule). */
456
+ ALIAS_BEFORE_DECL: "E_ALIAS_BEFORE_DECL",
457
+ /** Same alias bound to two different canonicals. */
458
+ ALIAS_COLLISION: "E_ALIAS_COLLISION",
459
+ /** Alias literal matches an existing canonical name. */
460
+ ALIAS_SHADOWS_NAME: "E_ALIAS_SHADOWS_NAME",
461
+ /** Same canonical re-declared with a different alias. */
462
+ ALIAS_REBINDING: "E_ALIAS_REBINDING",
463
+ /** `pm as p` where `pm` is itself an alias — must alias the canonical. */
464
+ ALIAS_OF_ALIAS: "E_ALIAS_OF_ALIAS",
465
+ /** Alias matches a reserved keyword (`as`, `is`, chart-type tokens, etc.). */
466
+ ALIAS_RESERVED_KEYWORD: "E_ALIAS_RESERVED_KEYWORD",
467
+ /** `as` matched but token doesn't fit `[A-Za-z][A-Za-z0-9_]{0,11}`. */
468
+ ALIAS_INVALID_FORMAT: "E_ALIAS_INVALID_FORMAT",
469
+ /** Canonical name was used plainly before its alias declaration. */
470
+ ALIAS_AFTER_CANONICAL: "E_ALIAS_AFTER_CANONICAL",
471
+ /** Legacy `tag Name x` shorthand encountered — use `tag Name as x`. */
472
+ TAG_SHORTHAND_REMOVED: "E_TAG_SHORTHAND_REMOVED",
473
+ /** Legacy venn `Name(color) alias X` encountered — use `as`. */
474
+ VENN_ALIAS_KEYWORD_REMOVED: "E_VENN_ALIAS_KEYWORD_REMOVED",
475
+ /** Reference token differs from a declared alias only in case. */
476
+ ALIAS_CASE_NEAR_MATCH: "W_ALIAS_CASE_NEAR_MATCH",
477
+ /** Alias declared but referenced ≤1 time. */
478
+ ALIAS_UNDERUSED: "W_ALIAS_UNDERUSED"
479
+ };
762
480
  }
763
481
  });
764
482
 
765
- // src/palettes/color-utils.ts
766
- function hexToHSL(hex) {
767
- const raw = hex.replace("#", "");
768
- const full = raw.length === 3 ? raw[0] + raw[0] + raw[1] + raw[1] + raw[2] + raw[2] : raw;
769
- const r = parseInt(full.substring(0, 2), 16) / 255;
770
- const g = parseInt(full.substring(2, 4), 16) / 255;
771
- const b = parseInt(full.substring(4, 6), 16) / 255;
772
- const max = Math.max(r, g, b);
773
- const min = Math.min(r, g, b);
774
- const l = (max + min) / 2;
775
- if (max === min) {
776
- return { h: 0, s: 0, l: Math.round(l * 100) };
777
- }
778
- const d = max - min;
779
- const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
780
- let h;
781
- if (max === r) {
782
- h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
783
- } else if (max === g) {
784
- h = ((b - r) / d + 2) / 6;
785
- } else {
786
- h = ((r - g) / d + 4) / 6;
483
+ // src/colors.ts
484
+ function isRecognizedColorName(name) {
485
+ return Object.prototype.hasOwnProperty.call(colorNames, name.toLowerCase());
486
+ }
487
+ function resolveColor(color, palette) {
488
+ if (!color) return null;
489
+ if (color.startsWith("#")) return null;
490
+ const lower = color.toLowerCase();
491
+ if (!isRecognizedColorName(lower)) return null;
492
+ if (palette) {
493
+ const named = palette.colors[lower];
494
+ if (named) return named;
787
495
  }
788
- return {
789
- h: Math.round(h * 360),
790
- s: Math.round(s * 100),
791
- l: Math.round(l * 100)
792
- };
496
+ return colorNames[lower];
793
497
  }
794
- function hslToHex(h, s, l) {
795
- const sNorm = s / 100;
498
+ function resolveColorWithDiagnostic(color, line12, diagnostics, palette) {
499
+ const resolved = resolveColor(color, palette);
500
+ if (resolved !== null) return resolved;
501
+ const hint = suggest(color, RECOGNIZED_COLOR_NAMES);
502
+ const suggestion = hint ? ` ${hint}` : "";
503
+ diagnostics.push(
504
+ makeDgmoError(
505
+ line12,
506
+ `Unknown color "${color}". Allowed: ${RECOGNIZED_COLOR_NAMES.join(", ")}.${suggestion}`,
507
+ "warning"
508
+ )
509
+ );
510
+ return void 0;
511
+ }
512
+ var nord, colorNames, RECOGNIZED_COLOR_NAMES, seriesColors;
513
+ var init_colors = __esm({
514
+ "src/colors.ts"() {
515
+ "use strict";
516
+ init_diagnostics();
517
+ nord = {
518
+ // Polar Night (dark)
519
+ nord0: "#2e3440",
520
+ nord1: "#3b4252",
521
+ nord2: "#434c5e",
522
+ nord3: "#4c566a",
523
+ // Snow Storm (light)
524
+ nord4: "#d8dee9",
525
+ nord5: "#e5e9f0",
526
+ nord6: "#eceff4",
527
+ // Frost (accent blues)
528
+ nord7: "#8fbcbb",
529
+ nord8: "#88c0d0",
530
+ nord9: "#81a1c1",
531
+ nord10: "#5e81ac",
532
+ // Aurora (colors)
533
+ nord11: "#bf616a",
534
+ // red
535
+ nord12: "#d08770",
536
+ // orange
537
+ nord13: "#ebcb8b",
538
+ // yellow
539
+ nord14: "#a3be8c",
540
+ // green
541
+ nord15: "#b48ead"
542
+ // purple
543
+ };
544
+ colorNames = {
545
+ red: nord.nord11,
546
+ orange: nord.nord12,
547
+ yellow: nord.nord13,
548
+ green: nord.nord14,
549
+ blue: nord.nord10,
550
+ purple: nord.nord15,
551
+ teal: nord.nord7,
552
+ cyan: nord.nord8,
553
+ gray: nord.nord3,
554
+ black: nord.nord0,
555
+ white: nord.nord6
556
+ };
557
+ RECOGNIZED_COLOR_NAMES = Object.freeze([
558
+ "red",
559
+ "orange",
560
+ "yellow",
561
+ "green",
562
+ "blue",
563
+ "purple",
564
+ "teal",
565
+ "cyan",
566
+ "gray",
567
+ "black",
568
+ "white"
569
+ ]);
570
+ seriesColors = [
571
+ nord.nord10,
572
+ // blue
573
+ nord.nord14,
574
+ // green
575
+ nord.nord13,
576
+ // yellow
577
+ nord.nord12,
578
+ // orange
579
+ nord.nord15,
580
+ // purple
581
+ nord.nord11,
582
+ // red
583
+ nord.nord7,
584
+ // teal
585
+ nord.nord8
586
+ // light blue
587
+ ];
588
+ }
589
+ });
590
+
591
+ // src/palettes/registry.ts
592
+ function isValidHex(value) {
593
+ return /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(value);
594
+ }
595
+ function validatePaletteColors(colors, mode, paletteId) {
596
+ for (const key of SEMANTIC_KEYS) {
597
+ const value = colors[key];
598
+ if (typeof value !== "string" || !isValidHex(value)) {
599
+ throw new Error(
600
+ `Palette "${paletteId}" ${mode}.${key}: invalid hex "${value}"`
601
+ );
602
+ }
603
+ }
604
+ for (const key of COLOR_KEYS) {
605
+ const value = colors.colors[key];
606
+ if (typeof value !== "string" || !isValidHex(value)) {
607
+ throw new Error(
608
+ `Palette "${paletteId}" ${mode}.colors.${key}: invalid hex "${value}"`
609
+ );
610
+ }
611
+ }
612
+ }
613
+ function registerPalette(palette) {
614
+ validatePaletteColors(palette.light, "light", palette.id);
615
+ validatePaletteColors(palette.dark, "dark", palette.id);
616
+ PALETTE_REGISTRY.set(palette.id, palette);
617
+ }
618
+ function getPalette(id) {
619
+ return PALETTE_REGISTRY.get(id) ?? PALETTE_REGISTRY.get(DEFAULT_PALETTE_ID);
620
+ }
621
+ function getAvailablePalettes() {
622
+ return Array.from(PALETTE_REGISTRY.values()).sort(
623
+ (a, b) => a.name.localeCompare(b.name)
624
+ );
625
+ }
626
+ var PALETTE_REGISTRY, DEFAULT_PALETTE_ID, COLOR_KEYS, SEMANTIC_KEYS;
627
+ var init_registry = __esm({
628
+ "src/palettes/registry.ts"() {
629
+ "use strict";
630
+ PALETTE_REGISTRY = /* @__PURE__ */ new Map();
631
+ DEFAULT_PALETTE_ID = "nord";
632
+ COLOR_KEYS = [
633
+ "red",
634
+ "orange",
635
+ "yellow",
636
+ "green",
637
+ "blue",
638
+ "purple",
639
+ "teal",
640
+ "cyan",
641
+ "gray"
642
+ ];
643
+ SEMANTIC_KEYS = [
644
+ "bg",
645
+ "surface",
646
+ "overlay",
647
+ "border",
648
+ "text",
649
+ "textMuted",
650
+ "primary",
651
+ "secondary",
652
+ "accent",
653
+ "destructive"
654
+ ];
655
+ }
656
+ });
657
+
658
+ // src/palettes/color-utils.ts
659
+ function hexToHSL(hex) {
660
+ const raw = hex.replace("#", "");
661
+ const full = raw.length === 3 ? raw[0] + raw[0] + raw[1] + raw[1] + raw[2] + raw[2] : raw;
662
+ const r = parseInt(full.substring(0, 2), 16) / 255;
663
+ const g = parseInt(full.substring(2, 4), 16) / 255;
664
+ const b = parseInt(full.substring(4, 6), 16) / 255;
665
+ const max = Math.max(r, g, b);
666
+ const min = Math.min(r, g, b);
667
+ const l = (max + min) / 2;
668
+ if (max === min) {
669
+ return { h: 0, s: 0, l: Math.round(l * 100) };
670
+ }
671
+ const d = max - min;
672
+ const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
673
+ let h;
674
+ if (max === r) {
675
+ h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
676
+ } else if (max === g) {
677
+ h = ((b - r) / d + 2) / 6;
678
+ } else {
679
+ h = ((r - g) / d + 4) / 6;
680
+ }
681
+ return {
682
+ h: Math.round(h * 360),
683
+ s: Math.round(s * 100),
684
+ l: Math.round(l * 100)
685
+ };
686
+ }
687
+ function hslToHex(h, s, l) {
688
+ const sNorm = s / 100;
796
689
  const lNorm = l / 100;
797
690
  if (sNorm === 0) {
798
691
  const v = Math.round(lNorm * 255);
@@ -1866,6 +1759,7 @@ __export(palettes_exports, {
1866
1759
  monokaiPalette: () => monokaiPalette,
1867
1760
  nordPalette: () => nordPalette,
1868
1761
  oneDarkPalette: () => oneDarkPalette,
1762
+ palettes: () => palettes,
1869
1763
  registerPalette: () => registerPalette,
1870
1764
  rosePinePalette: () => rosePinePalette,
1871
1765
  shade: () => shade,
@@ -1874,6 +1768,7 @@ __export(palettes_exports, {
1874
1768
  tint: () => tint,
1875
1769
  tokyoNightPalette: () => tokyoNightPalette
1876
1770
  });
1771
+ var palettes;
1877
1772
  var init_palettes = __esm({
1878
1773
  "src/palettes/index.ts"() {
1879
1774
  "use strict";
@@ -1889,6 +1784,28 @@ var init_palettes = __esm({
1889
1784
  init_tokyo_night();
1890
1785
  init_dracula();
1891
1786
  init_monokai();
1787
+ init_bold();
1788
+ init_catppuccin();
1789
+ init_dracula();
1790
+ init_gruvbox();
1791
+ init_monokai();
1792
+ init_nord();
1793
+ init_one_dark();
1794
+ init_rose_pine();
1795
+ init_solarized();
1796
+ init_tokyo_night();
1797
+ palettes = {
1798
+ nord: nordPalette,
1799
+ catppuccin: catppuccinPalette,
1800
+ solarized: solarizedPalette,
1801
+ gruvbox: gruvboxPalette,
1802
+ tokyoNight: tokyoNightPalette,
1803
+ oneDark: oneDarkPalette,
1804
+ rosePine: rosePinePalette,
1805
+ dracula: draculaPalette,
1806
+ monokai: monokaiPalette,
1807
+ bold: boldPalette
1808
+ };
1892
1809
  }
1893
1810
  });
1894
1811
 
@@ -2893,10 +2810,6 @@ function centerRowItems(items, containerWidth, totalControlsW, controlsGroupW =
2893
2810
  x += item.width + LEGEND_GROUP_GAP;
2894
2811
  }
2895
2812
  }
2896
- function getLegendReservedHeight(config, state, containerWidth) {
2897
- const layout = computeLegendLayout(config, state, containerWidth);
2898
- return layout.height;
2899
- }
2900
2813
  var CONTROL_PILL_PAD, CONTROL_FONT_SIZE, CONTROL_ICON_GAP, CONTROL_GAP;
2901
2814
  var init_legend_layout = __esm({
2902
2815
  "src/utils/legend-layout.ts"() {
@@ -2915,7 +2828,7 @@ function renderLegendD3(container, config, state, palette, isDark, callbacks, co
2915
2828
  let currentState = { ...state };
2916
2829
  let currentLayout;
2917
2830
  const legendG = container.append("g").attr("class", "dgmo-legend");
2918
- function render2() {
2831
+ function render3() {
2919
2832
  currentLayout = computeLegendLayout(config, currentState, width);
2920
2833
  legendG.selectAll("*").remove();
2921
2834
  if (currentLayout.height === 0) return;
@@ -2966,11 +2879,11 @@ function renderLegendD3(container, config, state, palette, isDark, callbacks, co
2966
2879
  );
2967
2880
  }
2968
2881
  }
2969
- render2();
2882
+ render3();
2970
2883
  return {
2971
2884
  setState(newState) {
2972
2885
  currentState = { ...newState };
2973
- render2();
2886
+ render3();
2974
2887
  },
2975
2888
  destroy() {
2976
2889
  legendG.remove();
@@ -3428,38 +3341,6 @@ function normalizeName(input) {
3428
3341
  function displayName(input) {
3429
3342
  return input.normalize("NFC").trim();
3430
3343
  }
3431
- function getOrCreateName(input, store, lineNumber, aliasStore) {
3432
- if (aliasStore !== void 0) {
3433
- const aliased = aliasStore.get(input.trim());
3434
- if (aliased !== void 0) {
3435
- return { entry: aliased, created: false };
3436
- }
3437
- }
3438
- const key = normalizeName(input);
3439
- const incomingDisplay = displayName(input);
3440
- const existing = store.get(key);
3441
- if (existing) {
3442
- if (existing.displayLabel !== incomingDisplay) {
3443
- return {
3444
- entry: existing,
3445
- created: false,
3446
- merged: {
3447
- existingLine: existing.declaredLine,
3448
- existingDisplay: existing.displayLabel,
3449
- incomingDisplay
3450
- }
3451
- };
3452
- }
3453
- return { entry: existing, created: false };
3454
- }
3455
- const entry = {
3456
- normalizedKey: key,
3457
- displayLabel: incomingDisplay,
3458
- declaredLine: lineNumber
3459
- };
3460
- store.set(key, entry);
3461
- return { entry, created: true };
3462
- }
3463
3344
  var WHITESPACE_RUN_RE;
3464
3345
  var init_name_normalize = __esm({
3465
3346
  "src/utils/name-normalize.ts"() {
@@ -3468,6 +3349,113 @@ var init_name_normalize = __esm({
3468
3349
  }
3469
3350
  });
3470
3351
 
3352
+ // src/utils/arrows.ts
3353
+ function validateLabelCharacters(label, lineNumber) {
3354
+ const out = [];
3355
+ if (label.includes("->") || label.includes("~>")) {
3356
+ out.push(
3357
+ makeDgmoError(
3358
+ lineNumber,
3359
+ 'Arrow symbols (-> or ~>) are not allowed inside a label. Move the label after the arrow: "A -> B: uses -> to chain". See "In-Arrow Message Labels" \u2192 Forbidden.',
3360
+ "error",
3361
+ ARROW_DIAGNOSTIC_CODES.ARROW_SUBSTRING_IN_LABEL
3362
+ )
3363
+ );
3364
+ }
3365
+ for (const ch of label) {
3366
+ const cp = ch.codePointAt(0);
3367
+ const isC0 = cp >= 0 && cp <= 31 && cp !== 9;
3368
+ const isDel = cp === 127;
3369
+ if (isC0 || isDel) {
3370
+ const hex = cp.toString(16).toUpperCase().padStart(4, "0");
3371
+ out.push(
3372
+ makeDgmoError(
3373
+ lineNumber,
3374
+ `Label contains a control character (U+${hex}). Remove it and use plain text.`,
3375
+ "error",
3376
+ ARROW_DIAGNOSTIC_CODES.CONTROL_CHAR_IN_LABEL
3377
+ )
3378
+ );
3379
+ break;
3380
+ }
3381
+ }
3382
+ return out;
3383
+ }
3384
+ function parseInArrowLabel(rawLabel, lineNumber) {
3385
+ const trimmed = rawLabel.trim();
3386
+ if (trimmed.length === 0) {
3387
+ return { label: void 0, diagnostics: [] };
3388
+ }
3389
+ const diagnostics = validateLabelCharacters(trimmed, lineNumber);
3390
+ return { label: trimmed, diagnostics };
3391
+ }
3392
+ function matchColorParens(content) {
3393
+ const m = content.match(/^\(([A-Za-z]+)\)$/);
3394
+ if (!m) return null;
3395
+ const candidate = m[1].toLowerCase();
3396
+ if (RECOGNIZED_COLOR_NAMES.includes(candidate)) {
3397
+ return candidate;
3398
+ }
3399
+ return null;
3400
+ }
3401
+ function parseArrow(line12) {
3402
+ if (BIDI_SYNC_RE.test(line12) || BIDI_ASYNC_RE.test(line12)) {
3403
+ return {
3404
+ error: "Bidirectional arrows are no longer supported. Use two separate lines: 'A -msg-> B' and 'B -msg-> A'"
3405
+ };
3406
+ }
3407
+ if (RETURN_SYNC_LABELED_RE.test(line12) || RETURN_ASYNC_LABELED_RE.test(line12)) {
3408
+ const m = line12.match(RETURN_SYNC_LABELED_RE) ?? line12.match(RETURN_ASYNC_LABELED_RE);
3409
+ const from = m[3];
3410
+ const to = m[1];
3411
+ const label = m[2].trim();
3412
+ return {
3413
+ error: `Left-pointing arrows are no longer supported. Write '${from} -${label}-> ${to}' instead`
3414
+ };
3415
+ }
3416
+ const patterns = [
3417
+ { re: SYNC_LABELED_RE, async: false },
3418
+ { re: ASYNC_LABELED_RE, async: true }
3419
+ ];
3420
+ for (const { re, async: isAsync } of patterns) {
3421
+ const m = line12.match(re);
3422
+ if (!m) continue;
3423
+ const label = m[2].trim();
3424
+ if (!label) return null;
3425
+ return {
3426
+ from: m[1],
3427
+ to: m[3],
3428
+ label,
3429
+ async: isAsync
3430
+ };
3431
+ }
3432
+ return null;
3433
+ }
3434
+ var ARROW_DIAGNOSTIC_CODES, SYNC_LABELED_RE, ASYNC_LABELED_RE, RETURN_SYNC_LABELED_RE, RETURN_ASYNC_LABELED_RE, BIDI_SYNC_RE, BIDI_ASYNC_RE;
3435
+ var init_arrows = __esm({
3436
+ "src/utils/arrows.ts"() {
3437
+ "use strict";
3438
+ init_diagnostics();
3439
+ init_colors();
3440
+ ARROW_DIAGNOSTIC_CODES = {
3441
+ /** Active: label contains `->` or `~>` substring (TD-13). */
3442
+ ARROW_SUBSTRING_IN_LABEL: "E_ARROW_SUBSTRING_IN_LABEL",
3443
+ /** Active: label contains a forbidden control character (TD-14). */
3444
+ CONTROL_CHAR_IN_LABEL: "E_CONTROL_CHAR_IN_LABEL",
3445
+ /** Reserved: not currently emitted by any parser. See JSDoc above. */
3446
+ TRAILING_ARROW_TEXT: "E_TRAILING_ARROW_TEXT",
3447
+ /** Reserved: not currently emitted by any parser. See JSDoc above. */
3448
+ MIXED_ARROW_DELIMITERS: "E_MIXED_ARROW_DELIMITERS"
3449
+ };
3450
+ SYNC_LABELED_RE = /^(.+?)\s*-(.+)->\s*(.+)$/;
3451
+ ASYNC_LABELED_RE = /^(.+?)\s*~(.+)~>\s*(.+)$/;
3452
+ RETURN_SYNC_LABELED_RE = /^(.+?)\s*<-(.+)-\s*(.+)$/;
3453
+ RETURN_ASYNC_LABELED_RE = /^(.+?)\s*<~(.+)~\s*(.+)$/;
3454
+ BIDI_SYNC_RE = /^(.+?)\s*<-(.+)->\s*(.+)$/;
3455
+ BIDI_ASYNC_RE = /^(.+?)\s*<~(.+)~>\s*(.+)$/;
3456
+ }
3457
+ });
3458
+
3471
3459
  // src/sequence/parser.ts
3472
3460
  var parser_exports = {};
3473
3461
  __export(parser_exports, {
@@ -6564,19 +6552,6 @@ function renderLegendSvg(groups, options) {
6564
6552
  const svg = `<g${classAttr}${activeAttr}>${parts.join("")}</g>`;
6565
6553
  return { svg, height: LEGEND_HEIGHT, width: totalWidth };
6566
6554
  }
6567
- function renderLegendSvgFromConfig(config, state, palette, containerWidth) {
6568
- return renderLegendSvg(config.groups, {
6569
- palette: {
6570
- bg: palette.bg,
6571
- surface: palette.surface,
6572
- text: palette.text,
6573
- textMuted: palette.textMuted
6574
- },
6575
- isDark: palette.isDark,
6576
- containerWidth,
6577
- activeGroup: state.activeGroup
6578
- });
6579
- }
6580
6555
  var init_legend_svg = __esm({
6581
6556
  "src/utils/legend-svg.ts"() {
6582
6557
  "use strict";
@@ -10957,6 +10932,17 @@ function parseInfra(content) {
10957
10932
  if (!m) return { label: trimmed };
10958
10933
  return { label: m[1].trim(), alias: m[2] };
10959
10934
  }
10935
+ const IS_A_SUFFIX = /^(.*?)\s+is\s+an?\s+[A-Za-z][\w-]*\s*$/i;
10936
+ function peelInfraDecorations(rawName, lineNumber) {
10937
+ const peeled = peelAlias2(rawName);
10938
+ const m = peeled.label.match(IS_A_SUFFIX);
10939
+ if (!m) return peeled;
10940
+ warn(
10941
+ lineNumber,
10942
+ `Infra nodes don't use 'is a <type>' \u2014 types are inferred from properties (cache-hit, buffer, drain-rate, \u2026). Drop the 'is a' suffix.`
10943
+ );
10944
+ return { label: m[1].trim(), alias: peeled.alias };
10945
+ }
10960
10946
  function resolveTargetId(rawName) {
10961
10947
  const aliasResolved = nameAliasMap.get(rawName.trim());
10962
10948
  if (aliasResolved !== void 0) return aliasResolved;
@@ -11111,7 +11097,7 @@ function parseInfra(content) {
11111
11097
  finishCurrentNode();
11112
11098
  finishCurrentTagGroup();
11113
11099
  const rawName = (compMatch[1] ?? compMatch[2] ?? "").trim();
11114
- const peeled = peelAlias2(rawName);
11100
+ const peeled = peelInfraDecorations(rawName, lineNumber);
11115
11101
  const name = peeled.label;
11116
11102
  const rest = compMatch[3] || "";
11117
11103
  const { tags } = extractPipeMetadata(rest);
@@ -11182,7 +11168,7 @@ function parseInfra(content) {
11182
11168
  if (compMatch) {
11183
11169
  finishCurrentTagGroup();
11184
11170
  const rawName = (compMatch[1] ?? compMatch[2] ?? "").trim();
11185
- const peeled = peelAlias2(rawName);
11171
+ const peeled = peelInfraDecorations(rawName, lineNumber);
11186
11172
  const name = peeled.label;
11187
11173
  const rest = compMatch[3] || "";
11188
11174
  const { tags: nodeTags } = extractPipeMetadata(rest);
@@ -11401,7 +11387,7 @@ function parseInfra(content) {
11401
11387
  const compMatch = trimmed.match(COMPONENT_RE);
11402
11388
  if (compMatch) {
11403
11389
  const rawName = (compMatch[1] ?? compMatch[2] ?? "").trim();
11404
- const peeled = peelAlias2(rawName);
11390
+ const peeled = peelInfraDecorations(rawName, lineNumber);
11405
11391
  const name = peeled.label;
11406
11392
  const rest = compMatch[3] || "";
11407
11393
  const { tags: nodeTags } = extractPipeMetadata(rest);
@@ -11427,10 +11413,13 @@ function parseInfra(content) {
11427
11413
  finishCurrentNode();
11428
11414
  finishCurrentTagGroup();
11429
11415
  currentGroup = null;
11430
- const name = (compMatch[1] ?? compMatch[2] ?? "").trim();
11416
+ const rawName = (compMatch[1] ?? compMatch[2] ?? "").trim();
11417
+ const peeled = peelInfraDecorations(rawName, lineNumber);
11418
+ const name = peeled.label;
11431
11419
  const rest = compMatch[3] || "";
11432
11420
  const { tags } = extractPipeMetadata(rest);
11433
11421
  const id = nodeId2(name);
11422
+ if (peeled.alias) nameAliasMap.set(peeled.alias, id);
11434
11423
  currentNode = {
11435
11424
  id,
11436
11425
  label: name,
@@ -11480,6 +11469,14 @@ function parseInfra(content) {
11480
11469
  validateTagGroupNames(result.tagGroups, warn, setError);
11481
11470
  return result;
11482
11471
  }
11472
+ function stripNodeDecorations(name) {
11473
+ let s = name.trim();
11474
+ const aliasMatch = s.match(/^(.*?)\s+as\s+[A-Za-z][A-Za-z0-9_]{0,11}\s*$/);
11475
+ if (aliasMatch) s = aliasMatch[1].trim();
11476
+ const isAMatch = s.match(/^(.*?)\s+is\s+an?\s+[A-Za-z][\w-]*\s*$/i);
11477
+ if (isAMatch) s = isAMatch[1].trim();
11478
+ return s;
11479
+ }
11483
11480
  function extractSymbols4(docText) {
11484
11481
  const entities = [];
11485
11482
  let inMetadata = true;
@@ -11513,7 +11510,7 @@ function extractSymbols4(docText) {
11513
11510
  if (/^\[/.test(line12)) continue;
11514
11511
  const m = COMPONENT_RE.exec(line12);
11515
11512
  if (m) {
11516
- const name = (m[1] ?? m[2] ?? "").trim();
11513
+ const name = stripNodeDecorations((m[1] ?? m[2] ?? "").trim());
11517
11514
  if (name && !entities.includes(name)) entities.push(name);
11518
11515
  }
11519
11516
  } else {
@@ -11528,7 +11525,7 @@ function extractSymbols4(docText) {
11528
11525
  continue;
11529
11526
  const m = COMPONENT_RE.exec(line12);
11530
11527
  if (m) {
11531
- const name = (m[1] ?? m[2] ?? "").trim();
11528
+ const name = stripNodeDecorations((m[1] ?? m[2] ?? "").trim());
11532
11529
  if (name && !entities.includes(name)) entities.push(name);
11533
11530
  }
11534
11531
  }
@@ -17369,7 +17366,7 @@ var init_parser19 = __esm({
17369
17366
  });
17370
17367
 
17371
17368
  // src/chart-types.ts
17372
- var chartTypes, BETA_CHART_IDS;
17369
+ var chartTypes;
17373
17370
  var init_chart_types = __esm({
17374
17371
  "src/chart-types.ts"() {
17375
17372
  "use strict";
@@ -17828,7 +17825,6 @@ var init_chart_types = __esm({
17828
17825
  fallback: true
17829
17826
  }
17830
17827
  ];
17831
- BETA_CHART_IDS = /* @__PURE__ */ new Set(["c4", "venn"]);
17832
17828
  }
17833
17829
  });
17834
17830
 
@@ -20637,106 +20633,6 @@ var init_renderer2 = __esm({
20637
20633
  });
20638
20634
 
20639
20635
  // src/kanban/mutations.ts
20640
- function computeCardMove(content, parsed, cardId, targetColumnId, targetIndex) {
20641
- let sourceCard = null;
20642
- let sourceColumn = null;
20643
- for (const col of parsed.columns) {
20644
- for (const card of col.cards) {
20645
- if (card.id === cardId) {
20646
- sourceCard = card;
20647
- sourceColumn = col;
20648
- break;
20649
- }
20650
- }
20651
- if (sourceCard) break;
20652
- }
20653
- if (!sourceCard || !sourceColumn) return null;
20654
- const targetColumn = parsed.columns.find((c) => c.id === targetColumnId);
20655
- if (!targetColumn) return null;
20656
- const lines = content.split("\n");
20657
- const startIdx = sourceCard.lineNumber - 1;
20658
- const endIdx = sourceCard.endLineNumber - 1;
20659
- const cardLines = lines.slice(startIdx, endIdx + 1);
20660
- const withoutCard = [
20661
- ...lines.slice(0, startIdx),
20662
- ...lines.slice(endIdx + 1)
20663
- ];
20664
- let insertIdx;
20665
- const removedCount = endIdx - startIdx + 1;
20666
- const adjustLine = (ln) => {
20667
- if (ln > endIdx + 1) return ln - removedCount;
20668
- return ln;
20669
- };
20670
- if (targetIndex === 0) {
20671
- const adjColLine = adjustLine(targetColumn.lineNumber);
20672
- insertIdx = adjColLine;
20673
- } else {
20674
- const targetCards = targetColumn.cards.filter((c) => c.id !== cardId);
20675
- const clampedIdx = Math.min(targetIndex, targetCards.length);
20676
- const precedingCard = targetCards[clampedIdx - 1];
20677
- if (!precedingCard) {
20678
- const adjColLine = adjustLine(targetColumn.lineNumber);
20679
- insertIdx = adjColLine;
20680
- } else {
20681
- const adjEndLine = adjustLine(precedingCard.endLineNumber);
20682
- insertIdx = adjEndLine;
20683
- }
20684
- }
20685
- const result = [
20686
- ...withoutCard.slice(0, insertIdx),
20687
- ...cardLines,
20688
- ...withoutCard.slice(insertIdx)
20689
- ];
20690
- return result.join("\n");
20691
- }
20692
- function computeCardArchive(content, parsed, cardId) {
20693
- let sourceCard = null;
20694
- for (const col of parsed.columns) {
20695
- for (const card of col.cards) {
20696
- if (card.id === cardId) {
20697
- sourceCard = card;
20698
- break;
20699
- }
20700
- }
20701
- if (sourceCard) break;
20702
- }
20703
- if (!sourceCard) return null;
20704
- const lines = content.split("\n");
20705
- const startIdx = sourceCard.lineNumber - 1;
20706
- const endIdx = sourceCard.endLineNumber - 1;
20707
- const cardLines = lines.slice(startIdx, endIdx + 1);
20708
- const withoutCard = [
20709
- ...lines.slice(0, startIdx),
20710
- ...lines.slice(endIdx + 1)
20711
- ];
20712
- const archiveCol = parsed.columns.find(
20713
- (c) => c.name.toLowerCase() === ARCHIVE_COLUMN_NAME
20714
- );
20715
- if (archiveCol) {
20716
- const removedCount = endIdx - startIdx + 1;
20717
- let archiveEndLine = archiveCol.lineNumber;
20718
- if (archiveCol.cards.length > 0) {
20719
- const lastCard = archiveCol.cards[archiveCol.cards.length - 1];
20720
- archiveEndLine = lastCard.endLineNumber;
20721
- }
20722
- if (archiveEndLine > endIdx + 1) {
20723
- archiveEndLine -= removedCount;
20724
- }
20725
- const insertIdx = archiveEndLine;
20726
- return [
20727
- ...withoutCard.slice(0, insertIdx),
20728
- ...cardLines,
20729
- ...withoutCard.slice(insertIdx)
20730
- ].join("\n");
20731
- } else {
20732
- const trimmedEnd = withoutCard.length > 0 && withoutCard[withoutCard.length - 1].trim() === "" ? withoutCard : [...withoutCard, ""];
20733
- return [
20734
- ...trimmedEnd,
20735
- "[Archive]",
20736
- ...cardLines
20737
- ].join("\n");
20738
- }
20739
- }
20740
20636
  function isArchiveColumn(name) {
20741
20637
  return name.toLowerCase() === ARCHIVE_COLUMN_NAME;
20742
20638
  }
@@ -38433,7 +38329,7 @@ function renderHtmlPanel(panel, parsed, quadrant, qColor, palette, isDark, rootC
38433
38329
  solid: parsed.options["solid-fill"] === "on"
38434
38330
  });
38435
38331
  let expandedLineNum = null;
38436
- function render2() {
38332
+ function render3() {
38437
38333
  panel.innerHTML = "";
38438
38334
  for (const ringName of ringOrder) {
38439
38335
  const blips = quadrant.blips.filter((b) => b.ring === ringName);
@@ -38543,7 +38439,7 @@ function renderHtmlPanel(panel, parsed, quadrant, qColor, palette, isDark, rootC
38543
38439
  if (hasDesc) {
38544
38440
  const wasExpanded = expandedLineNum === ln;
38545
38441
  expandedLineNum = wasExpanded ? null : ln;
38546
- render2();
38442
+ render3();
38547
38443
  if (!wasExpanded) {
38548
38444
  requestAnimationFrame(() => {
38549
38445
  dimExcept(rootContainer, ln);
@@ -38573,11 +38469,11 @@ function renderHtmlPanel(panel, parsed, quadrant, qColor, palette, isDark, rootC
38573
38469
  }
38574
38470
  }
38575
38471
  }
38576
- render2();
38472
+ render3();
38577
38473
  panel.addEventListener("click", () => {
38578
38474
  if (expandedLineNum) {
38579
38475
  expandedLineNum = null;
38580
- render2();
38476
+ render3();
38581
38477
  clearDim(rootContainer);
38582
38478
  rootContainer.querySelectorAll("svg [data-line-number]").forEach((el) => el.removeAttribute("transform"));
38583
38479
  }
@@ -38588,7 +38484,7 @@ function renderHtmlPanel(panel, parsed, quadrant, qColor, palette, isDark, rootC
38588
38484
  if (blip && blip.description.length > 0) {
38589
38485
  const wasExpanded = expandedLineNum === ln;
38590
38486
  expandedLineNum = wasExpanded ? null : ln;
38591
- render2();
38487
+ render3();
38592
38488
  const node = panel.querySelector(`[data-line-number="${ln}"]`);
38593
38489
  if (node) node.scrollIntoView({ behavior: "smooth", block: "nearest" });
38594
38490
  if (!wasExpanded) {
@@ -38664,226 +38560,6 @@ function renderInlineMarkdownHtml(text, palette) {
38664
38560
  function escapeHtml(text) {
38665
38561
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
38666
38562
  }
38667
- function renderQuadrantFocusForExport(container, parsed, quadrantPosition, palette, isDark, exportDims) {
38668
- const quadrant = parsed.quadrants.find(
38669
- (q) => q.position === quadrantPosition
38670
- );
38671
- if (!quadrant) return;
38672
- container.innerHTML = "";
38673
- const width = exportDims.width;
38674
- const height = exportDims.height;
38675
- const qColor = resolveQuadrantColor(
38676
- quadrant.position,
38677
- quadrant.color,
38678
- palette
38679
- );
38680
- const titleBar = document.createElement("div");
38681
- titleBar.style.cssText = `
38682
- display: flex; align-items: baseline; gap: 8px;
38683
- padding: 12px 16px; font-family: ${FONT_FAMILY};
38684
- font-size: ${TITLE_FONT_SIZE2 + 2}px; background: ${palette.bg};
38685
- `;
38686
- const titleText = document.createElement("span");
38687
- titleText.textContent = parsed.title || "Tech Radar";
38688
- titleText.style.cssText = `font-weight: bold; color: ${palette.text};`;
38689
- const sep = document.createElement("span");
38690
- sep.textContent = "\u203A";
38691
- sep.style.color = palette.border;
38692
- const quadrantLabel = document.createElement("span");
38693
- quadrantLabel.textContent = quadrant.name;
38694
- quadrantLabel.style.cssText = `font-weight: bold; color: ${qColor};`;
38695
- titleBar.appendChild(titleText);
38696
- titleBar.appendChild(sep);
38697
- titleBar.appendChild(quadrantLabel);
38698
- container.appendChild(titleBar);
38699
- const mainLayout = document.createElement("div");
38700
- mainLayout.style.cssText = `
38701
- display: flex; flex-direction: row;
38702
- height: ${height - 48}px; background: ${palette.bg};
38703
- `;
38704
- container.appendChild(mainLayout);
38705
- const svgContainer = document.createElement("div");
38706
- svgContainer.style.cssText = `width: 45%; min-width: 200px; flex-shrink: 0;`;
38707
- mainLayout.appendChild(svgContainer);
38708
- const panel = document.createElement("div");
38709
- panel.style.cssText = `
38710
- flex: 1; padding: 8px 16px;
38711
- font-family: ${FONT_FAMILY}; background: ${palette.bg};
38712
- `;
38713
- mainLayout.appendChild(panel);
38714
- renderStaticHtmlPanel(panel, parsed, quadrant, qColor, palette, isDark);
38715
- const svgWidth = width * 0.45;
38716
- const svgHeight = height - 48;
38717
- const svg = d3Selection15.select(svgContainer).append("svg").attr("width", svgWidth).attr("height", svgHeight).attr("viewBox", `0 0 ${svgWidth} ${svgHeight}`).style("background", palette.bg);
38718
- renderQuarterCircleStatic(
38719
- svg,
38720
- parsed,
38721
- quadrant,
38722
- qColor,
38723
- palette,
38724
- isDark,
38725
- svgWidth,
38726
- svgHeight,
38727
- palette.border
38728
- );
38729
- }
38730
- function renderQuarterCircleStatic(svg, parsed, quadrant, qColor, palette, isDark, width, height, mutedColor) {
38731
- const padding = 8;
38732
- const size = Math.min(width - padding, height - padding);
38733
- const maxRadius = size * 0.95;
38734
- const ringCount = parsed.rings.length;
38735
- const ringBandWidth = maxRadius / ringCount;
38736
- const { startAngle, endAngle } = getQuadrantArc(quadrant.position);
38737
- let cx, cy;
38738
- switch (quadrant.position) {
38739
- case "top-right":
38740
- cx = padding;
38741
- cy = size + padding;
38742
- break;
38743
- case "top-left":
38744
- cx = width - padding;
38745
- cy = size + padding;
38746
- break;
38747
- case "bottom-left":
38748
- cx = width - padding;
38749
- cy = padding;
38750
- break;
38751
- case "bottom-right":
38752
- cx = padding;
38753
- cy = padding;
38754
- break;
38755
- }
38756
- const arcGen = (innerR, outerR) => `M${cx + outerR * Math.cos(startAngle)},${cy - outerR * Math.sin(startAngle)} A${outerR},${outerR} 0 0,0 ${cx + outerR * Math.cos(endAngle)},${cy - outerR * Math.sin(endAngle)} L${cx + innerR * Math.cos(endAngle)},${cy - innerR * Math.sin(endAngle)} A${innerR},${innerR} 0 0,1 ${cx + innerR * Math.cos(startAngle)},${cy - innerR * Math.sin(startAngle)} Z`;
38757
- for (let ri = parsed.rings.length - 1; ri >= 0; ri--) {
38758
- const innerR = ri * ringBandWidth;
38759
- const outerR = (ri + 1) * ringBandWidth;
38760
- const fillColor = ri % 2 === 0 ? palette.bg : mix(palette.bg, palette.border, 0.15);
38761
- svg.append("path").attr("d", arcGen(innerR, outerR)).attr("fill", fillColor).attr("stroke", mutedColor).attr("stroke-width", 0.5);
38762
- }
38763
- for (let ri = 0; ri < parsed.rings.length; ri++) {
38764
- const rCenter = (ri + 0.5) * ringBandWidth;
38765
- const midAngle = (startAngle + endAngle) / 2;
38766
- const labelX = cx + rCenter * Math.cos(midAngle);
38767
- const labelY = cy - rCenter * Math.sin(midAngle);
38768
- svg.append("text").attr("x", labelX).attr("y", labelY).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("fill", palette.textMuted).attr("font-family", FONT_FAMILY).attr("font-size", 11).attr("font-weight", "600").attr("opacity", 0.5).text(parsed.rings[ri].name);
38769
- }
38770
- const ringOrder = parsed.rings.map((r) => r.name);
38771
- const angularPadding = 0.08;
38772
- const radialPadding = ringBandWidth * 0.12;
38773
- const usableArcStart = startAngle + angularPadding;
38774
- const usableArcEnd = endAngle - angularPadding;
38775
- const arcSpan = usableArcEnd - usableArcStart;
38776
- const blipsByRing = /* @__PURE__ */ new Map();
38777
- for (const blip of quadrant.blips) {
38778
- const list = blipsByRing.get(blip.ring) ?? [];
38779
- list.push(blip);
38780
- blipsByRing.set(blip.ring, list);
38781
- }
38782
- for (const [ringName, blips] of blipsByRing) {
38783
- const ringIndex = ringOrder.indexOf(ringName);
38784
- if (ringIndex < 0) continue;
38785
- const rInner = ringIndex * ringBandWidth + radialPadding;
38786
- const rOuter = (ringIndex + 1) * ringBandWidth - radialPadding;
38787
- const rMid = (rInner + rOuter) / 2;
38788
- for (let bi = 0; bi < blips.length; bi++) {
38789
- const blip = blips[bi];
38790
- const angle = blips.length === 1 ? (usableArcStart + usableArcEnd) / 2 : usableArcStart + (bi + 0.5) / blips.length * arcSpan;
38791
- const radius = blips.length <= 3 ? rMid : rInner + BLIP_RADIUS + bi % 3 / 2 * (rOuter - rInner - BLIP_RADIUS * 2);
38792
- const bx = cx + radius * Math.cos(angle);
38793
- const by = cy - radius * Math.sin(angle);
38794
- const blipGroup = svg.append("g");
38795
- const angleToCenter = Math.atan2(cy - by, cx - bx);
38796
- renderTrendIndicator(
38797
- blipGroup,
38798
- blip.trend,
38799
- qColor,
38800
- bx,
38801
- by,
38802
- BLIP_RADIUS,
38803
- angleToCenter
38804
- );
38805
- blipGroup.append("text").attr("x", bx).attr("y", by + 3).attr("text-anchor", "middle").attr("fill", isDark ? "#000" : "#fff").attr("font-family", FONT_FAMILY).attr("font-size", BLIP_FONT_SIZE).attr("font-weight", "bold").text(blip.globalNumber);
38806
- }
38807
- }
38808
- }
38809
- function renderStaticHtmlPanel(panel, parsed, quadrant, qColor, palette, isDark) {
38810
- const ringOrder = parsed.rings.map((r) => r.name);
38811
- const fillColor = shapeFill(palette, qColor, isDark, {
38812
- solid: parsed.options["solid-fill"] === "on"
38813
- });
38814
- for (const ringName of ringOrder) {
38815
- const blips = quadrant.blips.filter((b) => b.ring === ringName);
38816
- if (blips.length === 0) continue;
38817
- const ringGroup = document.createElement("div");
38818
- ringGroup.style.cssText = `
38819
- background: ${palette.surface};
38820
- border-radius: 8px;
38821
- padding: 10px;
38822
- margin-bottom: 12px;
38823
- `;
38824
- const header = document.createElement("div");
38825
- header.style.cssText = `
38826
- font-size: 13px; font-weight: 700; color: ${palette.textMuted};
38827
- margin-bottom: 8px;
38828
- `;
38829
- header.textContent = ringName;
38830
- ringGroup.appendChild(header);
38831
- panel.appendChild(ringGroup);
38832
- for (const blip of blips) {
38833
- const hasDesc = blip.description.length > 0;
38834
- const node = document.createElement("div");
38835
- node.style.cssText = `
38836
- background: ${fillColor}; border: 1.5px solid ${qColor};
38837
- border-radius: 6px; margin-bottom: 6px;
38838
- `;
38839
- const titleRow = document.createElement("div");
38840
- titleRow.style.cssText = `
38841
- display: flex; align-items: center; gap: 8px;
38842
- padding: 6px 10px; min-height: 28px;
38843
- `;
38844
- const indicatorSvg = document.createElementNS(
38845
- "http://www.w3.org/2000/svg",
38846
- "svg"
38847
- );
38848
- indicatorSvg.setAttribute("width", "26");
38849
- indicatorSvg.setAttribute("height", "26");
38850
- indicatorSvg.style.flexShrink = "0";
38851
- const indicatorG = d3Selection15.select(indicatorSvg).append("g");
38852
- renderTrendIndicator(
38853
- indicatorG,
38854
- blip.trend,
38855
- qColor,
38856
- 13,
38857
- 13,
38858
- 10,
38859
- -Math.PI / 2
38860
- );
38861
- d3Selection15.select(indicatorSvg).append("text").attr("x", 13).attr("y", 16).attr("text-anchor", "middle").attr("fill", isDark ? "#000" : "#fff").attr("font-family", FONT_FAMILY).attr("font-size", 9).attr("font-weight", "bold").text(blip.globalNumber);
38862
- titleRow.appendChild(indicatorSvg);
38863
- const name = document.createElement("span");
38864
- name.textContent = blip.name;
38865
- name.style.cssText = `
38866
- flex: 1; font-size: 12px; font-weight: 600;
38867
- color: ${palette.text};
38868
- `;
38869
- titleRow.appendChild(name);
38870
- node.appendChild(titleRow);
38871
- if (hasDesc) {
38872
- const sepDiv = document.createElement("div");
38873
- sepDiv.style.cssText = `border-top: 1px solid ${qColor}; opacity: 0.3;`;
38874
- node.appendChild(sepDiv);
38875
- const descDiv = document.createElement("div");
38876
- descDiv.style.cssText = `
38877
- padding: 6px 10px 8px; font-size: 11px; line-height: 1.6;
38878
- color: ${palette.textMuted};
38879
- `;
38880
- descDiv.innerHTML = renderDescriptionHtml(blip.description, palette);
38881
- node.appendChild(descDiv);
38882
- }
38883
- ringGroup.appendChild(node);
38884
- }
38885
- }
38886
- }
38887
38563
  var BLIP_RADIUS, BLIP_FONT_SIZE, TITLE_FONT_SIZE2, NARROW_BREAKPOINT;
38888
38564
  var init_interactive = __esm({
38889
38565
  "src/tech-radar/interactive.ts"() {
@@ -47612,53 +47288,6 @@ function getRotateFn(mode) {
47612
47288
  if (mode === "angled") return () => Math.round(Math.random() * 30 - 15);
47613
47289
  return () => 0;
47614
47290
  }
47615
- function renderWordCloud(container, parsed, palette, _isDark, onClickItem, exportDims) {
47616
- const { words, cloudOptions } = parsed;
47617
- const title = parsed.noTitle ? null : parsed.title;
47618
- if (words.length === 0) return;
47619
- const init2 = initD3Chart(container, palette, exportDims);
47620
- if (!init2) return;
47621
- const { svg, width, height, textColor, colors } = init2;
47622
- const titleHeight = title ? 40 : 0;
47623
- const cloudHeight = height - titleHeight;
47624
- const { minSize, maxSize } = cloudOptions;
47625
- const weights = words.map((w) => w.weight);
47626
- const minWeight = Math.min(...weights);
47627
- const maxWeight = Math.max(...weights);
47628
- const range = maxWeight - minWeight || 1;
47629
- const fontSize = (weight) => {
47630
- const t = (weight - minWeight) / range;
47631
- return minSize + Math.sqrt(t) * (maxSize - minSize);
47632
- };
47633
- const rotateFn = getRotateFn(cloudOptions.rotate);
47634
- renderChartTitle(
47635
- svg,
47636
- title,
47637
- parsed.titleLineNumber,
47638
- width,
47639
- textColor,
47640
- onClickItem
47641
- );
47642
- const g = svg.append("g").attr(
47643
- "transform",
47644
- `translate(${width / 2},${titleHeight + cloudHeight / 2})`
47645
- );
47646
- cloud().size([width, cloudHeight]).words(words.map((w) => ({ ...w, size: fontSize(w.weight) }))).padding(2).rotate(rotateFn).fontSize((d) => d.size).font(FONT_FAMILY).on("end", (layoutWords) => {
47647
- g.selectAll("text").data(layoutWords).join("text").style("font-size", (d) => `${d.size}px`).style("font-family", FONT_FAMILY).style("font-weight", "600").style("fill", (_d, i) => colors[i % colors.length]).style(
47648
- "cursor",
47649
- (d) => onClickItem && d.lineNumber ? "pointer" : "default"
47650
- ).attr("text-anchor", "middle").attr(
47651
- "transform",
47652
- (d) => `translate(${d.x},${d.y}) rotate(${d.rotate})`
47653
- ).attr("data-line-number", (d) => {
47654
- const ln = d.lineNumber;
47655
- return ln ? String(ln) : null;
47656
- }).text((d) => d.text).on("click", (_event, d) => {
47657
- const ln = d.lineNumber;
47658
- if (onClickItem && ln) onClickItem(ln);
47659
- });
47660
- }).start();
47661
- }
47662
47291
  function renderWordCloudAsync(container, parsed, palette, _isDark, exportDims) {
47663
47292
  return new Promise((resolve) => {
47664
47293
  d3Selection22.select(container).selectAll(":not([data-d3-tooltip])").remove();
@@ -50007,10 +49636,6 @@ var require_lz_string = __commonJS({
50007
49636
  }
50008
49637
  });
50009
49638
 
50010
- // src/index.ts
50011
- init_diagnostics();
50012
- init_arrows();
50013
-
50014
49639
  // src/render.ts
50015
49640
  init_d3();
50016
49641
  init_echarts();
@@ -50018,7 +49643,7 @@ init_dgmo_router();
50018
49643
  init_registry();
50019
49644
  async function ensureDom() {
50020
49645
  if (typeof document !== "undefined") return;
50021
- const { JSDOM } = await import("jsdom");
49646
+ const { JSDOM } = await loadJsdom();
50022
49647
  const dom = new JSDOM("<!DOCTYPE html><html><body></body></html>");
50023
49648
  const win = dom.window;
50024
49649
  Object.defineProperty(globalThis, "document", {
@@ -50042,6 +49667,14 @@ async function ensureDom() {
50042
49667
  configurable: true
50043
49668
  });
50044
49669
  }
49670
+ async function loadJsdom() {
49671
+ const spec = ["js", "dom"].join("");
49672
+ return import(
49673
+ /* @vite-ignore */
49674
+ /* webpackIgnore: true */
49675
+ spec
49676
+ );
49677
+ }
50045
49678
  async function render(content, options) {
50046
49679
  const theme = options?.theme ?? "light";
50047
49680
  const paletteName = options?.palette ?? "nord";
@@ -50070,933 +49703,6 @@ async function render(content, options) {
50070
49703
  return { svg, diagnostics };
50071
49704
  }
50072
49705
 
50073
- // src/index.ts
50074
- init_chart_types();
50075
-
50076
- // src/chart-type-scoring.ts
50077
- init_chart_types();
50078
- var TYPOGRAPHIC_REPLACEMENTS = [
50079
- [/[‘’]/g, "'"],
50080
- // curly single quotes
50081
- [/[“”]/g, '"'],
50082
- // curly double quotes
50083
- [/[–—]/g, "-"],
50084
- // en/em dash
50085
- [/×/g, "x"]
50086
- // unicode multiplication → ASCII (for "2×2" vs "2x2")
50087
- ];
50088
- function normalize(s) {
50089
- let out = s.normalize("NFKD").toLowerCase();
50090
- for (const [re, repl] of TYPOGRAPHIC_REPLACEMENTS)
50091
- out = out.replace(re, repl);
50092
- return out.split(/[^a-z0-9]+/).filter(Boolean);
50093
- }
50094
- function matchesContiguously(promptTokens, triggerTokens) {
50095
- if (triggerTokens.length === 0 || triggerTokens.length > promptTokens.length)
50096
- return false;
50097
- outer: for (let i = 0; i <= promptTokens.length - triggerTokens.length; i++) {
50098
- for (let j = 0; j < triggerTokens.length; j++) {
50099
- if (promptTokens[i + j] !== triggerTokens[j]) continue outer;
50100
- }
50101
- return true;
50102
- }
50103
- return false;
50104
- }
50105
- function scoreChartType(prompt, type) {
50106
- const promptTokens = normalize(prompt);
50107
- const matched = [];
50108
- let score = 0;
50109
- for (const trigger of type.triggers) {
50110
- const triggerTokens = normalize(trigger);
50111
- if (matchesContiguously(promptTokens, triggerTokens)) {
50112
- matched.push(trigger);
50113
- score += triggerTokens.length;
50114
- }
50115
- }
50116
- const descTokens = new Set(normalize(type.description));
50117
- let descHits = 0;
50118
- for (const t of promptTokens) if (descTokens.has(t)) descHits++;
50119
- score += descHits * 0.25;
50120
- return { score, matched };
50121
- }
50122
- var MIN_PRIMARY_SCORE = 1;
50123
- var AMBIGUITY_THRESHOLD = 0.5;
50124
- function confidence(top, second) {
50125
- if (top < MIN_PRIMARY_SCORE) return "ambiguous";
50126
- if (second === 0) return "high";
50127
- if (top >= second * 2) return "high";
50128
- if (top - second < AMBIGUITY_THRESHOLD) return "ambiguous";
50129
- return "medium";
50130
- }
50131
- function suggestChartTypes(prompt) {
50132
- const scored = [];
50133
- for (const type of chartTypes) {
50134
- const { score, matched } = scoreChartType(prompt, type);
50135
- if (score > 0) scored.push({ type, score, matched });
50136
- }
50137
- scored.sort((a, b) => b.score - a.score);
50138
- const fallback = chartTypes.filter((c) => c.fallback);
50139
- const topScore = scored[0]?.score ?? 0;
50140
- const secondScore = scored[1]?.score ?? 0;
50141
- const fellBack = topScore < MIN_PRIMARY_SCORE;
50142
- return {
50143
- ranked: scored,
50144
- fallback,
50145
- confidence: confidence(topScore, secondScore),
50146
- fellBack
50147
- };
50148
- }
50149
-
50150
- // src/index.ts
50151
- init_dgmo_router();
50152
- init_chart();
50153
- init_echarts();
50154
- init_d3();
50155
- init_time_ticks();
50156
- init_parser();
50157
- init_participant_inference();
50158
- init_flowchart_parser();
50159
- init_state_parser();
50160
- init_state_renderer();
50161
-
50162
- // src/graph/state-collapse.ts
50163
- function collapseStateGroups(parsed, collapsedGroups) {
50164
- const originalGroups = parsed.groups ?? [];
50165
- if (collapsedGroups.size === 0 || originalGroups.length === 0) {
50166
- return { parsed, collapsedChildCounts: /* @__PURE__ */ new Map(), originalGroups };
50167
- }
50168
- const groupById = /* @__PURE__ */ new Map();
50169
- for (const group of originalGroups) {
50170
- groupById.set(group.id, group);
50171
- }
50172
- const nodeToGroup = /* @__PURE__ */ new Map();
50173
- const collapsedChildCounts = /* @__PURE__ */ new Map();
50174
- for (const groupId3 of collapsedGroups) {
50175
- const group = groupById.get(groupId3);
50176
- if (!group) continue;
50177
- for (const nodeId3 of group.nodeIds) {
50178
- nodeToGroup.set(nodeId3, groupId3);
50179
- }
50180
- collapsedChildCounts.set(groupId3, group.nodeIds.length);
50181
- }
50182
- const nodes = parsed.nodes.filter((n) => !nodeToGroup.has(n.id));
50183
- const edgeKeys = /* @__PURE__ */ new Set();
50184
- const edges = [];
50185
- for (const edge of parsed.edges) {
50186
- const src = nodeToGroup.get(edge.source) ?? edge.source;
50187
- const tgt = nodeToGroup.get(edge.target) ?? edge.target;
50188
- if (src === tgt && src !== edge.source) continue;
50189
- const key = `${src}|${tgt}|${edge.label ?? ""}`;
50190
- if (edgeKeys.has(key)) continue;
50191
- edgeKeys.add(key);
50192
- edges.push({ ...edge, source: src, target: tgt });
50193
- }
50194
- const groups = originalGroups.filter((g) => !collapsedGroups.has(g.id));
50195
- return {
50196
- parsed: { ...parsed, nodes, edges, groups },
50197
- collapsedChildCounts,
50198
- originalGroups
50199
- };
50200
- }
50201
-
50202
- // src/index.ts
50203
- init_parser2();
50204
- init_layout3();
50205
- init_renderer4();
50206
- init_parser3();
50207
- init_layout4();
50208
- init_renderer5();
50209
- init_inline_markdown();
50210
- init_name_normalize();
50211
- init_parser4();
50212
- init_layout();
50213
- init_renderer();
50214
- init_parser5();
50215
- init_mutations();
50216
- init_renderer3();
50217
- init_parser6();
50218
- init_layout8();
50219
- init_renderer9();
50220
- init_parser11();
50221
- init_layout5();
50222
- init_renderer6();
50223
-
50224
- // src/boxes-and-lines/collapse.ts
50225
- function collapseBoxesAndLines(parsed, collapsedGroups) {
50226
- const originalGroups = parsed.groups;
50227
- if (collapsedGroups.size === 0) {
50228
- return { parsed, collapsedChildCounts: /* @__PURE__ */ new Map(), originalGroups };
50229
- }
50230
- const groupByLabel = /* @__PURE__ */ new Map();
50231
- for (const group of parsed.groups) {
50232
- groupByLabel.set(group.label, group);
50233
- }
50234
- const nodeToGroup = /* @__PURE__ */ new Map();
50235
- const collapsedChildCounts = /* @__PURE__ */ new Map();
50236
- function collectDescendants(groupLabel) {
50237
- const group = groupByLabel.get(groupLabel);
50238
- if (!group) return [];
50239
- const descendants = [];
50240
- for (const child of group.children) {
50241
- descendants.push(child);
50242
- if (groupByLabel.has(child)) {
50243
- descendants.push(...collectDescendants(child));
50244
- }
50245
- }
50246
- return descendants;
50247
- }
50248
- for (const groupLabel of collapsedGroups) {
50249
- const group = groupByLabel.get(groupLabel);
50250
- if (!group) continue;
50251
- const groupId3 = `__group_${groupLabel}`;
50252
- const allDescendants = collectDescendants(groupLabel);
50253
- for (const child of allDescendants) {
50254
- nodeToGroup.set(child, groupId3);
50255
- }
50256
- collapsedChildCounts.set(groupLabel, group.children.length);
50257
- }
50258
- const nodes = parsed.nodes.filter((n) => !nodeToGroup.has(n.label));
50259
- const edgeKeys = /* @__PURE__ */ new Set();
50260
- const edges = [];
50261
- for (const edge of parsed.edges) {
50262
- const src = nodeToGroup.get(edge.source) ?? edge.source;
50263
- const tgt = nodeToGroup.get(edge.target) ?? edge.target;
50264
- if (src === tgt) continue;
50265
- const key = `${src}|${tgt}|${edge.label ?? ""}`;
50266
- if (edgeKeys.has(key)) continue;
50267
- edgeKeys.add(key);
50268
- edges.push({ ...edge, source: src, target: tgt });
50269
- }
50270
- const groups = parsed.groups.filter(
50271
- (g) => !collapsedGroups.has(g.label) && !nodeToGroup.has(g.label)
50272
- );
50273
- return {
50274
- parsed: { ...parsed, nodes, edges, groups },
50275
- collapsedChildCounts,
50276
- originalGroups
50277
- };
50278
- }
50279
-
50280
- // src/index.ts
50281
- init_parser7();
50282
- init_layout2();
50283
- init_renderer2();
50284
- init_collapse2();
50285
- init_parser8();
50286
- init_types();
50287
- init_compute();
50288
-
50289
- // src/infra/validation.ts
50290
- function detectCycles(parsed) {
50291
- const diagnostics = [];
50292
- const adj = /* @__PURE__ */ new Map();
50293
- const edgeLines = /* @__PURE__ */ new Map();
50294
- for (const edge of parsed.edges) {
50295
- const list = adj.get(edge.sourceId) ?? [];
50296
- list.push(edge.targetId);
50297
- adj.set(edge.sourceId, list);
50298
- edgeLines.set(`${edge.sourceId}->${edge.targetId}`, edge.lineNumber);
50299
- }
50300
- const color = /* @__PURE__ */ new Map();
50301
- const parent = /* @__PURE__ */ new Map();
50302
- function dfs(nodeId3) {
50303
- color.set(nodeId3, 1);
50304
- const neighbors = adj.get(nodeId3) ?? [];
50305
- for (const next of neighbors) {
50306
- const c = color.get(next) ?? 0;
50307
- if (c === 1) {
50308
- const lineKey = `${nodeId3}->${next}`;
50309
- diagnostics.push({
50310
- type: "CYCLE",
50311
- line: edgeLines.get(lineKey) ?? 0,
50312
- message: `Cycle detected: ${nodeId3} -> ${next} creates a circular reference.`
50313
- });
50314
- return true;
50315
- }
50316
- if (c === 0) {
50317
- parent.set(next, nodeId3);
50318
- if (dfs(next)) return true;
50319
- }
50320
- }
50321
- color.set(nodeId3, 2);
50322
- return false;
50323
- }
50324
- for (const node of parsed.nodes) {
50325
- if ((color.get(node.id) ?? 0) === 0) {
50326
- dfs(node.id);
50327
- }
50328
- }
50329
- return diagnostics;
50330
- }
50331
- function validateSplits(parsed) {
50332
- const diagnostics = [];
50333
- const outbound = /* @__PURE__ */ new Map();
50334
- for (const edge of parsed.edges) {
50335
- const list = outbound.get(edge.sourceId) ?? [];
50336
- list.push(edge);
50337
- outbound.set(edge.sourceId, list);
50338
- }
50339
- for (const [sourceId, edges] of outbound) {
50340
- if (edges.length <= 1) continue;
50341
- const declared = edges.filter((e) => e.split !== null);
50342
- if (declared.length === edges.length) {
50343
- const sum = declared.reduce((s, e) => s + (e.split ?? 0), 0);
50344
- if (Math.abs(sum - 100) > 0.01) {
50345
- diagnostics.push({
50346
- type: "SPLIT_SUM",
50347
- line: declared[0].lineNumber,
50348
- message: `Splits from '${sourceId}' sum to ${sum}%, expected 100%.`
50349
- });
50350
- }
50351
- } else if (declared.length > 0) {
50352
- const declaredSum = declared.reduce((s, e) => s + (e.split ?? 0), 0);
50353
- if (declaredSum > 100) {
50354
- diagnostics.push({
50355
- type: "SPLIT_SUM",
50356
- line: declared[0].lineNumber,
50357
- message: `Declared splits from '${sourceId}' sum to ${declaredSum}%, exceeding 100%.`
50358
- });
50359
- }
50360
- }
50361
- }
50362
- return diagnostics;
50363
- }
50364
- function detectOrphans(parsed) {
50365
- const diagnostics = [];
50366
- const edgeNode = parsed.nodes.find((n) => n.isEdge);
50367
- if (!edgeNode) return diagnostics;
50368
- const reachable = /* @__PURE__ */ new Set();
50369
- const adj = /* @__PURE__ */ new Map();
50370
- for (const edge of parsed.edges) {
50371
- const list = adj.get(edge.sourceId) ?? [];
50372
- list.push(edge.targetId);
50373
- adj.set(edge.sourceId, list);
50374
- }
50375
- const queue = [edgeNode.id];
50376
- while (queue.length > 0) {
50377
- const id = queue.shift();
50378
- if (reachable.has(id)) continue;
50379
- reachable.add(id);
50380
- for (const next of adj.get(id) ?? []) {
50381
- queue.push(next);
50382
- }
50383
- }
50384
- for (const group of parsed.groups) {
50385
- if (reachable.has(group.id)) {
50386
- for (const node of parsed.nodes) {
50387
- if (node.groupId === group.id) reachable.add(node.id);
50388
- }
50389
- }
50390
- }
50391
- for (const node of parsed.nodes) {
50392
- if (!node.isEdge && !reachable.has(node.id)) {
50393
- diagnostics.push({
50394
- type: "ORPHAN",
50395
- line: node.lineNumber,
50396
- message: `Component '${node.label}' is not reachable from the edge entry point.`
50397
- });
50398
- }
50399
- }
50400
- return diagnostics;
50401
- }
50402
- function validateInfra(parsed) {
50403
- return [
50404
- ...detectCycles(parsed),
50405
- ...validateSplits(parsed),
50406
- ...detectOrphans(parsed)
50407
- ];
50408
- }
50409
- function validateComputed(computed) {
50410
- const diagnostics = [];
50411
- if (computed.systemUptime > 0 && computed.systemUptime < 0.99) {
50412
- const pct = (computed.systemUptime * 100).toFixed(2);
50413
- diagnostics.push({
50414
- type: "UPTIME",
50415
- line: 1,
50416
- message: `System uptime is ${pct}%, below 99% SLA threshold.`
50417
- });
50418
- }
50419
- return diagnostics;
50420
- }
50421
-
50422
- // src/index.ts
50423
- init_roles();
50424
- init_layout10();
50425
- init_renderer10();
50426
- init_parser9();
50427
- init_calculator();
50428
- init_renderer12();
50429
- init_resolver();
50430
- init_parser10();
50431
- init_analyzer();
50432
- init_layout11();
50433
-
50434
- // src/pert/share-normalize.ts
50435
- init_internal();
50436
- var START_DATE_NOW_RE = /^(\s*start-date\s+)now(\s*)$/i;
50437
- function splitTrailingComment(line12) {
50438
- const m = line12.match(/^(.*?)(\s+#.*)$/);
50439
- if (!m) return { code: line12, comment: "" };
50440
- return { code: m[1], comment: m[2] };
50441
- }
50442
- function normalizePertSourceForShare(dsl) {
50443
- const today = formatLocalISODate(/* @__PURE__ */ new Date());
50444
- const lines = dsl.split("\n");
50445
- const out = [];
50446
- for (const line12 of lines) {
50447
- const { code, comment } = splitTrailingComment(line12);
50448
- const m = code.match(START_DATE_NOW_RE);
50449
- if (m) {
50450
- out.push(`${m[1]}${today}${m[2]}${comment}`);
50451
- } else {
50452
- out.push(line12);
50453
- }
50454
- }
50455
- return out.join("\n");
50456
- }
50457
-
50458
- // src/index.ts
50459
- init_renderer11();
50460
- init_collapse();
50461
- init_parser12();
50462
- init_layout6();
50463
- init_renderer7();
50464
- init_collapse3();
50465
- init_parser13();
50466
- init_layout7();
50467
- init_renderer8();
50468
- init_parser14();
50469
- init_layout12();
50470
- init_renderer13();
50471
- init_interactive();
50472
- init_parser15();
50473
- init_layout14();
50474
- init_renderer15();
50475
- init_parser16();
50476
- init_layout13();
50477
- init_renderer14();
50478
- init_parser17();
50479
- init_renderer16();
50480
- init_parser18();
50481
- init_renderer17();
50482
-
50483
- // src/raci/index.ts
50484
- init_parser19();
50485
- init_renderer18();
50486
-
50487
- // src/raci/mutations.ts
50488
- init_parsing();
50489
- init_parser19();
50490
- function cellReplace(content, parsed, taskId, roleId, marker) {
50491
- const task = findTask(parsed, taskId);
50492
- if (!task) return null;
50493
- const lines = content.split("\n");
50494
- const existing = task.roleAssignments.find((a) => a.id === roleId);
50495
- if (existing) {
50496
- if (marker !== null && existing.markers.length === 1 && existing.markers[0] === marker) {
50497
- return null;
50498
- }
50499
- if (marker === null && existing.markers.length === 0) {
50500
- return null;
50501
- }
50502
- if (marker === null) {
50503
- lines.splice(existing.lineNumber - 1, 1);
50504
- return lines.join("\n");
50505
- }
50506
- lines[existing.lineNumber - 1] = rewriteAssignmentLine(
50507
- lines[existing.lineNumber - 1],
50508
- existing.displayName,
50509
- [marker]
50510
- );
50511
- return lines.join("\n");
50512
- }
50513
- if (marker === null) return null;
50514
- const roleDisplay = lookupRoleDisplay(parsed, roleId);
50515
- if (!roleDisplay) return null;
50516
- const indent = inferAssignmentIndent(task, lines);
50517
- const insertAt = insertionLineFor(task, roleId, parsed);
50518
- const newLine = `${" ".repeat(indent)}${roleDisplay}: ${marker}`;
50519
- lines.splice(insertAt, 0, newLine);
50520
- return lines.join("\n");
50521
- }
50522
- function cellAppendMarker(content, parsed, taskId, roleId, marker) {
50523
- const task = findTask(parsed, taskId);
50524
- if (!task) return null;
50525
- const existing = task.roleAssignments.find((a) => a.id === roleId);
50526
- if (!existing) {
50527
- return cellReplace(content, parsed, taskId, roleId, marker);
50528
- }
50529
- if (existing.markers.includes(marker)) return null;
50530
- const lines = content.split("\n");
50531
- lines[existing.lineNumber - 1] = rewriteAssignmentLine(
50532
- lines[existing.lineNumber - 1],
50533
- existing.displayName,
50534
- [...existing.markers, marker]
50535
- );
50536
- return lines.join("\n");
50537
- }
50538
- function cellRemove(content, parsed, taskId, roleId, marker) {
50539
- const task = findTask(parsed, taskId);
50540
- if (!task) return null;
50541
- const existing = task.roleAssignments.find((a) => a.id === roleId);
50542
- if (!existing) return null;
50543
- const lines = content.split("\n");
50544
- let nextMarkers;
50545
- if (marker === void 0) {
50546
- nextMarkers = [];
50547
- } else {
50548
- if (!existing.markers.includes(marker)) return null;
50549
- nextMarkers = existing.markers.filter((m) => m !== marker);
50550
- }
50551
- if (nextMarkers.length === 0) {
50552
- lines.splice(existing.lineNumber - 1, 1);
50553
- return lines.join("\n");
50554
- }
50555
- lines[existing.lineNumber - 1] = rewriteAssignmentLine(
50556
- lines[existing.lineNumber - 1],
50557
- existing.displayName,
50558
- nextMarkers
50559
- );
50560
- return lines.join("\n");
50561
- }
50562
- function cellCycle(content, parsed, taskId, roleId, alphabet) {
50563
- if (alphabet.length === 0) return null;
50564
- const task = findTask(parsed, taskId);
50565
- if (!task) return null;
50566
- const existing = task.roleAssignments.find((a) => a.id === roleId);
50567
- const current = existing?.markers ?? [];
50568
- let next;
50569
- if (current.length === 0) {
50570
- next = alphabet[0];
50571
- } else {
50572
- const dominant = current[0];
50573
- const idx = alphabet.indexOf(dominant);
50574
- if (idx < 0) {
50575
- next = alphabet[0];
50576
- } else if (idx === alphabet.length - 1) {
50577
- next = null;
50578
- } else {
50579
- next = alphabet[idx + 1];
50580
- }
50581
- }
50582
- return cellReplace(content, parsed, taskId, roleId, next);
50583
- }
50584
- function findTask(parsed, taskId) {
50585
- for (const t of allTasks(parsed)) {
50586
- if (t.id === taskId) return t;
50587
- }
50588
- return null;
50589
- }
50590
- function lookupRoleDisplay(parsed, roleId) {
50591
- const idx = parsed.roles.indexOf(roleId);
50592
- if (idx < 0) return null;
50593
- return parsed.roleDisplayNames[idx] ?? null;
50594
- }
50595
- function rewriteAssignmentLine(originalLine, displayName2, markers) {
50596
- const indent = measureIndent(originalLine);
50597
- return `${" ".repeat(indent)}${displayName2}: ${markers.join(" ")}`;
50598
- }
50599
- function inferAssignmentIndent(task, lines) {
50600
- if (task.roleAssignments.length > 0) {
50601
- return measureIndent(lines[task.roleAssignments[0].lineNumber - 1]);
50602
- }
50603
- const taskIndent = measureIndent(lines[task.lineNumber - 1]);
50604
- return taskIndent + 2;
50605
- }
50606
- function insertionLineFor(task, roleId, parsed) {
50607
- if (task.roleAssignments.length === 0) {
50608
- return task.endLineNumber;
50609
- }
50610
- const targetIdx = parsed.roles.indexOf(roleId);
50611
- const lastAssignmentLine = Math.max(
50612
- ...task.roleAssignments.map((a) => a.endLineNumber)
50613
- );
50614
- if (targetIdx < 0) {
50615
- return lastAssignmentLine;
50616
- }
50617
- for (const a of task.roleAssignments) {
50618
- const aIdx = parsed.roles.indexOf(a.id);
50619
- if (aIdx > targetIdx) {
50620
- return a.lineNumber - 1;
50621
- }
50622
- }
50623
- return lastAssignmentLine;
50624
- }
50625
-
50626
- // src/raci/index.ts
50627
- init_variants();
50628
-
50629
- // src/org/resolver.ts
50630
- init_diagnostics();
50631
- init_tag_groups();
50632
- var MAX_DEPTH = 10;
50633
- var IMPORT_RE = /^(\s+)import:?\s+(.+\.dgmo)\s*$/i;
50634
- var TAGS_RE = /^tags:?\s+(.+\.dgmo)\s*$/i;
50635
- var HEADER_RE = /^(org|kanban|title\s*:)/i;
50636
- var KNOWN_HEADER_OPTIONS = /* @__PURE__ */ new Set([
50637
- "direction-tb",
50638
- "sub-node-label",
50639
- "hide",
50640
- "show-sub-node-count",
50641
- "color-off",
50642
- "solid-fill",
50643
- "active-tag"
50644
- ]);
50645
- function dirname(filePath) {
50646
- const last = filePath.lastIndexOf("/");
50647
- return last > 0 ? filePath.substring(0, last) : "/";
50648
- }
50649
- function resolvePath(base, relative) {
50650
- const parts = dirname(base).split("/");
50651
- for (const seg of relative.split("/")) {
50652
- if (seg === "..") {
50653
- if (parts.length > 1) parts.pop();
50654
- } else if (seg !== "." && seg !== "") {
50655
- parts.push(seg);
50656
- }
50657
- }
50658
- return parts.join("/") || "/";
50659
- }
50660
- function extractTagGroups(lines) {
50661
- const blocks = [];
50662
- let current = null;
50663
- for (const line12 of lines) {
50664
- const trimmed = line12.trim();
50665
- const headingMatch = matchTagBlockHeading(trimmed);
50666
- if (headingMatch) {
50667
- const name = headingMatch.name.toLowerCase();
50668
- current = { name, lines: [line12] };
50669
- blocks.push(current);
50670
- } else if (current) {
50671
- if (trimmed === "" || trimmed.startsWith("//")) {
50672
- current = null;
50673
- } else if (line12.match(/^\s+/)) {
50674
- current.lines.push(line12);
50675
- } else {
50676
- current = null;
50677
- }
50678
- }
50679
- }
50680
- return blocks;
50681
- }
50682
- function parseFileHeader(lines) {
50683
- const tagGroups = extractTagGroups(lines);
50684
- const tagGroupLineSet = /* @__PURE__ */ new Set();
50685
- for (const group of tagGroups) {
50686
- for (let i = 0; i < lines.length; i++) {
50687
- if (lines[i] === group.lines[0]) {
50688
- for (let j = 0; j < group.lines.length; j++) {
50689
- tagGroupLineSet.add(i + j);
50690
- }
50691
- break;
50692
- }
50693
- }
50694
- }
50695
- let tagsDirective = null;
50696
- const contentLines = [];
50697
- const contentLineIndices = [];
50698
- let headerDone = false;
50699
- for (let i = 0; i < lines.length; i++) {
50700
- if (tagGroupLineSet.has(i)) continue;
50701
- const trimmed = lines[i].trim();
50702
- if (!headerDone && (trimmed === "" || trimmed.startsWith("//"))) continue;
50703
- if (!headerDone) {
50704
- if (HEADER_RE.test(trimmed)) continue;
50705
- const tagsMatch = trimmed.match(TAGS_RE);
50706
- if (tagsMatch) {
50707
- tagsDirective = tagsMatch[1].trim();
50708
- continue;
50709
- }
50710
- if (!lines[i].match(/^\s/) && !isTagBlockHeading(trimmed) && !trimmed.includes("|")) {
50711
- const firstToken = trimmed.split(/\s/)[0].toLowerCase();
50712
- if (KNOWN_HEADER_OPTIONS.has(firstToken)) {
50713
- continue;
50714
- }
50715
- }
50716
- headerDone = true;
50717
- }
50718
- contentLines.push(lines[i]);
50719
- contentLineIndices.push(i);
50720
- }
50721
- return { contentLines, contentLineIndices, tagGroups, tagsDirective };
50722
- }
50723
- async function resolveOrgImports(content, filePath, readFileFn) {
50724
- const diagnostics = [];
50725
- const result = await resolveFile(
50726
- content,
50727
- filePath,
50728
- readFileFn,
50729
- diagnostics,
50730
- /* @__PURE__ */ new Set([filePath]),
50731
- 0
50732
- );
50733
- return {
50734
- content: result.content,
50735
- diagnostics,
50736
- lineMap: result.lineMap,
50737
- importSourceMap: result.importSourceMap
50738
- };
50739
- }
50740
- async function resolveFile(content, filePath, readFileFn, diagnostics, ancestorChain, depth) {
50741
- const lines = content.split("\n");
50742
- const headerLines = [];
50743
- let tagsDirective = null;
50744
- const inlineTagGroups = extractTagGroups(lines);
50745
- const bodyStartIndex = findBodyStart(lines);
50746
- let tagsLineNumber = 0;
50747
- for (let i = 0; i < bodyStartIndex; i++) {
50748
- const trimmed = lines[i].trim();
50749
- if (trimmed === "" || trimmed.startsWith("//")) {
50750
- headerLines.push({ text: lines[i], originalLine: i + 1 });
50751
- continue;
50752
- }
50753
- if (isTagBlockHeading(trimmed)) continue;
50754
- if (/^\s/.test(lines[i])) continue;
50755
- const tagsMatch = trimmed.match(TAGS_RE);
50756
- if (tagsMatch) {
50757
- tagsDirective = tagsMatch[1].trim();
50758
- tagsLineNumber = i + 1;
50759
- continue;
50760
- }
50761
- headerLines.push({ text: lines[i], originalLine: i + 1 });
50762
- }
50763
- let tagsFileGroups = [];
50764
- if (tagsDirective) {
50765
- const tagsPath = resolvePath(filePath, tagsDirective);
50766
- try {
50767
- const tagsContent = await readFileFn(tagsPath);
50768
- const tagsLines = tagsContent.split("\n");
50769
- tagsFileGroups = extractTagGroups(tagsLines);
50770
- } catch {
50771
- diagnostics.push(
50772
- makeDgmoError(tagsLineNumber, `Tags file not found: ${tagsDirective}`)
50773
- );
50774
- }
50775
- }
50776
- const bodyLines = lines.slice(bodyStartIndex);
50777
- const resolvedBodyLines = [];
50778
- const importedTagGroups = [];
50779
- for (let i = 0; i < bodyLines.length; i++) {
50780
- const line12 = bodyLines[i];
50781
- const lineNumber = bodyStartIndex + i + 1;
50782
- const importMatch = line12.match(IMPORT_RE);
50783
- if (!importMatch) {
50784
- const trimmed = line12.trim();
50785
- if (isTagBlockHeading(trimmed) || inlineTagGroups.length > 0 && isTagGroupEntry(line12, bodyLines, i)) {
50786
- continue;
50787
- }
50788
- resolvedBodyLines.push({
50789
- text: line12,
50790
- originalLine: lineNumber,
50791
- importSource: null
50792
- });
50793
- continue;
50794
- }
50795
- const indent = importMatch[1];
50796
- const importRelPath = importMatch[2].trim();
50797
- const importAbsPath = resolvePath(filePath, importRelPath);
50798
- if (depth >= MAX_DEPTH) {
50799
- diagnostics.push(
50800
- makeDgmoError(
50801
- lineNumber,
50802
- `Import depth limit exceeded (${MAX_DEPTH}): ${importRelPath}`
50803
- )
50804
- );
50805
- continue;
50806
- }
50807
- if (ancestorChain.has(importAbsPath)) {
50808
- const chain = [...ancestorChain, importAbsPath].map((p) => p.split("/").pop()).join(" -> ");
50809
- diagnostics.push(
50810
- makeDgmoError(lineNumber, `Circular import detected: ${chain}`)
50811
- );
50812
- continue;
50813
- }
50814
- let importedContent;
50815
- try {
50816
- importedContent = await readFileFn(importAbsPath);
50817
- } catch {
50818
- diagnostics.push(
50819
- makeDgmoError(lineNumber, `Import file not found: ${importRelPath}`)
50820
- );
50821
- continue;
50822
- }
50823
- const nestedChain = new Set(ancestorChain);
50824
- nestedChain.add(importAbsPath);
50825
- const resolved = await resolveFile(
50826
- importedContent,
50827
- importAbsPath,
50828
- readFileFn,
50829
- diagnostics,
50830
- nestedChain,
50831
- depth + 1
50832
- );
50833
- const resolvedLines = resolved.content.split("\n");
50834
- const parsed = parseFileHeader(resolvedLines);
50835
- for (const group of parsed.tagGroups) {
50836
- importedTagGroups.push(group);
50837
- }
50838
- const importedContentLines = [];
50839
- for (let j = 0; j < parsed.contentLines.length; j++) {
50840
- if (parsed.contentLines[j].trim() !== "") {
50841
- importedContentLines.push({
50842
- text: parsed.contentLines[j],
50843
- index: parsed.contentLineIndices[j]
50844
- });
50845
- }
50846
- }
50847
- let lastNonEmpty = importedContentLines.length - 1;
50848
- while (lastNonEmpty >= 0 && importedContentLines[lastNonEmpty].text.trim() === "") {
50849
- lastNonEmpty--;
50850
- }
50851
- const trimmedImported = importedContentLines.slice(0, lastNonEmpty + 1);
50852
- for (const entry of trimmedImported) {
50853
- const resolvedLineNum = entry.index + 1;
50854
- let importSource = null;
50855
- if (resolved.importSourceMap[resolvedLineNum]) {
50856
- importSource = resolved.importSourceMap[resolvedLineNum];
50857
- } else {
50858
- const origLine = resolved.lineMap[resolvedLineNum];
50859
- if (origLine != null) {
50860
- importSource = { filePath: importAbsPath, sourceLine: origLine };
50861
- }
50862
- }
50863
- if (entry.text.trim() === "") {
50864
- resolvedBodyLines.push({
50865
- text: "",
50866
- originalLine: lineNumber,
50867
- importSource
50868
- });
50869
- } else {
50870
- resolvedBodyLines.push({
50871
- text: indent + entry.text,
50872
- originalLine: lineNumber,
50873
- importSource
50874
- });
50875
- }
50876
- }
50877
- }
50878
- const mergedGroups = mergeTagGroups(
50879
- inlineTagGroups,
50880
- tagsFileGroups,
50881
- importedTagGroups
50882
- );
50883
- const outputLines = [];
50884
- const lineMap = [null];
50885
- const importSourceMap = [null];
50886
- for (const entry of headerLines) {
50887
- outputLines.push(entry.text);
50888
- lineMap.push(entry.originalLine);
50889
- importSourceMap.push(null);
50890
- }
50891
- if (mergedGroups.length > 0) {
50892
- if (outputLines.length > 0 && outputLines[outputLines.length - 1].trim() !== "") {
50893
- outputLines.push("");
50894
- lineMap.push(null);
50895
- importSourceMap.push(null);
50896
- }
50897
- for (const group of mergedGroups) {
50898
- const inlineMatch = inlineTagGroups.find((g) => g.name === group.name);
50899
- for (const line12 of group.lines) {
50900
- outputLines.push(line12);
50901
- if (inlineMatch) {
50902
- const srcIdx = lines.indexOf(line12);
50903
- lineMap.push(srcIdx >= 0 ? srcIdx + 1 : null);
50904
- } else {
50905
- lineMap.push(null);
50906
- }
50907
- importSourceMap.push(null);
50908
- }
50909
- outputLines.push("");
50910
- lineMap.push(null);
50911
- importSourceMap.push(null);
50912
- }
50913
- }
50914
- if (resolvedBodyLines.length > 0 && outputLines.length > 0 && outputLines[outputLines.length - 1].trim() !== "") {
50915
- outputLines.push("");
50916
- lineMap.push(null);
50917
- importSourceMap.push(null);
50918
- }
50919
- for (const entry of resolvedBodyLines) {
50920
- outputLines.push(entry.text);
50921
- lineMap.push(entry.originalLine);
50922
- importSourceMap.push(entry.importSource);
50923
- }
50924
- return { content: outputLines.join("\n"), lineMap, importSourceMap };
50925
- }
50926
- function findBodyStart(lines) {
50927
- let inTagGroup = false;
50928
- for (let i = 0; i < lines.length; i++) {
50929
- const trimmed = lines[i].trim();
50930
- if (trimmed === "" || trimmed.startsWith("//")) {
50931
- if (inTagGroup) inTagGroup = false;
50932
- continue;
50933
- }
50934
- if (isTagBlockHeading(trimmed)) {
50935
- inTagGroup = true;
50936
- continue;
50937
- }
50938
- if (inTagGroup && lines[i].match(/^\s+/)) {
50939
- continue;
50940
- }
50941
- if (inTagGroup) {
50942
- inTagGroup = false;
50943
- }
50944
- if (HEADER_RE.test(trimmed)) continue;
50945
- if (TAGS_RE.test(trimmed)) continue;
50946
- if (!lines[i].match(/^\s/) && !trimmed.includes("|") && !isTagBlockHeading(trimmed)) {
50947
- const firstToken = trimmed.split(/\s/)[0].toLowerCase();
50948
- if (KNOWN_HEADER_OPTIONS.has(firstToken)) {
50949
- continue;
50950
- }
50951
- }
50952
- return i;
50953
- }
50954
- return lines.length;
50955
- }
50956
- function isTagGroupEntry(line12, allLines, index) {
50957
- if (!line12.match(/^\s+/)) return false;
50958
- for (let i = index - 1; i >= 0; i--) {
50959
- const prev = allLines[i].trim();
50960
- if (prev === "" || prev.startsWith("//")) continue;
50961
- if (isTagBlockHeading(prev)) return true;
50962
- if (allLines[i].match(/^\s+/)) continue;
50963
- return false;
50964
- }
50965
- return false;
50966
- }
50967
- function mergeTagGroups(inline, tagsFile, imported) {
50968
- const seen = /* @__PURE__ */ new Map();
50969
- for (const group of inline) {
50970
- seen.set(group.name, group);
50971
- }
50972
- for (const group of tagsFile) {
50973
- if (!seen.has(group.name)) {
50974
- seen.set(group.name, group);
50975
- }
50976
- }
50977
- for (const group of imported) {
50978
- if (!seen.has(group.name)) {
50979
- seen.set(group.name, group);
50980
- }
50981
- }
50982
- return Array.from(seen.values());
50983
- }
50984
-
50985
- // src/index.ts
50986
- init_layout9();
50987
- init_flowchart_renderer();
50988
- init_echarts();
50989
- init_legend_svg();
50990
- init_legend_constants();
50991
- init_legend_d3();
50992
- init_legend_layout();
50993
- init_d3();
50994
- init_renderer19();
50995
- init_collapse4();
50996
- init_colors();
50997
- init_palettes();
50998
- init_color_utils();
50999
-
51000
49706
  // src/sharing.ts
51001
49707
  var import_lz_string = __toESM(require_lz_string(), 1);
51002
49708
  var DEFAULT_BASE_URL = "https://online.diagrammo.app";
@@ -51088,1452 +49794,86 @@ function decodeDiagramUrl(hash) {
51088
49794
  }
51089
49795
  }
51090
49796
 
51091
- // src/completion.ts
51092
- init_parser3();
51093
- init_flowchart_parser();
51094
- init_parser8();
51095
- init_parser2();
51096
- init_parser10();
51097
- init_parsing();
49797
+ // src/index.ts
51098
49798
  init_dgmo_router();
51099
- var extractorRegistry = /* @__PURE__ */ new Map();
51100
- function registerExtractor(kind, fn) {
51101
- extractorRegistry.set(kind, fn);
51102
- }
51103
- function extractDiagramSymbols(docText) {
51104
- let chartType = null;
51105
- for (const line12 of docText.split("\n")) {
51106
- const trimmed = line12.trim();
51107
- if (!trimmed || trimmed.startsWith("//")) continue;
51108
- const result2 = parseFirstLine(trimmed);
51109
- if (result2) {
51110
- chartType = result2.chartType;
51111
- }
51112
- break;
51113
- }
51114
- if (!chartType) return null;
51115
- const fn = extractorRegistry.get(chartType);
51116
- if (!fn) return null;
51117
- const result = fn(docText);
51118
- const aliases = extractAliasDeclarations(docText);
51119
- return Object.keys(aliases).length > 0 ? { ...result, aliases } : result;
51120
- }
51121
- var GLOBAL_DIRECTIVES = {
51122
- palette: {
51123
- description: "Color palette name",
51124
- values: [
51125
- "nord",
51126
- "solarized",
51127
- "catppuccin",
51128
- "rose-pine",
51129
- "gruvbox",
51130
- "tokyo-night",
51131
- "one-dark",
51132
- "bold",
51133
- "dracula",
51134
- "monokai"
51135
- ]
51136
- },
51137
- theme: {
51138
- description: "Color theme",
51139
- values: ["light", "dark", "transparent"]
51140
- },
51141
- "no-title": {
51142
- description: "Hide the diagram title"
51143
- }
49799
+ init_palettes();
49800
+ init_diagnostics();
49801
+ init_palettes();
49802
+
49803
+ // src/themes.ts
49804
+ var themes = {
49805
+ light: "light",
49806
+ dark: "dark",
49807
+ transparent: "transparent"
51144
49808
  };
51145
- function withGlobals(directives = {}) {
51146
- return { directives: { ...GLOBAL_DIRECTIVES, ...directives } };
51147
- }
51148
- var COMPLETION_REGISTRY = /* @__PURE__ */ new Map([
51149
- // ── Data charts ──────────────────────────────────────────
51150
- [
51151
- "bar",
51152
- withGlobals({
51153
- series: { description: "Series name(s)" },
51154
- "x-label": { description: "X-axis label" },
51155
- "y-label": { description: "Y-axis label" },
51156
- "orientation-horizontal": { description: "Switch to horizontal bars" },
51157
- "no-value": { description: "Hide value labels atop each bar" },
51158
- color: { description: "Bar color override" }
51159
- })
51160
- ],
51161
- [
51162
- "line",
51163
- withGlobals({
51164
- series: { description: "Series name(s)" },
51165
- "x-label": { description: "X-axis label" },
51166
- "y-label": { description: "Y-axis label" },
51167
- "no-value": { description: "Hide value labels at each point" }
51168
- })
51169
- ],
51170
- [
51171
- "pie",
51172
- withGlobals({
51173
- "no-name": { description: "Hide name from segment labels" },
51174
- "no-value": { description: "Hide value from segment labels" },
51175
- "no-percent": { description: "Hide percent from segment labels" }
51176
- })
51177
- ],
51178
- [
51179
- "doughnut",
51180
- withGlobals({
51181
- "no-name": { description: "Hide name from segment labels" },
51182
- "no-value": { description: "Hide value from segment labels" },
51183
- "no-percent": { description: "Hide percent from segment labels" }
51184
- })
51185
- ],
51186
- [
51187
- "area",
51188
- withGlobals({
51189
- series: { description: "Series name(s)" },
51190
- "x-label": { description: "X-axis label" },
51191
- "y-label": { description: "Y-axis label" },
51192
- "no-value": { description: "Hide value labels at each point" }
51193
- })
51194
- ],
51195
- [
51196
- "multi-line",
51197
- withGlobals({
51198
- series: { description: "Series name(s)" },
51199
- "x-label": { description: "X-axis label" },
51200
- "y-label": { description: "Y-axis label" },
51201
- "no-value": { description: "Hide value labels at each point" }
51202
- })
51203
- ],
51204
- [
51205
- "polar-area",
51206
- withGlobals({
51207
- "no-name": { description: "Hide name from segment labels" },
51208
- "no-value": { description: "Hide value from segment labels" },
51209
- "no-percent": { description: "Hide percent from segment labels" }
51210
- })
51211
- ],
51212
- [
51213
- "radar",
51214
- withGlobals({
51215
- "no-value": { description: "Hide value labels at each vertex" }
51216
- })
51217
- ],
51218
- [
51219
- "bar-stacked",
51220
- withGlobals({
51221
- series: { description: "Series name(s) (required)" },
51222
- "x-label": { description: "X-axis label" },
51223
- "y-label": { description: "Y-axis label" },
51224
- "orientation-horizontal": { description: "Switch to horizontal bars" },
51225
- "no-value": { description: "Hide per-segment values inside each stack" }
51226
- })
51227
- ],
51228
- // ── Extended charts ──────────────────────────────────────
51229
- [
51230
- "scatter",
51231
- withGlobals({
51232
- "no-name": { description: "Hide point labels" },
51233
- "x-label": { description: "X-axis label" },
51234
- "y-label": { description: "Y-axis label" },
51235
- "size-label": { description: "Size axis label" }
51236
- })
51237
- ],
51238
- [
51239
- "heatmap",
51240
- withGlobals({
51241
- columns: { description: "Column labels (required)" },
51242
- "no-value": { description: "Hide cell value text" }
51243
- })
51244
- ],
51245
- ["sankey", withGlobals()],
51246
- ["chord", withGlobals()],
51247
- [
51248
- "funnel",
51249
- withGlobals({
51250
- "no-name": { description: "Hide left-side name labels" },
51251
- "no-value": { description: "Hide right-side value labels" }
51252
- })
51253
- ],
51254
- [
51255
- "function",
51256
- withGlobals({
51257
- x: { description: "X-axis range (start to end)" },
51258
- "x-label": { description: "X-axis label" },
51259
- "y-label": { description: "Y-axis label" },
51260
- shade: { description: "Fill area below curves with translucent color" }
51261
- })
51262
- ],
51263
- // ── Visualizations ───────────────────────────────────────
51264
- ["slope", withGlobals()],
51265
- [
51266
- "wordcloud",
51267
- withGlobals({
51268
- rotate: {
51269
- description: "Word rotation",
51270
- values: ["none", "mixed", "angled"]
51271
- },
51272
- max: { description: "Maximum word count" },
51273
- size: { description: "Font size range (min, max)" }
51274
- })
51275
- ],
51276
- [
51277
- "arc",
51278
- withGlobals({
51279
- order: {
51280
- description: "Node ordering",
51281
- values: ["appearance", "name", "group", "degree"]
51282
- }
51283
- })
51284
- ],
51285
- ["timeline", withGlobals()],
51286
- ["venn", withGlobals()],
51287
- [
51288
- "quadrant",
51289
- withGlobals({
51290
- "x-label": { description: "X-axis labels (low, high)" },
51291
- "y-label": { description: "Y-axis labels (low, high)" }
51292
- })
51293
- ],
51294
- // ── Diagrams ─────────────────────────────────────────────
51295
- [
51296
- "sequence",
51297
- withGlobals({
51298
- activations: {
51299
- description: "Show activation bars",
51300
- values: ["on", "off"]
51301
- },
51302
- "active-tag": { description: "Active tag group name" }
51303
- })
51304
- ],
51305
- [
51306
- "flowchart",
51307
- // Spec §5 §4.6: direction-lr, orientation-vertical, no-color, solid-fill
51308
- withGlobals({
51309
- "direction-lr": { description: "Switch to left-to-right layout" },
51310
- "orientation-vertical": {
51311
- description: "Use vertical orientation for ranks"
51312
- },
51313
- "no-color": {
51314
- description: "Resolve all nodes to muted neutral fill"
51315
- }
51316
- })
51317
- ],
51318
- [
51319
- "class",
51320
- withGlobals({
51321
- "no-auto-color": {
51322
- description: "Disable automatic modifier-based coloring"
51323
- }
51324
- })
51325
- ],
51326
- [
51327
- "er",
51328
- // Spec §9 §8.5: notation (chen/crow), active-tag.
51329
- withGlobals({
51330
- notation: {
51331
- description: "ER notation style",
51332
- values: ["chen", "crow"]
51333
- },
51334
- "active-tag": { description: "Active tag group name" }
51335
- })
51336
- ],
51337
- [
51338
- "org",
51339
- // Spec §7 §6.5: direction-tb, sub-node-label, show-sub-node-count,
51340
- // hide, active-tag. solid-fill via SOLID_FILL_CAPABLE.
51341
- withGlobals({
51342
- "direction-tb": { description: "Switch to top-to-bottom layout" },
51343
- "sub-node-label": { description: "Label for sub-nodes" },
51344
- "show-sub-node-count": { description: "Show sub-node counts" },
51345
- hide: { description: "Hide tag:value pairs" },
51346
- "active-tag": { description: "Active tag group name" }
51347
- })
51348
- ],
51349
- [
51350
- "kanban",
51351
- // Spec §11 §10.4: no-auto-color, hide, active-tag.
51352
- withGlobals({
51353
- "no-auto-color": { description: "Disable automatic card coloring" },
51354
- hide: { description: "Hide tag:value pairs" },
51355
- "active-tag": { description: "Active tag group name" }
51356
- })
51357
- ],
51358
- // RACI / RASCI / DACI — one chart type (`raci`), variant inferred from
51359
- // markers or locked via `variant-*` bare directive. `rasci`/`daci` are
51360
- // not first-line keywords so they get no separate registry entry.
51361
- [
51362
- "raci",
51363
- withGlobals({
51364
- "variant-raci": {
51365
- description: "Lock chart to RACI variant (R / A / C / I markers)"
51366
- },
51367
- "variant-rasci": {
51368
- description: "Lock chart to RASCI variant (adds Support \u2014 R / A / S / C / I)"
51369
- },
51370
- "variant-daci": {
51371
- description: "Lock chart to DACI variant (Driver / Approver / Contributor / Informed)"
51372
- },
51373
- roles: {
51374
- description: "Declare role column order (inline `roles A, B, C` or indented block with per-role pipe metadata)"
51375
- },
51376
- "active-tag": { description: "Active tag group name" }
51377
- })
51378
- ],
51379
- [
51380
- "c4",
51381
- // Spec §8 §7.7: direction-tb, active-tag.
51382
- withGlobals({
51383
- "direction-tb": { description: "Switch to top-to-bottom layout" },
51384
- "active-tag": { description: "Active tag group name" }
51385
- })
51386
- ],
51387
- [
51388
- "state",
51389
- // Spec §6 §5.5: direction-tb, no-color, solid-fill.
51390
- withGlobals({
51391
- "direction-tb": { description: "Switch to top-to-bottom layout" },
51392
- "no-color": {
51393
- description: "Resolve all states to muted neutral fill"
51394
- }
51395
- })
51396
- ],
51397
- [
51398
- "sitemap",
51399
- withGlobals({
51400
- "direction-tb": { description: "Switch to top-to-bottom layout" },
51401
- "active-tag": { description: "Active tag group name" }
51402
- })
51403
- ],
51404
- [
51405
- "infra",
51406
- withGlobals({
51407
- "direction-tb": { description: "Switch to top-to-bottom layout" },
51408
- animate: { description: "Enable traffic animation" },
51409
- "no-animate": { description: "Disable traffic animation" },
51410
- "default-latency-ms": { description: "Default latency for all nodes" },
51411
- "default-uptime": { description: "Default uptime for all nodes" },
51412
- "default-rps": { description: "Default RPS capacity for all nodes" },
51413
- "slo-availability": { description: "SLO availability target (0-1)" },
51414
- "slo-p90-latency-ms": { description: "SLO p90 latency target in ms" },
51415
- "slo-warning-margin": { description: "SLO warning margin percentage" },
51416
- "active-tag": { description: "Active tag group name" }
51417
- })
51418
- ],
51419
- [
51420
- "pert",
51421
- withGlobals({
51422
- "time-unit": {
51423
- description: "Time unit for activity durations",
51424
- values: ["min", "h", "d", "bd", "w", "m", "q", "y"]
51425
- },
51426
- confidence: {
51427
- description: "Confidence factor for M-only durations",
51428
- values: ["high", "medium", "low"]
51429
- },
51430
- direction: { description: "Layout direction", values: ["LR", "TB"] },
51431
- "node-detail": {
51432
- description: "Node visual density",
51433
- values: ["compact", "full"]
51434
- },
51435
- trials: {
51436
- description: "Monte Carlo trial count (auto-derived from activity count)"
51437
- },
51438
- seed: { description: "Monte Carlo PRNG seed (auto-derived from title)" },
51439
- "scrubber-trials": {
51440
- description: "Fast-MC trials for the duration scrubber (default 300)"
51441
- }
51442
- })
51443
- ],
51444
- [
51445
- "gantt",
51446
- // Spec §13 §12.2 Options.
51447
- withGlobals({
51448
- start: { description: "Project start date (YYYY-MM-DD)" },
51449
- "today-marker": {
51450
- description: "Today marker (bare = on, or YYYY-MM-DD date)"
51451
- },
51452
- sort: { description: "Sort order", values: ["time", "group", "tag"] },
51453
- "critical-path": { description: "Show critical path" },
51454
- "no-dependencies": { description: "Hide dependency arrows" },
51455
- "sprint-length": { description: "Sprint duration (e.g. 2w)" },
51456
- "sprint-number": { description: "Starting sprint number" },
51457
- "sprint-start": { description: "Sprint start date (YYYY-MM-DD)" },
51458
- "active-tag": { description: "Active tag group name" },
51459
- // Legacy positive form `dependencies` — kept for back-compat. Use
51460
- // `no-dependencies` to suppress dependency arrows in new code.
51461
- dependencies: { description: "Show dependencies (legacy form)" }
51462
- })
51463
- ],
51464
- [
51465
- "boxes-and-lines",
51466
- withGlobals({
51467
- direction: { description: "Layout direction", values: ["LR", "TB"] },
51468
- "active-tag": { description: "Active tag group name" },
51469
- hide: { description: "Hide tag:value pairs" }
51470
- })
51471
- ],
51472
- [
51473
- "mindmap",
51474
- withGlobals({
51475
- "no-descriptions": { description: "Hide node descriptions" },
51476
- "active-tag": { description: "Active tag group name" }
51477
- })
51478
- ],
51479
- [
51480
- "wireframe",
51481
- withGlobals({
51482
- mobile: { description: "Use mobile (narrow vertical) layout" },
51483
- "active-tag": { description: "Active tag group name" }
51484
- })
51485
- ],
51486
- [
51487
- "tech-radar",
51488
- // Spec §20 documents one directive: `show-blip-legend`. `rings` is a
51489
- // structural block keyword; quadrant/ring/trend/color are pipe metadata
51490
- // that live in PIPE_METADATA.
51491
- withGlobals({
51492
- "show-blip-legend": {
51493
- description: "Render the four-column blip listing alongside the radar"
51494
- }
51495
- })
51496
- ],
51497
- [
51498
- "cycle",
51499
- withGlobals({
51500
- "direction-counterclockwise": {
51501
- description: "Reverse cycle direction to counterclockwise"
51502
- },
51503
- "no-descriptions": { description: "Hide node and edge descriptions" },
51504
- "circle-nodes": {
51505
- description: "Render nodes as circles instead of rectangles"
51506
- }
51507
- })
51508
- ],
51509
- [
51510
- "journey-map",
51511
- // Spec §22 directives: `no-legend`, `active-tag`. `persona` is a
51512
- // structural keyword (like `tag` / `roles`), not a directive.
51513
- // `solid-fill` is added via SOLID_FILL_CAPABLE below.
51514
- withGlobals({
51515
- "no-legend": { description: "Hide the score legend" },
51516
- "active-tag": { description: "Active tag group name" }
51517
- })
51518
- ],
51519
- [
51520
- "pyramid",
51521
- // Spec §23.5 documents `inverted`; `solid-fill` is added via
51522
- // SOLID_FILL_CAPABLE below (working but not yet in spec §23.5).
51523
- // `color`/`description` are layer pipe-metadata, not directives.
51524
- withGlobals({
51525
- inverted: { description: "Flip apex to the bottom (funnel orientation)" }
51526
- })
51527
- ],
51528
- [
51529
- "ring",
51530
- // Per spec §24.5 the only chart-specific directive is `solid-fill`,
51531
- // applied via SOLID_FILL_CAPABLE below. `color`/`description` are
51532
- // layer pipe-metadata, not directives — they live in PIPE_METADATA.
51533
- withGlobals({})
51534
- ]
51535
- ]);
51536
- {
51537
- const raciSpec = COMPLETION_REGISTRY.get("raci");
51538
- if (raciSpec) {
51539
- COMPLETION_REGISTRY.set("rasci", raciSpec);
51540
- COMPLETION_REGISTRY.set("daci", raciSpec);
51541
- }
51542
- }
51543
- var SOLID_FILL_CAPABLE = /* @__PURE__ */ new Set([
51544
- "flowchart",
51545
- "state",
51546
- "sequence",
51547
- "c4",
51548
- "org",
51549
- "kanban",
51550
- "journey-map",
51551
- "mindmap",
51552
- "cycle",
51553
- "pyramid",
51554
- "ring",
51555
- "funnel",
51556
- "class",
51557
- "er",
51558
- "sitemap",
51559
- "boxes-and-lines",
51560
- "wireframe",
51561
- "bar",
51562
- "bar-stacked",
51563
- "pie",
51564
- "doughnut",
51565
- "polar-area",
51566
- "radar",
51567
- "scatter",
51568
- "chord"
51569
- ]);
51570
- for (const [type, spec] of COMPLETION_REGISTRY) {
51571
- if (SOLID_FILL_CAPABLE.has(type)) {
51572
- spec.directives["solid-fill"] = {
51573
- description: "Render shapes with full intent color instead of the default 25% tint"
51574
- };
51575
- }
51576
- }
51577
- var CHART_TYPES = [...ALL_CHART_TYPES].filter((t) => t !== "multi-line").map((name) => ({
51578
- name,
51579
- description: CHART_TYPE_DESCRIPTIONS[name] ?? name
51580
- }));
51581
- var ENTITY_TYPES = /* @__PURE__ */ new Map([
51582
- [
51583
- "sequence",
51584
- [
51585
- "service",
51586
- "database",
51587
- "actor",
51588
- "queue",
51589
- "cache",
51590
- "gateway",
51591
- "external",
51592
- "networking",
51593
- "frontend"
51594
- ]
51595
- ],
51596
- [
51597
- "c4",
51598
- ["person", "system", "container", "component", "external", "database"]
51599
- ]
51600
- ]);
51601
- var PIPE_METADATA = /* @__PURE__ */ new Map([
51602
- [
51603
- "infra",
51604
- {
51605
- node: {
51606
- description: { description: "Node description text" },
51607
- instances: {
51608
- description: "Instance count or auto-scaling range (N-M)"
51609
- },
51610
- "latency-ms": { description: "Per-request latency in milliseconds" },
51611
- "max-rps": { description: "Max requests per second per instance" },
51612
- "cache-hit": { description: "Cache hit percentage (0-100)" },
51613
- "firewall-block": { description: "Traffic blocked percentage" },
51614
- "ratelimit-rps": { description: "Max RPS allowed through" },
51615
- "cb-error-threshold": {
51616
- description: "Circuit breaker error threshold %"
51617
- },
51618
- "cb-latency-threshold-ms": {
51619
- description: "Circuit breaker latency threshold"
51620
- },
51621
- uptime: { description: "Component availability (0-1)" },
51622
- concurrency: { description: "Concurrent request limit" },
51623
- "duration-ms": { description: "Processing duration" },
51624
- "cold-start-ms": { description: "Function cold-start time" },
51625
- buffer: { description: "Queue/buffer capacity" },
51626
- "drain-rate": { description: "Queue drain rate" },
51627
- "retention-hours": { description: "Data retention period" },
51628
- partitions: { description: "Queue/stream partition count" },
51629
- "slo-availability": { description: "Node availability target (0-1)" },
51630
- "slo-p90-latency-ms": { description: "Node p90 latency target" },
51631
- "slo-warning-margin": { description: "Node SLO warning margin" }
51632
- },
51633
- edge: {
51634
- split: { description: "Traffic split percentage (e.g., 60%)" },
51635
- fanout: { description: "Fanout multiplier (integer >= 1)" }
51636
- }
51637
- }
51638
- ],
51639
- [
51640
- "c4",
51641
- {
51642
- node: {
51643
- description: { description: "Element description" },
51644
- tech: { description: "Technology stack" },
51645
- technology: { description: "Technology stack (alias for tech)" }
51646
- },
51647
- edge: {}
51648
- }
51649
- ],
51650
- [
51651
- "gantt",
51652
- {
51653
- node: {},
51654
- edge: {
51655
- // Gantt "edge" = dependency arrow (TaskA -> TaskB | offset 2bd)
51656
- offset: { description: "Dependency offset (e.g., 2bd, -1w)" }
51657
- }
51658
- }
51659
- ],
51660
- [
51661
- "boxes-and-lines",
51662
- {
51663
- node: {
51664
- description: { description: "Node description text" }
51665
- },
51666
- edge: {}
51667
- }
51668
- ],
51669
- [
51670
- "mindmap",
51671
- {
51672
- node: {
51673
- description: { description: "Node description text" },
51674
- collapsed: { description: "Collapse node subtree by default" }
51675
- },
51676
- edge: {}
51677
- }
51678
- ],
51679
- [
51680
- // Tech-radar pipe metadata (spec §20). Two contexts:
51681
- // - quadrant: top-level quadrant headers (`Tools | quadrant: top-left, color: blue`)
51682
- // - blip: indented blip lines (` Vite | ring: Adopt, trend: up`)
51683
- "tech-radar",
51684
- {
51685
- quadrant: {
51686
- quadrant: {
51687
- description: "Quadrant position",
51688
- values: ["top-left", "top-right", "bottom-left", "bottom-right"]
51689
- },
51690
- color: { description: "Override quadrant color" }
51691
- },
51692
- blip: {
51693
- ring: { description: "Ring assignment (must match a declared ring)" },
51694
- trend: {
51695
- description: "Blip trend indicator",
51696
- values: ["new", "up", "down", "stable"]
51697
- }
51698
- }
51699
- }
51700
- ],
51701
- [
51702
- "cycle",
51703
- {
51704
- node: {
51705
- color: { description: "Node fill color (palette name)" },
51706
- span: { description: "Relative arc distance to next node" },
51707
- description: { description: "Node description text" }
51708
- },
51709
- edge: {
51710
- color: { description: "Edge stroke color (palette name)" },
51711
- width: { description: "Edge stroke width in pixels" }
51712
- }
51713
- }
51714
- ],
51715
- [
51716
- // RACI pipe metadata (spec §24A). Two contexts:
51717
- // - role: declarations inside the `roles` block (`Cap | color: red`)
51718
- // - phase: bracketed phase headers (`[Departure] | color: teal`)
51719
- "raci",
51720
- {
51721
- role: {
51722
- color: { description: "Role column tint (palette name)" }
51723
- },
51724
- phase: {
51725
- color: { description: "Phase bar tint (palette name)" }
51726
- }
51727
- }
51728
- ],
51729
- [
51730
- // Ring layer pipe metadata (spec §24.4). One context: `layer`.
51731
- "ring",
51732
- {
51733
- layer: {
51734
- color: { description: "Ring color (palette name)" },
51735
- description: { description: "Layer description (one-liner shorthand)" }
51736
- }
51737
- }
51738
- ],
51739
- [
51740
- // Pyramid layer pipe metadata (spec §23.4). Identical surface to ring.
51741
- "pyramid",
51742
- {
51743
- layer: {
51744
- color: { description: "Layer color (palette name)" },
51745
- description: { description: "Layer description (one-liner shorthand)" }
51746
- }
51747
- }
51748
- ],
51749
- [
51750
- // Journey-map step pipe metadata (spec §22). One static key: `score`.
51751
- // Tag aliases (e.g. `ch: Web`) are user-defined via the `tag` block
51752
- // and resolved dynamically — not part of the static map.
51753
- "journey-map",
51754
- {
51755
- step: {
51756
- score: { description: "Step score (1\u20135 integer; high = good)" }
51757
- }
51758
- }
51759
- ]
51760
- ]);
51761
- var METADATA_KEY_SET = /* @__PURE__ */ new Set([
51762
- "chart",
51763
- "title",
51764
- // implicit directives recognized as metadata
51765
- ...[...COMPLETION_REGISTRY.values()].flatMap(
51766
- (spec) => Object.keys(spec.directives)
51767
- )
51768
- ]);
51769
- var SEQ_ARROW_RE = /^(?:"([^"]+)"|([^|"]+?))\s+(->|-.*->|~>|~.*~>)\s+(?:"([^"]+)"|([^|"]+?))(?:\s|\|.*)?$/;
51770
- var SEQ_IS_A_RE = /^(?:"([^"]+)"|([^|":]+?))\s+is\s+an?\s+/i;
51771
- var SEQ_SECTION_RE = /^==/;
51772
- var SEQ_STRUCTURAL_RE = /^(if|else|loop|parallel|end)\b/i;
51773
- function extractSequenceSymbols(docText) {
51774
- const lines = docText.split("\n");
51775
- const entities = [];
51776
- let pastFirstLine = false;
51777
- for (const line12 of lines) {
51778
- const trimmed = line12.trim();
51779
- if (!trimmed || trimmed.startsWith("//")) continue;
51780
- if (!pastFirstLine) {
51781
- pastFirstLine = true;
51782
- continue;
51783
- }
51784
- const firstToken = trimmed.split(/\s+/)[0].toLowerCase();
51785
- if (METADATA_KEY_SET.has(firstToken)) continue;
51786
- if (SEQ_SECTION_RE.test(trimmed)) continue;
51787
- if (SEQ_STRUCTURAL_RE.test(trimmed)) continue;
51788
- const arrowMatch = trimmed.match(SEQ_ARROW_RE);
51789
- if (arrowMatch) {
51790
- const src = (arrowMatch[1] ?? arrowMatch[2] ?? "").trim();
51791
- const dst = (arrowMatch[4] ?? arrowMatch[5] ?? "").trim();
51792
- if (src && !entities.includes(src)) entities.push(src);
51793
- if (dst && !entities.includes(dst)) entities.push(dst);
51794
- continue;
51795
- }
51796
- const isAMatch = trimmed.match(SEQ_IS_A_RE);
51797
- if (isAMatch) {
51798
- const name = (isAMatch[1] ?? isAMatch[2] ?? "").trim();
51799
- if (name && !entities.includes(name)) entities.push(name);
51800
- continue;
51801
- }
51802
- }
51803
- return {
51804
- kind: "sequence",
51805
- entities,
51806
- keywords: ["if", "else", "loop", "parallel", "note"]
51807
- };
51808
- }
51809
- var STATE_ARROW_RE = /^(\S+)\s+->\s+(\S+)/;
51810
- function extractStateSymbols(docText) {
51811
- const lines = docText.split("\n");
51812
- const entities = [];
51813
- let pastFirstLine = false;
51814
- for (const line12 of lines) {
51815
- const trimmed = line12.trim();
51816
- if (!trimmed || trimmed.startsWith("//")) continue;
51817
- if (!pastFirstLine) {
51818
- pastFirstLine = true;
51819
- continue;
51820
- }
51821
- const firstToken = trimmed.split(/\s+/)[0].toLowerCase();
51822
- if (METADATA_KEY_SET.has(firstToken)) continue;
51823
- const arrowMatch = trimmed.match(STATE_ARROW_RE);
51824
- if (arrowMatch) {
51825
- const src = arrowMatch[1].split("|")[0].trim();
51826
- const dst = arrowMatch[2].split("|")[0].trim();
51827
- if (src && !entities.includes(src)) entities.push(src);
51828
- if (dst && !entities.includes(dst)) entities.push(dst);
51829
- }
51830
- }
51831
- return { kind: "state", entities, keywords: [] };
51832
- }
51833
- var TAG_DECL_EXPLICIT_RE = /^tag\s+(\S+)\s+alias\s+(\S+)/i;
51834
- var TAG_DECL_SHORT_RE = /^tag\s+(\S+)\s+([a-z]{1,4})(?:\s|$)/;
51835
- function extractTagDeclarations(docText) {
51836
- const result = /* @__PURE__ */ new Map();
51837
- const lines = docText.split("\n");
51838
- let currentAlias = null;
51839
- let currentValues = [];
51840
- for (let i = 0; i < lines.length; i++) {
51841
- const raw = lines[i];
51842
- const trimmed = raw.trim();
51843
- const tagMatch = trimmed.match(TAG_DECL_EXPLICIT_RE) ?? trimmed.match(TAG_DECL_SHORT_RE);
51844
- if (tagMatch) {
51845
- if (currentAlias !== null) {
51846
- result.set(currentAlias, currentValues);
51847
- }
51848
- const name = tagMatch[1];
51849
- const alias = tagMatch[2] ?? name;
51850
- currentAlias = alias;
51851
- currentValues = [];
51852
- continue;
51853
- }
51854
- if (/^tag\s+(\S+)\s*$/i.test(trimmed)) {
51855
- if (currentAlias !== null) {
51856
- result.set(currentAlias, currentValues);
51857
- }
51858
- currentAlias = trimmed.match(/^tag\s+(\S+)/i)[1];
51859
- currentValues = [];
51860
- continue;
51861
- }
51862
- if (currentAlias !== null && raw.length > 0 && (raw[0] === " " || raw[0] === " ")) {
51863
- if (trimmed && !trimmed.startsWith("//")) {
51864
- const colorIdx = trimmed.indexOf("(");
51865
- const value = colorIdx > 0 ? trimmed.substring(0, colorIdx).trim() : trimmed;
51866
- if (value) currentValues.push(value);
51867
- }
51868
- continue;
51869
- }
51870
- if (currentAlias !== null && trimmed) {
51871
- result.set(currentAlias, currentValues);
51872
- currentAlias = null;
51873
- currentValues = [];
51874
- }
51875
- }
51876
- if (currentAlias !== null) {
51877
- result.set(currentAlias, currentValues);
51878
- }
51879
- return result;
51880
- }
51881
- var ALIAS_POSTFIX_DECL_RE = /(?:^|[^|/])\s*(.+?)\s+as\s+([A-Za-z][A-Za-z0-9_]{0,11})\s*(?:\|.*)?$/;
51882
- function extractAliasDeclarations(docText) {
51883
- const aliases = {};
51884
- for (const raw of docText.split("\n")) {
51885
- const trimmed = raw.trim();
51886
- if (!trimmed || trimmed.startsWith("//")) continue;
51887
- const match = trimmed.match(ALIAS_POSTFIX_DECL_RE);
51888
- if (!match) continue;
51889
- const canonical = match[1].trim();
51890
- const alias = match[2];
51891
- if (!canonical || canonical === "[" || canonical === "]") continue;
51892
- if (!(alias in aliases)) {
51893
- aliases[alias] = canonical;
51894
- }
51895
- }
51896
- return aliases;
51897
- }
51898
- var SITEMAP_CONTAINER_RE = /^\[([^\]]+)\]/;
51899
- var SITEMAP_ARROW_RE = /^-.*->\s*(.+)$/;
51900
- var SITEMAP_BARE_ARROW_RE = /^->\s*(.+)$/;
51901
- var SITEMAP_METADATA_RE = /^([^:]+):\s*(.+)$/;
51902
- function extractSitemapSymbols(docText) {
51903
- const lines = docText.split("\n");
51904
- const entities = [];
51905
- let pastFirstLine = false;
51906
- let inTagBlock = false;
51907
- let lastNodeIndent = -1;
51908
- for (const line12 of lines) {
51909
- const trimmed = line12.trim();
51910
- if (!trimmed || trimmed.startsWith("//")) continue;
51911
- if (!pastFirstLine) {
51912
- pastFirstLine = true;
51913
- continue;
51914
- }
51915
- const firstToken = trimmed.split(/\s+/)[0].toLowerCase();
51916
- if (METADATA_KEY_SET.has(firstToken)) continue;
51917
- if (/^tag\s+/i.test(trimmed)) {
51918
- inTagBlock = true;
51919
- continue;
51920
- }
51921
- const indent = line12.search(/\S/);
51922
- if (inTagBlock) {
51923
- if (indent > 0) continue;
51924
- inTagBlock = false;
51925
- }
51926
- const containerMatch = trimmed.match(SITEMAP_CONTAINER_RE);
51927
- if (containerMatch) {
51928
- const name = containerMatch[1].split("|")[0].trim();
51929
- if (name && !entities.includes(name)) entities.push(name);
51930
- lastNodeIndent = indent;
51931
- continue;
51932
- }
51933
- const bareArrow = trimmed.match(SITEMAP_BARE_ARROW_RE);
51934
- const labeledArrow = !bareArrow ? trimmed.match(SITEMAP_ARROW_RE) : null;
51935
- if (bareArrow || labeledArrow) {
51936
- const target = (bareArrow?.[1] ?? labeledArrow?.[1] ?? "").split("|")[0].trim();
51937
- if (target && !entities.includes(target)) entities.push(target);
51938
- continue;
51939
- }
51940
- if (indent > 0 && lastNodeIndent >= 0 && indent > lastNodeIndent && SITEMAP_METADATA_RE.test(trimmed)) {
51941
- continue;
51942
- }
51943
- const label = trimmed.split("|")[0].trim();
51944
- if (label) {
51945
- if (!entities.includes(label)) entities.push(label);
51946
- lastNodeIndent = indent;
51947
- }
51948
- }
51949
- return { kind: "sitemap", entities, keywords: [] };
51950
- }
51951
- var C4_ELEMENT_RE = /^(person|system|container|component)\s+(.+)$/i;
51952
- var C4_IS_A_RE2 = /^(.+?)\s+is\s+an?\s+(person|system|container|component|external|database)\b/i;
51953
- var C4_ARROW_RE = /^(\S+)\s+(?:->|-.*->|~>|~.*~>|<->|<-.*->|<~>|<~.*~>)\s+(\S+)/;
51954
- var C4_SECTION_RE = /^(containers|components|deployment)\s*$/i;
51955
- function extractC4Symbols(docText) {
51956
- const lines = docText.split("\n");
51957
- const entities = [];
51958
- let pastFirstLine = false;
51959
- let inTagBlock = false;
51960
- for (const line12 of lines) {
51961
- const trimmed = line12.trim();
51962
- if (!trimmed || trimmed.startsWith("//")) continue;
51963
- if (!pastFirstLine) {
51964
- pastFirstLine = true;
51965
- continue;
51966
- }
51967
- const firstToken = trimmed.split(/\s+/)[0].toLowerCase();
51968
- if (METADATA_KEY_SET.has(firstToken)) continue;
51969
- if (/^tag\s+/i.test(trimmed)) {
51970
- inTagBlock = true;
51971
- continue;
51972
- }
51973
- const indent = line12.search(/\S/);
51974
- if (inTagBlock) {
51975
- if (indent > 0) continue;
51976
- inTagBlock = false;
51977
- }
51978
- if (C4_SECTION_RE.test(trimmed)) continue;
51979
- const elemMatch = trimmed.match(C4_ELEMENT_RE);
51980
- if (elemMatch) {
51981
- const name = elemMatch[2].split("|")[0].trim();
51982
- if (name && !entities.includes(name)) entities.push(name);
51983
- continue;
51984
- }
51985
- const isAMatch = trimmed.match(C4_IS_A_RE2);
51986
- if (isAMatch) {
51987
- const name = isAMatch[1].split("|")[0].trim();
51988
- if (name && !entities.includes(name)) entities.push(name);
51989
- continue;
51990
- }
51991
- const arrowMatch = trimmed.match(C4_ARROW_RE);
51992
- if (arrowMatch) {
51993
- const src = arrowMatch[1].split("|")[0].trim();
51994
- const dst = arrowMatch[2].split("|")[0].trim();
51995
- if (src && !entities.includes(src)) entities.push(src);
51996
- if (dst && !entities.includes(dst)) entities.push(dst);
51997
- continue;
51998
- }
51999
- }
52000
- return {
52001
- kind: "c4",
52002
- entities,
52003
- keywords: ["containers", "components", "deployment"]
52004
- };
52005
- }
52006
- var GANTT_DURATION_RE2 = /^(\d+(?:\.\d+)?)(min|bd|d|w|m|q|y|h)\??\s+(.+)$/;
52007
- var GANTT_DATE_RE2 = /^(\d{4}-\d{2}-\d{2}(?:\s\d{2}:\d{2})?)\s+(.+)$/;
52008
- var GANTT_GROUP_RE = /^\[(.+?)\]/;
52009
- var GANTT_STRUCTURAL_RE = /^(era|marker|holiday|workweek|parallel)\b/i;
52010
- function extractGanttSymbols(docText) {
52011
- const lines = docText.split("\n");
52012
- const entities = [];
52013
- let pastFirstLine = false;
52014
- let inTagBlock = false;
52015
- for (const line12 of lines) {
52016
- const trimmed = line12.trim();
52017
- if (!trimmed || trimmed.startsWith("//")) continue;
52018
- if (!pastFirstLine) {
52019
- pastFirstLine = true;
52020
- continue;
52021
- }
52022
- const firstToken = trimmed.split(/\s+/)[0].toLowerCase();
52023
- if (METADATA_KEY_SET.has(firstToken)) continue;
52024
- if (/^tag\s+/i.test(trimmed)) {
52025
- inTagBlock = true;
52026
- continue;
52027
- }
52028
- const indent = line12.search(/\S/);
52029
- if (inTagBlock) {
52030
- if (indent > 0) continue;
52031
- inTagBlock = false;
52032
- }
52033
- if (GANTT_STRUCTURAL_RE.test(trimmed)) continue;
52034
- const groupMatch = trimmed.match(GANTT_GROUP_RE);
52035
- if (groupMatch) {
52036
- const name = groupMatch[1].trim();
52037
- if (name && !entities.includes(name)) entities.push(name);
52038
- continue;
52039
- }
52040
- const durMatch = trimmed.match(GANTT_DURATION_RE2);
52041
- if (durMatch) {
52042
- let taskName = durMatch[3].split("|")[0].trim();
52043
- const arrowIdx = taskName.indexOf("->");
52044
- if (arrowIdx > 0)
52045
- taskName = taskName.substring(0, arrowIdx).replace(/-[^>]*$/, "").trim();
52046
- if (taskName && !entities.includes(taskName)) entities.push(taskName);
52047
- continue;
52048
- }
52049
- const dateMatch = trimmed.match(GANTT_DATE_RE2);
52050
- if (dateMatch) {
52051
- let taskName = dateMatch[2].split("|")[0].trim();
52052
- const arrowIdx = taskName.indexOf("->");
52053
- if (arrowIdx > 0)
52054
- taskName = taskName.substring(0, arrowIdx).replace(/-[^>]*$/, "").trim();
52055
- if (taskName && !entities.includes(taskName)) entities.push(taskName);
52056
- continue;
52057
- }
52058
- }
52059
- return { kind: "gantt", entities, keywords: [] };
52060
- }
52061
- var BL_ARROW_RE = /^(\S+)\s+(?:-.*)?(?:->|<->)\s+(\S+)/;
52062
- function extractBoxesAndLinesSymbols(docText) {
52063
- const lines = docText.split("\n");
52064
- const entities = [];
52065
- let pastFirstLine = false;
52066
- let inTagBlock = false;
52067
- for (const line12 of lines) {
52068
- const trimmed = line12.trim();
52069
- if (!trimmed || trimmed.startsWith("//")) continue;
52070
- if (!pastFirstLine) {
52071
- pastFirstLine = true;
52072
- continue;
52073
- }
52074
- const firstToken = trimmed.split(/\s+/)[0].toLowerCase();
52075
- if (METADATA_KEY_SET.has(firstToken)) continue;
52076
- if (/^tag\s+/i.test(trimmed)) {
52077
- inTagBlock = true;
52078
- continue;
52079
- }
52080
- const indent = line12.search(/\S/);
52081
- if (inTagBlock) {
52082
- if (indent > 0) continue;
52083
- inTagBlock = false;
52084
- }
52085
- if (/^\[.+?\]/.test(trimmed)) continue;
52086
- const arrowMatch = trimmed.match(BL_ARROW_RE);
52087
- if (arrowMatch) {
52088
- const src = arrowMatch[1].split("|")[0].trim();
52089
- const dst = arrowMatch[2].split("|")[0].trim();
52090
- if (src && !entities.includes(src)) entities.push(src);
52091
- if (dst && !entities.includes(dst)) entities.push(dst);
52092
- continue;
52093
- }
52094
- const label = trimmed.split("|")[0].split("[")[0].trim();
52095
- if (label && !entities.includes(label)) entities.push(label);
52096
- }
52097
- return { kind: "boxes-and-lines", entities, keywords: [] };
52098
- }
52099
- registerExtractor("er", extractSymbols3);
52100
- registerExtractor("flowchart", extractSymbols);
52101
- registerExtractor("infra", extractSymbols4);
52102
- registerExtractor("class", extractSymbols2);
52103
- registerExtractor("sequence", extractSequenceSymbols);
52104
- registerExtractor("state", extractStateSymbols);
52105
- registerExtractor("sitemap", extractSitemapSymbols);
52106
- registerExtractor("c4", extractC4Symbols);
52107
- registerExtractor("gantt", extractGanttSymbols);
52108
- registerExtractor("pert", extractPertSymbols);
52109
- registerExtractor("boxes-and-lines", extractBoxesAndLinesSymbols);
52110
- registerExtractor("tech-radar", extractTechRadarSymbols);
52111
- registerExtractor("cycle", extractCycleSymbols);
52112
- registerExtractor("journey-map", extractJourneyMapSymbols);
52113
- registerExtractor("raci", extractRaciSymbols);
52114
- registerExtractor("rasci", extractRaciSymbols);
52115
- registerExtractor("daci", extractRaciSymbols);
52116
- function extractTechRadarSymbols(docText) {
52117
- const entities = [];
52118
- const keywords = [
52119
- "rings",
52120
- "quadrant",
52121
- "ring",
52122
- "trend",
52123
- "new",
52124
- "up",
52125
- "down",
52126
- "stable",
52127
- "top-left",
52128
- "top-right",
52129
- "bottom-left",
52130
- "bottom-right",
52131
- "alias",
52132
- "aka",
52133
- "color"
52134
- ];
52135
- const lines = docText.split("\n");
52136
- let inRings = false;
52137
- for (const line12 of lines) {
52138
- const trimmed = line12.trim();
52139
- if (trimmed.toLowerCase() === "rings") {
52140
- inRings = true;
52141
- continue;
52142
- }
52143
- if (inRings) {
52144
- if (!trimmed || line12[0] !== " " && line12[0] !== " ") {
52145
- inRings = false;
52146
- continue;
52147
- }
52148
- const aliasMatch = trimmed.match(/^(.+?)\s+(?:alias|aka)\s+(\S+)\s*$/i);
52149
- if (aliasMatch) {
52150
- entities.push(aliasMatch[1].trim());
52151
- entities.push(aliasMatch[2].trim());
52152
- } else {
52153
- entities.push(trimmed);
52154
- }
52155
- }
49809
+
49810
+ // src/index.ts
49811
+ async function render2(text, options) {
49812
+ const palette = options?.palette ?? palettes.nord;
49813
+ const onError = options?.onError ?? "svg";
49814
+ const result = await render(text, {
49815
+ theme: options?.theme,
49816
+ palette: palette.id
49817
+ });
49818
+ const errors = result.diagnostics.filter((d) => d.severity === "error");
49819
+ if (errors.length === 0) {
49820
+ return result;
52156
49821
  }
52157
- return { kind: "tech-radar", entities, keywords };
52158
- }
52159
- function extractCycleSymbols(docText) {
52160
- const lines = docText.split("\n");
52161
- const entities = [];
52162
- let pastFirstLine = false;
52163
- for (const line12 of lines) {
52164
- const trimmed = line12.trim();
52165
- if (!trimmed || trimmed.startsWith("//")) continue;
52166
- if (!pastFirstLine) {
52167
- pastFirstLine = true;
52168
- continue;
52169
- }
52170
- const firstToken = trimmed.split(/\s+/)[0].toLowerCase();
52171
- if (METADATA_KEY_SET.has(firstToken)) continue;
52172
- if (firstToken === "direction-counterclockwise" || firstToken === "circle-nodes" || firstToken === "no-descriptions")
52173
- continue;
52174
- if (line12[0] === " " || line12[0] === " ") continue;
52175
- const label = trimmed.split("|")[0].trim();
52176
- if (label && !entities.includes(label)) entities.push(label);
49822
+ if (onError === "throw") {
49823
+ throw new Error(
49824
+ `DGMO parse error: ${errors.map(formatDgmoError).join("; ")}`
49825
+ );
52177
49826
  }
52178
- return {
52179
- kind: "cycle",
52180
- entities,
52181
- keywords: ["direction-counterclockwise", "no-descriptions", "circle-nodes"]
52182
- };
52183
- }
52184
- var RACI_PHASE_RE = /^\[(.+)\]\s*$/;
52185
- var RACI_ROLES_DIRECTIVE_RE = /^roles\s+(.+)$/i;
52186
- var RACI_VARIANT_DIRECTIVE_RE = /^variant\s+(.+)$/i;
52187
- var RACI_ROLE_ASSIGNMENT_RE = /^([^:]+):\s*(.*)$/;
52188
- function extractRaciSymbols(docText) {
52189
- const lines = docText.split("\n");
52190
- const entities = [];
52191
- let chartType = "raci";
52192
- let pastFirstLine = false;
52193
- let underTask = false;
52194
- const push = (s) => {
52195
- const trimmed = s.trim();
52196
- if (trimmed && !entities.includes(trimmed)) entities.push(trimmed);
52197
- };
52198
- for (const line12 of lines) {
52199
- const trimmed = line12.trim();
52200
- if (!trimmed || trimmed.startsWith("//")) continue;
52201
- if (!pastFirstLine) {
52202
- pastFirstLine = true;
52203
- const firstToken = trimmed.split(/\s+/)[0].toLowerCase();
52204
- if (firstToken === "raci" || firstToken === "rasci" || firstToken === "daci") {
52205
- chartType = firstToken;
52206
- }
52207
- continue;
52208
- }
52209
- const indent = line12.length - line12.trimStart().length;
52210
- if (indent === 0) {
52211
- const rolesMatch = trimmed.match(RACI_ROLES_DIRECTIVE_RE);
52212
- if (rolesMatch) {
52213
- for (const r of rolesMatch[1].split(",")) push(r);
52214
- continue;
52215
- }
52216
- if (RACI_VARIANT_DIRECTIVE_RE.test(trimmed)) continue;
52217
- if (METADATA_KEY_SET.has(trimmed.split(/\s+/)[0].toLowerCase())) continue;
52218
- if (trimmed.toLowerCase() === "draft" || trimmed.toLowerCase() === "solid-fill")
52219
- continue;
52220
- }
52221
- const phaseMatch = trimmed.match(RACI_PHASE_RE);
52222
- if (phaseMatch && indent === 0) {
52223
- push(phaseMatch[1]);
52224
- underTask = false;
52225
- continue;
52226
- }
52227
- const roleMatch = trimmed.match(RACI_ROLE_ASSIGNMENT_RE);
52228
- if (underTask && roleMatch) {
52229
- const rolePart = roleMatch[1].trim();
52230
- push(rolePart);
52231
- continue;
52232
- }
52233
- push(trimmed);
52234
- underTask = true;
49827
+ if (onError === "silent") {
49828
+ return result;
52235
49829
  }
52236
49830
  return {
52237
- kind: chartType,
52238
- entities,
52239
- keywords: ["variant", "roles", "no-rule-enforcement"]
52240
- };
49831
+ svg: result.svg || renderErrorSvg(errors, palette, options?.theme),
49832
+ diagnostics: result.diagnostics
49833
+ };
49834
+ }
49835
+ function renderErrorSvg(errors, palette, theme) {
49836
+ const colors = palette[theme === "dark" ? "dark" : "light"];
49837
+ const bg = theme === "transparent" ? "transparent" : colors.bg;
49838
+ const fg = colors.destructive ?? colors.text;
49839
+ const muted = colors.textMuted ?? colors.text;
49840
+ const lines = errors.slice(0, 5).map((e) => formatDgmoError(e));
49841
+ const height = 60 + lines.length * 20;
49842
+ const body = lines.map(
49843
+ (line12, i) => `<text x="20" y="${60 + i * 20}" fill="${fg}" font-family="ui-monospace, monospace" font-size="12">${escapeXml(line12)}</text>`
49844
+ ).join("");
49845
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="640" height="${height}" viewBox="0 0 640 ${height}"><rect width="100%" height="100%" fill="${bg}"/><text x="20" y="34" fill="${muted}" font-family="system-ui, sans-serif" font-size="13" font-weight="600">DGMO parse error</text>${body}</svg>`;
49846
+ }
49847
+ function escapeXml(s) {
49848
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
52241
49849
  }
52242
- function extractJourneyMapSymbols(docText) {
52243
- const lines = docText.split("\n");
52244
- const entities = [];
52245
- let pastFirstLine = false;
52246
- for (const line12 of lines) {
52247
- const trimmed = line12.trim();
52248
- if (!trimmed || trimmed.startsWith("//")) continue;
52249
- if (!pastFirstLine) {
52250
- pastFirstLine = true;
52251
- continue;
52252
- }
52253
- const firstToken = trimmed.split(/\s+/)[0].toLowerCase();
52254
- if (METADATA_KEY_SET.has(firstToken)) continue;
52255
- if (firstToken === "persona" || firstToken === "tag" || firstToken === "no-legend")
52256
- continue;
52257
- const isIndented = line12[0] === " " || line12[0] === " ";
52258
- if (isIndented) {
52259
- if (/^(pain|opportunity|thought|description)\s*:/i.test(trimmed))
52260
- continue;
52261
- if (/^\S+\([^)]+\)/.test(trimmed)) continue;
52262
- }
52263
- const phaseMatch = trimmed.match(/^\[(.+?)\]$/);
52264
- if (phaseMatch) {
52265
- entities.push(phaseMatch[1].trim());
52266
- continue;
52267
- }
52268
- const label = trimmed.split("|")[0].trim();
52269
- if (label && !entities.includes(label)) entities.push(label);
52270
- }
52271
- return {
52272
- kind: "journey-map",
52273
- entities,
52274
- keywords: [
52275
- "persona",
52276
- "no-legend",
52277
- "pain",
52278
- "opportunity",
52279
- "thought",
52280
- "description"
52281
- ]
52282
- };
49850
+ function encodeDiagramUrl2(text, options) {
49851
+ const internalTheme = options?.theme === "light" || options?.theme === "dark" ? options.theme : void 0;
49852
+ const result = encodeDiagramUrl(text, {
49853
+ baseUrl: options?.baseUrl,
49854
+ palette: options?.palette?.id,
49855
+ theme: internalTheme,
49856
+ filename: options?.filename
49857
+ });
49858
+ return "error" in result && result.error ? null : result.url ?? null;
49859
+ }
49860
+ function decodeDiagramUrl2(url) {
49861
+ const decoded = decodeDiagramUrl(url);
49862
+ if (!decoded.dsl) return null;
49863
+ const palette = decoded.palette ? getPalette(decoded.palette) : void 0;
49864
+ const out = { text: decoded.dsl };
49865
+ if (palette) out.palette = palette;
49866
+ if (decoded.theme) out.theme = decoded.theme;
49867
+ if (decoded.filename) out.filename = decoded.filename;
49868
+ return out;
52283
49869
  }
52284
-
52285
- // src/index.ts
52286
- init_parsing();
52287
49870
  export {
52288
- ALL_CHART_TYPES,
52289
- AMBIGUITY_THRESHOLD,
52290
- ARROW_DIAGNOSTIC_CODES,
52291
- BETA_CHART_IDS,
52292
- CHART_TYPES,
52293
- CHART_TYPE_DESCRIPTIONS,
52294
- COMPLETION_REGISTRY,
52295
- ENTITY_TYPES,
52296
- INFRA_BEHAVIOR_KEYS,
52297
- LEGEND_GEAR_PILL_W,
52298
- LEGEND_HEIGHT,
52299
- METADATA_KEY_SET,
52300
- MIN_PRIMARY_SCORE,
52301
- PERT_LEGEND_PILL_HEIGHT,
52302
- PIPE_METADATA,
52303
- RACI_ERROR_CODES,
52304
- VARIANTS as RACI_VARIANTS,
52305
- RACI_WARNING_CODES,
52306
- RECOGNIZED_COLOR_NAMES,
52307
- RULE_COUNT,
52308
- addDurationToDate,
52309
- analyzePert,
52310
- applyCollapseProjection,
52311
- applyGroupOrdering,
52312
- applyPositionOverrides,
52313
- boldPalette,
52314
- buildExtendedChartOption,
52315
- buildNoteMessageMap,
52316
- buildRenderSequence,
52317
- buildSimpleChartOption,
52318
- buildTagLaneRowList,
52319
- calculateSchedule,
52320
- catppuccinPalette,
52321
- confidence as chartTypeConfidence,
52322
- chartTypeParsers,
52323
- chartTypes,
52324
- collapseBoxesAndLines,
52325
- collapseMindmapTree,
52326
- collapseOrgTree,
52327
- collapseSitemapTree,
52328
- collapseStateGroups,
52329
- collectDiagramRoles,
52330
- collectTasks,
52331
- colorNames,
52332
- computeActivations,
52333
- computeCardArchive,
52334
- computeCardMove,
52335
- computeCycleLayout,
52336
- computeInfra,
52337
- computeInfraLegendGroups,
52338
- computeLegendLayout,
52339
- computeRadarLayout,
52340
- computeScatterLabelGraphics,
52341
- computeTimeTicks,
52342
- contrastText,
52343
- controlsGroupCapsuleWidth,
52344
- decodeDiagramUrl,
52345
- decodeViewState,
52346
- displayName,
52347
- draculaPalette,
52348
- encodeDiagramUrl,
52349
- encodeViewState,
52350
- extractDiagramSymbols,
52351
- extractPertSymbols,
52352
- extractTagDeclarations,
52353
- focusOrgTree,
52354
- formatDateLabel,
49871
+ decodeDiagramUrl2 as decodeDiagramUrl,
49872
+ encodeDiagramUrl2 as encodeDiagramUrl,
52355
49873
  formatDgmoError,
52356
- getAllChartTypes,
52357
- getAvailablePalettes,
52358
- getExtendedChartLegendGroups,
52359
- getLegendReservedHeight,
52360
- getOrCreateName,
52361
- getPalette,
52362
- getRadarGeometry,
52363
- getRenderCategory,
52364
- getSeriesColors,
52365
- getSimpleChartLegendGroups,
52366
- groupMessagesBySection,
52367
- gruvboxPalette,
52368
- hexToHSL,
52369
- hexToHSLString,
52370
- highlightPertCriticalPath,
52371
- highlightPertSet,
52372
- hslToHex,
52373
- inferParticipantType,
52374
- inferRoles,
52375
- isArchiveColumn,
52376
- isExtendedChartType,
52377
- isRecognizedColorName,
52378
- isSequenceBlock,
52379
- isSequenceNote,
52380
- isValidHex,
52381
- knownChartTypeIds,
52382
- layoutBoxesAndLines,
52383
- layoutC4Components,
52384
- layoutC4Containers,
52385
- layoutC4Context,
52386
- layoutC4Deployment,
52387
- layoutClassDiagram,
52388
- layoutERDiagram,
52389
- layoutGraph,
52390
- layoutInfra,
52391
- layoutJourneyMap,
52392
- layoutMindmap,
52393
- layoutOrg,
52394
- layoutPert,
52395
- layoutSitemap,
52396
- layoutWireframe,
52397
- looksLikeClassDiagram,
52398
- looksLikeERDiagram,
52399
- looksLikeFlowchart,
52400
- looksLikePert,
52401
- looksLikeSequence,
52402
- looksLikeSitemap,
52403
- looksLikeState,
52404
- makeDgmoError,
52405
- matchColorParens,
52406
- matchesContiguously,
52407
- measurePertAnalysisBlock,
52408
- mix,
52409
- monokaiPalette,
52410
- nord,
52411
- nordPalette,
52412
- normalize as normalizeChartTypePrompt,
52413
- normalizeName,
52414
- normalizePertSourceForShare,
52415
- oneDarkPalette,
52416
- orderArcNodes,
52417
- parseAndLayoutInfra,
52418
- parseBoxesAndLines,
52419
- parseC4,
52420
- parseChart,
52421
- parseClassDiagram,
52422
- parseCycle,
52423
- parseDataRowValues,
52424
- parseDgmo,
52425
- parseDgmoChartType,
52426
- parseERDiagram,
52427
- parseExtendedChart,
52428
- parseFirstLine,
52429
- parseFlowchart,
52430
- parseGantt,
52431
- parseInArrowLabel,
52432
- parseInfra,
52433
- parseInlineMarkdown,
52434
- parseJourneyMap,
52435
- parseKanban,
52436
- parseMindmap,
52437
- parseOrg,
52438
- parsePert,
52439
- parsePyramid,
52440
- parseRaci,
52441
- parseRing,
52442
- parseSequenceDgmo,
52443
- parseSequenceDgmo as parseSequenceDiagram,
52444
- parseSitemap,
52445
- parseState,
52446
- parseTechRadar,
52447
- parseTimelineDate,
52448
- parseVisualization,
52449
- parseWireframe,
52450
- pertLegendBlockWidth,
52451
- pertLegendEntries,
52452
- cellAppendMarker as raciCellAppendMarker,
52453
- cellCycle as raciCellCycle,
52454
- cellRemove as raciCellRemove,
52455
- cellReplace as raciCellReplace,
52456
- registerExtractor,
52457
- registerPalette,
52458
- relayoutPert,
52459
- render,
52460
- renderArcDiagram,
52461
- renderBoxesAndLines,
52462
- renderBoxesAndLinesForExport,
52463
- renderC4ComponentsForExport,
52464
- renderC4Containers,
52465
- renderC4ContainersForExport,
52466
- renderC4Context,
52467
- renderC4ContextForExport,
52468
- renderC4Deployment,
52469
- renderC4DeploymentForExport,
52470
- renderClassDiagram,
52471
- renderClassDiagramForExport,
52472
- renderCycle,
52473
- renderCycleForExport,
52474
- renderERDiagram,
52475
- renderERDiagramForExport,
52476
- renderExtendedChartForExport,
52477
- renderFlowchart,
52478
- renderFlowchartForExport,
52479
- renderForExport,
52480
- renderGantt,
52481
- renderInfra,
52482
- renderJourneyMap,
52483
- renderJourneyMapForExport,
52484
- renderKanban,
52485
- renderKanbanForExport,
52486
- renderLegendD3,
52487
- renderLegendSvg,
52488
- renderLegendSvgFromConfig,
52489
- renderMindmap,
52490
- renderMindmapForExport,
52491
- renderOrg,
52492
- renderOrgForExport,
52493
- renderPert,
52494
- renderPertAnalysisBlock,
52495
- renderPertForExport,
52496
- renderLegendBlock as renderPertLegendBlock,
52497
- renderPyramid,
52498
- renderPyramidForExport,
52499
- renderQuadrant,
52500
- renderQuadrantFocus,
52501
- renderQuadrantFocusForExport,
52502
- renderRaci,
52503
- renderRaciForExport,
52504
- renderRing,
52505
- renderRingForExport,
52506
- renderSequenceDiagram,
52507
- renderSitemap,
52508
- renderSitemapForExport,
52509
- renderSlopeChart,
52510
- renderState,
52511
- renderStateForExport,
52512
- renderTechRadar,
52513
- renderTechRadarForExport,
52514
- renderTimeline,
52515
- renderVenn,
52516
- renderWireframe,
52517
- renderWordCloud,
52518
- resetPertCriticalPath,
52519
- resetPertHighlight,
52520
- resolveColor,
52521
- resolveColorWithDiagnostic,
52522
- resolveOrgImports,
52523
- resolveTaskName,
52524
- rollUpContextRelationships,
52525
- rosePinePalette,
52526
- scoreChartType,
52527
- seriesColors,
52528
- shade,
52529
- shapeFill,
52530
- solarizedPalette,
52531
- suggestChartTypes,
52532
- tint,
52533
- tokyoNightPalette,
52534
- truncateBareUrl,
52535
- validateComputed,
52536
- validateInfra,
52537
- validateLabelCharacters
49874
+ palettes,
49875
+ render2 as render,
49876
+ themes,
49877
+ parseDgmo as validate
52538
49878
  };
52539
49879
  //# sourceMappingURL=index.js.map