@diagrammo/dgmo 0.8.19 → 0.8.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -34,8 +34,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
34
34
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
35
35
 
36
36
  // src/diagnostics.ts
37
- function makeDgmoError(line10, message, severity = "error") {
38
- return { line: line10, message, severity };
37
+ function makeDgmoError(line10, message, severity = "error", code) {
38
+ return code !== void 0 ? { line: line10, message, severity, code } : { line: line10, message, severity };
39
39
  }
40
40
  function formatDgmoError(err) {
41
41
  return err.line > 0 ? `Line ${err.line}: ${err.message}` : err.message;
@@ -76,74 +76,227 @@ var init_diagnostics = __esm({
76
76
  }
77
77
  });
78
78
 
79
- // src/fonts.ts
80
- var FONT_FAMILY;
81
- var init_fonts = __esm({
82
- "src/fonts.ts"() {
79
+ // src/colors.ts
80
+ function isRecognizedColorName(name) {
81
+ return Object.prototype.hasOwnProperty.call(colorNames, name.toLowerCase());
82
+ }
83
+ function resolveColor(color, palette) {
84
+ if (!color) return null;
85
+ if (color.startsWith("#")) return null;
86
+ const lower = color.toLowerCase();
87
+ if (!isRecognizedColorName(lower)) return null;
88
+ if (palette) {
89
+ const named = palette.colors[lower];
90
+ if (named) return named;
91
+ }
92
+ return colorNames[lower];
93
+ }
94
+ function resolveColorWithDiagnostic(color, line10, diagnostics, palette) {
95
+ const resolved = resolveColor(color, palette);
96
+ if (resolved !== null) return resolved;
97
+ const hint = suggest(color, RECOGNIZED_COLOR_NAMES);
98
+ const suggestion = hint ? ` ${hint}` : "";
99
+ diagnostics.push(
100
+ makeDgmoError(
101
+ line10,
102
+ `Unknown color "${color}". Allowed: ${RECOGNIZED_COLOR_NAMES.join(", ")}.${suggestion}`,
103
+ "warning"
104
+ )
105
+ );
106
+ return void 0;
107
+ }
108
+ var nord, colorNames, RECOGNIZED_COLOR_NAMES, seriesColors;
109
+ var init_colors = __esm({
110
+ "src/colors.ts"() {
83
111
  "use strict";
84
- FONT_FAMILY = "Inter, system-ui, Avenir, Helvetica, Arial, sans-serif";
112
+ init_diagnostics();
113
+ nord = {
114
+ // Polar Night (dark)
115
+ nord0: "#2e3440",
116
+ nord1: "#3b4252",
117
+ nord2: "#434c5e",
118
+ nord3: "#4c566a",
119
+ // Snow Storm (light)
120
+ nord4: "#d8dee9",
121
+ nord5: "#e5e9f0",
122
+ nord6: "#eceff4",
123
+ // Frost (accent blues)
124
+ nord7: "#8fbcbb",
125
+ nord8: "#88c0d0",
126
+ nord9: "#81a1c1",
127
+ nord10: "#5e81ac",
128
+ // Aurora (colors)
129
+ nord11: "#bf616a",
130
+ // red
131
+ nord12: "#d08770",
132
+ // orange
133
+ nord13: "#ebcb8b",
134
+ // yellow
135
+ nord14: "#a3be8c",
136
+ // green
137
+ nord15: "#b48ead"
138
+ // purple
139
+ };
140
+ colorNames = {
141
+ red: nord.nord11,
142
+ orange: nord.nord12,
143
+ yellow: nord.nord13,
144
+ green: nord.nord14,
145
+ blue: nord.nord10,
146
+ purple: nord.nord15,
147
+ teal: nord.nord7,
148
+ cyan: nord.nord8,
149
+ gray: nord.nord3,
150
+ black: nord.nord0,
151
+ white: nord.nord6
152
+ };
153
+ RECOGNIZED_COLOR_NAMES = Object.freeze([
154
+ "red",
155
+ "orange",
156
+ "yellow",
157
+ "green",
158
+ "blue",
159
+ "purple",
160
+ "teal",
161
+ "cyan",
162
+ "gray",
163
+ "black",
164
+ "white"
165
+ ]);
166
+ seriesColors = [
167
+ nord.nord10,
168
+ // blue
169
+ nord.nord14,
170
+ // green
171
+ nord.nord13,
172
+ // yellow
173
+ nord.nord12,
174
+ // orange
175
+ nord.nord15,
176
+ // purple
177
+ nord.nord11,
178
+ // red
179
+ nord.nord7,
180
+ // teal
181
+ nord.nord8
182
+ // light blue
183
+ ];
85
184
  }
86
185
  });
87
186
 
88
- // src/branding.ts
89
- var branding_exports = {};
90
- __export(branding_exports, {
91
- injectBranding: () => injectBranding
92
- });
93
- function injectBranding(svgHtml, mutedColor) {
94
- if (!svgHtml) return svgHtml;
95
- const brandingText = `<text x="0" y="0" font-size="10" font-family="${FONT_FAMILY}" fill="${mutedColor}" opacity="0.5" text-anchor="end">diagrammo.app</text>`;
96
- const vbMatch = svgHtml.match(/viewBox="([^"]+)"/);
97
- const heightAttrMatch = svgHtml.match(/height="([^"]+)"/);
98
- if (vbMatch) {
99
- const parts = vbMatch[1].split(/\s+/).map(Number);
100
- if (parts.length === 4) {
101
- const [vx, vy, vw, vh] = parts;
102
- const newVh = vh + BRANDING_HEIGHT;
103
- const textX = vx + vw - 4;
104
- const textY = vy + vh + BRANDING_HEIGHT - 6;
105
- const positioned = brandingText.replace('x="0" y="0"', `x="${textX}" y="${textY}"`);
106
- let result = svgHtml.replace(
107
- /viewBox="[^"]+"/,
108
- `viewBox="${vx} ${vy} ${vw} ${newVh}"`
109
- );
110
- if (heightAttrMatch) {
111
- const oldH = parseFloat(heightAttrMatch[1]);
112
- if (!isNaN(oldH)) {
113
- result = result.replace(
114
- `height="${heightAttrMatch[1]}"`,
115
- `height="${oldH + BRANDING_HEIGHT}"`
116
- );
117
- }
118
- }
119
- result = result.replace("</svg>", `${positioned}</svg>`);
120
- return result;
121
- }
187
+ // src/utils/arrows.ts
188
+ function validateLabelCharacters(label, lineNumber) {
189
+ const out = [];
190
+ if (label.includes("->") || label.includes("~>")) {
191
+ out.push(
192
+ makeDgmoError(
193
+ lineNumber,
194
+ '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.',
195
+ "error",
196
+ ARROW_DIAGNOSTIC_CODES.ARROW_SUBSTRING_IN_LABEL
197
+ )
198
+ );
122
199
  }
123
- if (heightAttrMatch) {
124
- const widthMatch = svgHtml.match(/width="([^"]+)"/);
125
- const w = widthMatch ? parseFloat(widthMatch[1]) : 800;
126
- const h = parseFloat(heightAttrMatch[1]);
127
- if (!isNaN(h) && !isNaN(w)) {
128
- const textX = w - 4;
129
- const textY = h + BRANDING_HEIGHT - 6;
130
- const positioned = brandingText.replace('x="0" y="0"', `x="${textX}" y="${textY}"`);
131
- let result = svgHtml.replace(
132
- `height="${heightAttrMatch[1]}"`,
133
- `height="${h + BRANDING_HEIGHT}"`
200
+ for (const ch of label) {
201
+ const cp = ch.codePointAt(0);
202
+ const isC0 = cp >= 0 && cp <= 31 && cp !== 9;
203
+ const isDel = cp === 127;
204
+ if (isC0 || isDel) {
205
+ const hex = cp.toString(16).toUpperCase().padStart(4, "0");
206
+ out.push(
207
+ makeDgmoError(
208
+ lineNumber,
209
+ `Label contains a control character (U+${hex}). Remove it and use plain text.`,
210
+ "error",
211
+ ARROW_DIAGNOSTIC_CODES.CONTROL_CHAR_IN_LABEL
212
+ )
134
213
  );
135
- result = result.replace("</svg>", `${positioned}</svg>`);
136
- return result;
214
+ break;
137
215
  }
138
216
  }
139
- return svgHtml;
217
+ return out;
218
+ }
219
+ function parseInArrowLabel(rawLabel, lineNumber) {
220
+ const trimmed = rawLabel.trim();
221
+ if (trimmed.length === 0) {
222
+ return { label: void 0, diagnostics: [] };
223
+ }
224
+ const diagnostics = validateLabelCharacters(trimmed, lineNumber);
225
+ return { label: trimmed, diagnostics };
140
226
  }
141
- var BRANDING_HEIGHT;
142
- var init_branding = __esm({
143
- "src/branding.ts"() {
227
+ function matchColorParens(content) {
228
+ const m = content.match(/^\(([A-Za-z]+)\)$/);
229
+ if (!m) return null;
230
+ const candidate = m[1].toLowerCase();
231
+ if (RECOGNIZED_COLOR_NAMES.includes(candidate)) {
232
+ return candidate;
233
+ }
234
+ return null;
235
+ }
236
+ function parseArrow(line10) {
237
+ if (BIDI_SYNC_RE.test(line10) || BIDI_ASYNC_RE.test(line10)) {
238
+ return {
239
+ error: "Bidirectional arrows are no longer supported. Use two separate lines: 'A -msg-> B' and 'B -msg-> A'"
240
+ };
241
+ }
242
+ if (RETURN_SYNC_LABELED_RE.test(line10) || RETURN_ASYNC_LABELED_RE.test(line10)) {
243
+ const m = line10.match(RETURN_SYNC_LABELED_RE) ?? line10.match(RETURN_ASYNC_LABELED_RE);
244
+ const from = m[3];
245
+ const to = m[1];
246
+ const label = m[2].trim();
247
+ return {
248
+ error: `Left-pointing arrows are no longer supported. Write '${from} -${label}-> ${to}' instead`
249
+ };
250
+ }
251
+ const patterns = [
252
+ { re: SYNC_LABELED_RE, async: false },
253
+ { re: ASYNC_LABELED_RE, async: true }
254
+ ];
255
+ for (const { re, async: isAsync } of patterns) {
256
+ const m = line10.match(re);
257
+ if (!m) continue;
258
+ const label = m[2].trim();
259
+ if (!label) return null;
260
+ return {
261
+ from: m[1],
262
+ to: m[3],
263
+ label,
264
+ async: isAsync
265
+ };
266
+ }
267
+ return null;
268
+ }
269
+ var ARROW_DIAGNOSTIC_CODES, SYNC_LABELED_RE, ASYNC_LABELED_RE, RETURN_SYNC_LABELED_RE, RETURN_ASYNC_LABELED_RE, BIDI_SYNC_RE, BIDI_ASYNC_RE;
270
+ var init_arrows = __esm({
271
+ "src/utils/arrows.ts"() {
144
272
  "use strict";
145
- init_fonts();
146
- BRANDING_HEIGHT = 20;
273
+ init_diagnostics();
274
+ init_colors();
275
+ ARROW_DIAGNOSTIC_CODES = {
276
+ /** Active: label contains `->` or `~>` substring (TD-13). */
277
+ ARROW_SUBSTRING_IN_LABEL: "E_ARROW_SUBSTRING_IN_LABEL",
278
+ /** Active: label contains a forbidden control character (TD-14). */
279
+ CONTROL_CHAR_IN_LABEL: "E_CONTROL_CHAR_IN_LABEL",
280
+ /** Reserved: not currently emitted by any parser. See JSDoc above. */
281
+ TRAILING_ARROW_TEXT: "E_TRAILING_ARROW_TEXT",
282
+ /** Reserved: not currently emitted by any parser. See JSDoc above. */
283
+ MIXED_ARROW_DELIMITERS: "E_MIXED_ARROW_DELIMITERS"
284
+ };
285
+ SYNC_LABELED_RE = /^(.+?)\s*-(.+)->\s*(.+)$/;
286
+ ASYNC_LABELED_RE = /^(.+?)\s*~(.+)~>\s*(.+)$/;
287
+ RETURN_SYNC_LABELED_RE = /^(.+?)\s*<-(.+)-\s*(.+)$/;
288
+ RETURN_ASYNC_LABELED_RE = /^(.+?)\s*<~(.+)~\s*(.+)$/;
289
+ BIDI_SYNC_RE = /^(.+?)\s*<-(.+)->\s*(.+)$/;
290
+ BIDI_ASYNC_RE = /^(.+?)\s*<~(.+)~>\s*(.+)$/;
291
+ }
292
+ });
293
+
294
+ // src/fonts.ts
295
+ var FONT_FAMILY;
296
+ var init_fonts = __esm({
297
+ "src/fonts.ts"() {
298
+ "use strict";
299
+ FONT_FAMILY = "Inter, system-ui, Avenir, Helvetica, Arial, sans-serif";
147
300
  }
148
301
  });
149
302
 
@@ -324,110 +477,158 @@ var init_label_layout = __esm({
324
477
  }
325
478
  });
326
479
 
327
- // src/colors.ts
328
- function isRecognizedColorName(name) {
329
- return Object.prototype.hasOwnProperty.call(colorNames, name.toLowerCase());
480
+ // src/utils/time-ticks.ts
481
+ function fractionalYearToDate(frac) {
482
+ const year = Math.floor(frac);
483
+ const remainder = frac - year;
484
+ const monthFrac = remainder * 12;
485
+ const month = Math.floor(monthFrac);
486
+ const monthRemainder = remainder - month / 12;
487
+ const dayFrac = monthRemainder * 365;
488
+ const day = Math.floor(dayFrac) + 1;
489
+ const dayRemainder = dayFrac - Math.floor(dayFrac);
490
+ const hourFrac = dayRemainder * 24;
491
+ const hour = Math.floor(hourFrac);
492
+ const minute = Math.round((hourFrac - hour) * 60);
493
+ return new Date(year, month, day, hour, minute);
330
494
  }
331
- function resolveColor(color, palette) {
332
- if (!color) return null;
333
- if (color.startsWith("#")) return null;
334
- const lower = color.toLowerCase();
335
- if (!isRecognizedColorName(lower)) return null;
336
- if (palette) {
337
- const named = palette.colors[lower];
338
- if (named) return named;
339
- }
340
- return colorNames[lower];
495
+ function dateToFractionalYear(d) {
496
+ return d.getFullYear() + d.getMonth() / 12 + (d.getDate() - 1) / 365 + d.getHours() / 8760 + d.getMinutes() / 525600;
341
497
  }
342
- function resolveColorWithDiagnostic(color, line10, diagnostics, palette) {
343
- const resolved = resolveColor(color, palette);
344
- if (resolved !== null) return resolved;
345
- const hint = suggest(color, RECOGNIZED_COLOR_NAMES);
346
- const suggestion = hint ? ` ${hint}` : "";
347
- diagnostics.push(
348
- makeDgmoError(
349
- line10,
350
- `Unknown color "${color}". Allowed: ${RECOGNIZED_COLOR_NAMES.join(", ")}.${suggestion}`,
351
- "warning"
352
- )
353
- );
354
- return void 0;
498
+ function computeTimeTicks(domainMin, domainMax, scale, boundaryStart, boundaryEnd, boundaryStartLabel, boundaryEndLabel) {
499
+ const minYear = Math.floor(domainMin);
500
+ const maxYear = Math.floor(domainMax);
501
+ const span = domainMax - domainMin;
502
+ let ticks = [];
503
+ const firstYear = Math.ceil(domainMin);
504
+ const lastYear = Math.floor(domainMax);
505
+ if (lastYear >= firstYear + 1) {
506
+ const yearSpan = lastYear - firstYear;
507
+ let step = 1;
508
+ if (yearSpan > 80) step = 20;
509
+ else if (yearSpan > 40) step = 10;
510
+ else if (yearSpan > 20) step = 5;
511
+ else if (yearSpan > 10) step = 2;
512
+ const alignedFirst = Math.ceil(firstYear / step) * step;
513
+ for (let y = alignedFirst; y <= lastYear; y += step) {
514
+ ticks.push({ pos: scale(y), label: String(y) });
515
+ }
516
+ } else if (span > 0.25) {
517
+ const crossesYear = maxYear > minYear;
518
+ for (let y = minYear; y <= maxYear + 1; y++) {
519
+ for (let m = 1; m <= 12; m++) {
520
+ const val = y + (m - 1) / 12;
521
+ if (val > domainMax) break;
522
+ if (val >= domainMin) {
523
+ ticks.push({
524
+ pos: scale(val),
525
+ label: crossesYear ? `${MONTH_ABBR[m - 1]} '${String(y).slice(-2)}` : MONTH_ABBR[m - 1]
526
+ });
527
+ }
528
+ }
529
+ }
530
+ } else if (span <= 685e-6) {
531
+ let stepMin = 5;
532
+ const spanHours = span * 8760;
533
+ if (spanHours > 3) stepMin = 30;
534
+ else if (spanHours > 1) stepMin = 15;
535
+ else if (spanHours > 0.5) stepMin = 10;
536
+ const startDate = fractionalYearToDate(domainMin);
537
+ startDate.setMinutes(
538
+ Math.floor(startDate.getMinutes() / stepMin) * stepMin,
539
+ 0,
540
+ 0
541
+ );
542
+ while (true) {
543
+ const val = dateToFractionalYear(startDate);
544
+ if (val > domainMax) break;
545
+ if (val >= domainMin) {
546
+ const hh = String(startDate.getHours()).padStart(2, "0");
547
+ const mm = String(startDate.getMinutes()).padStart(2, "0");
548
+ ticks.push({ pos: scale(val), label: `${hh}:${mm}` });
549
+ }
550
+ startDate.setMinutes(startDate.getMinutes() + stepMin);
551
+ }
552
+ } else if (span <= 822e-5) {
553
+ let stepHour = 1;
554
+ const spanHours = span * 8760;
555
+ if (spanHours > 48) stepHour = 6;
556
+ else if (spanHours > 24) stepHour = 3;
557
+ else if (spanHours > 12) stepHour = 2;
558
+ const singleDay = spanHours <= 24;
559
+ const startDate = fractionalYearToDate(domainMin);
560
+ startDate.setHours(
561
+ Math.floor(startDate.getHours() / stepHour) * stepHour,
562
+ 0,
563
+ 0,
564
+ 0
565
+ );
566
+ while (true) {
567
+ const val = dateToFractionalYear(startDate);
568
+ if (val > domainMax) break;
569
+ if (val >= domainMin) {
570
+ const hh = String(startDate.getHours()).padStart(2, "0");
571
+ const mm = String(startDate.getMinutes()).padStart(2, "0");
572
+ if (singleDay) {
573
+ ticks.push({ pos: scale(val), label: `${hh}:${mm}` });
574
+ } else {
575
+ const mon = MONTH_ABBR[startDate.getMonth()];
576
+ const d = startDate.getDate();
577
+ ticks.push({ pos: scale(val), label: `${mon} ${d} ${hh}:${mm}` });
578
+ }
579
+ }
580
+ startDate.setHours(startDate.getHours() + stepHour);
581
+ }
582
+ } else {
583
+ for (let y = minYear; y <= maxYear + 1; y++) {
584
+ for (let m = 1; m <= 12; m++) {
585
+ for (const d of [1, 8, 15, 22]) {
586
+ const val = y + (m - 1) / 12 + (d - 1) / 365;
587
+ if (val > domainMax) break;
588
+ if (val >= domainMin) {
589
+ ticks.push({
590
+ pos: scale(val),
591
+ label: `${MONTH_ABBR[m - 1]} ${d}`
592
+ });
593
+ }
594
+ }
595
+ }
596
+ }
597
+ }
598
+ const collisionThreshold = 40;
599
+ if (boundaryStart !== void 0 && boundaryStartLabel) {
600
+ const boundaryPos = scale(boundaryStart);
601
+ ticks = ticks.filter(
602
+ (t) => Math.abs(t.pos - boundaryPos) >= collisionThreshold
603
+ );
604
+ ticks.unshift({ pos: boundaryPos, label: boundaryStartLabel });
605
+ }
606
+ if (boundaryEnd !== void 0 && boundaryEndLabel) {
607
+ const boundaryPos = scale(boundaryEnd);
608
+ ticks = ticks.filter(
609
+ (t) => Math.abs(t.pos - boundaryPos) >= collisionThreshold
610
+ );
611
+ ticks.push({ pos: boundaryPos, label: boundaryEndLabel });
612
+ }
613
+ return ticks;
355
614
  }
356
- var nord, colorNames, RECOGNIZED_COLOR_NAMES, seriesColors;
357
- var init_colors = __esm({
358
- "src/colors.ts"() {
615
+ var MONTH_ABBR;
616
+ var init_time_ticks = __esm({
617
+ "src/utils/time-ticks.ts"() {
359
618
  "use strict";
360
- init_diagnostics();
361
- nord = {
362
- // Polar Night (dark)
363
- nord0: "#2e3440",
364
- nord1: "#3b4252",
365
- nord2: "#434c5e",
366
- nord3: "#4c566a",
367
- // Snow Storm (light)
368
- nord4: "#d8dee9",
369
- nord5: "#e5e9f0",
370
- nord6: "#eceff4",
371
- // Frost (accent blues)
372
- nord7: "#8fbcbb",
373
- nord8: "#88c0d0",
374
- nord9: "#81a1c1",
375
- nord10: "#5e81ac",
376
- // Aurora (colors)
377
- nord11: "#bf616a",
378
- // red
379
- nord12: "#d08770",
380
- // orange
381
- nord13: "#ebcb8b",
382
- // yellow
383
- nord14: "#a3be8c",
384
- // green
385
- nord15: "#b48ead"
386
- // purple
387
- };
388
- colorNames = {
389
- red: nord.nord11,
390
- orange: nord.nord12,
391
- yellow: nord.nord13,
392
- green: nord.nord14,
393
- blue: nord.nord10,
394
- purple: nord.nord15,
395
- teal: nord.nord7,
396
- cyan: nord.nord8,
397
- gray: nord.nord3,
398
- black: nord.nord0,
399
- white: nord.nord6
400
- };
401
- RECOGNIZED_COLOR_NAMES = Object.freeze([
402
- "red",
403
- "orange",
404
- "yellow",
405
- "green",
406
- "blue",
407
- "purple",
408
- "teal",
409
- "cyan",
410
- "gray",
411
- "black",
412
- "white"
413
- ]);
414
- seriesColors = [
415
- nord.nord10,
416
- // blue
417
- nord.nord14,
418
- // green
419
- nord.nord13,
420
- // yellow
421
- nord.nord12,
422
- // orange
423
- nord.nord15,
424
- // purple
425
- nord.nord11,
426
- // red
427
- nord.nord7,
428
- // teal
429
- nord.nord8
430
- // light blue
619
+ MONTH_ABBR = [
620
+ "Jan",
621
+ "Feb",
622
+ "Mar",
623
+ "Apr",
624
+ "May",
625
+ "Jun",
626
+ "Jul",
627
+ "Aug",
628
+ "Sep",
629
+ "Oct",
630
+ "Nov",
631
+ "Dec"
431
632
  ];
432
633
  }
433
634
  });
@@ -556,10 +757,6 @@ function hexToHSLString(hex) {
556
757
  const { h, s, l } = hexToHSL(hex);
557
758
  return `${h} ${s}% ${l}%`;
558
759
  }
559
- function mute(hex) {
560
- const { h, s, l } = hexToHSL(hex);
561
- return hslToHex(h, Math.min(s, 35), Math.min(l, 36));
562
- }
563
760
  function tint(hex, amount) {
564
761
  const raw = hex.replace("#", "");
565
762
  const full = raw.length === 3 ? raw[0] + raw[0] + raw[1] + raw[1] + raw[2] + raw[2] : raw;
@@ -1501,177 +1698,10 @@ var init_monokai = __esm({
1501
1698
  }
1502
1699
  });
1503
1700
 
1504
- // src/palettes/mermaid-bridge.ts
1505
- function buildMermaidThemeVars(colors, isDark) {
1506
- const c = colors.colors;
1507
- const accentOrder = [
1508
- c.blue,
1509
- c.red,
1510
- c.green,
1511
- c.yellow,
1512
- c.purple,
1513
- c.orange,
1514
- c.teal,
1515
- c.cyan,
1516
- colors.secondary
1517
- ];
1518
- const fills = isDark ? accentOrder.map(mute) : accentOrder;
1519
- return {
1520
- // ── Backgrounds ──
1521
- background: isDark ? colors.overlay : colors.border,
1522
- mainBkg: colors.surface,
1523
- // ── Primary/Secondary/Tertiary nodes ──
1524
- primaryColor: isDark ? colors.primary : colors.surface,
1525
- primaryTextColor: colors.text,
1526
- primaryBorderColor: isDark ? colors.secondary : colors.border,
1527
- secondaryColor: colors.secondary,
1528
- secondaryTextColor: contrastText(colors.secondary, colors.text, colors.bg),
1529
- secondaryBorderColor: colors.primary,
1530
- tertiaryColor: colors.accent,
1531
- tertiaryTextColor: contrastText(colors.accent, colors.text, colors.bg),
1532
- tertiaryBorderColor: colors.border,
1533
- // ── Lines & text ──
1534
- lineColor: colors.textMuted,
1535
- textColor: colors.text,
1536
- // ── Clusters ──
1537
- clusterBkg: colors.bg,
1538
- clusterBorder: isDark ? colors.border : colors.textMuted,
1539
- titleColor: colors.text,
1540
- // ── Labels ──
1541
- edgeLabelBackground: "transparent",
1542
- // ── Notes (sequence diagrams) ──
1543
- noteBkgColor: colors.bg,
1544
- noteTextColor: colors.text,
1545
- noteBorderColor: isDark ? colors.border : colors.textMuted,
1546
- // ── Actors (sequence diagrams) ──
1547
- actorBkg: colors.surface,
1548
- actorTextColor: colors.text,
1549
- actorBorder: isDark ? colors.border : colors.textMuted,
1550
- actorLineColor: colors.textMuted,
1551
- // ── Signals (sequence diagrams) ──
1552
- signalColor: colors.textMuted,
1553
- signalTextColor: colors.text,
1554
- // ── Labels ──
1555
- labelColor: colors.text,
1556
- labelTextColor: colors.text,
1557
- labelBoxBkgColor: colors.surface,
1558
- labelBoxBorderColor: isDark ? colors.border : colors.textMuted,
1559
- // ── Loop boxes ──
1560
- loopTextColor: colors.text,
1561
- // ── Activation (sequence diagrams) ──
1562
- activationBkgColor: isDark ? colors.overlay : colors.border,
1563
- activationBorderColor: isDark ? colors.border : colors.textMuted,
1564
- // ── Sequence numbers ──
1565
- sequenceNumberColor: isDark ? colors.text : colors.bg,
1566
- // ── State diagrams ──
1567
- labelBackgroundColor: colors.surface,
1568
- // ── Pie chart (9 slices) ──
1569
- // Dark mode: use muted fills so light pieSectionTextColor stays readable
1570
- ...Object.fromEntries(
1571
- (isDark ? fills : accentOrder).map((col, i) => [`pie${i + 1}`, col])
1572
- ),
1573
- pieTitleTextColor: colors.text,
1574
- pieSectionTextColor: isDark ? colors.text : colors.bg,
1575
- pieLegendTextColor: colors.text,
1576
- pieStrokeColor: "transparent",
1577
- pieOuterStrokeWidth: "0px",
1578
- pieOuterStrokeColor: "transparent",
1579
- // ── cScale (9 tiers) — muted in dark mode ──
1580
- ...Object.fromEntries(fills.map((f, i) => [`cScale${i}`, f])),
1581
- ...Object.fromEntries(
1582
- fills.map((_, i) => [
1583
- `cScaleLabel${i}`,
1584
- isDark ? colors.text : i < 2 || i > 6 ? colors.bg : colors.text
1585
- ])
1586
- ),
1587
- // ── fillType (8 slots) ──
1588
- ...Object.fromEntries(
1589
- [0, 1, 2, 3, 4, 5, 6, 7].map((i) => [
1590
- `fillType${i}`,
1591
- fills[i % fills.length]
1592
- ])
1593
- ),
1594
- // ── Journey actors (6 slots) ──
1595
- ...Object.fromEntries(
1596
- [c.red, c.green, c.yellow, c.purple, c.orange, c.teal].map((color, i) => [
1597
- `actor${i}`,
1598
- color
1599
- ])
1600
- ),
1601
- // ── Flowchart ──
1602
- nodeBorder: isDark ? colors.border : colors.textMuted,
1603
- nodeTextColor: colors.text,
1604
- // ── Gantt ──
1605
- gridColor: isDark ? colors.textMuted : colors.border,
1606
- doneTaskBkgColor: c.green,
1607
- doneTaskBorderColor: isDark ? colors.border : colors.textMuted,
1608
- activeTaskBkgColor: colors.secondary,
1609
- activeTaskBorderColor: colors.primary,
1610
- critBkgColor: c.orange,
1611
- critBorderColor: c.red,
1612
- taskBkgColor: colors.surface,
1613
- taskBorderColor: isDark ? colors.border : colors.textMuted,
1614
- taskTextColor: contrastText(colors.surface, colors.text, colors.bg),
1615
- taskTextDarkColor: colors.bg,
1616
- taskTextLightColor: colors.text,
1617
- taskTextOutsideColor: colors.text,
1618
- doneTaskTextColor: contrastText(c.green, colors.text, colors.bg),
1619
- activeTaskTextColor: contrastText(colors.secondary, colors.text, colors.bg),
1620
- critTaskTextColor: contrastText(c.orange, colors.text, colors.bg),
1621
- sectionBkgColor: isDark ? shade(colors.primary, colors.bg, 0.6) : tint(colors.primary, 0.6),
1622
- altSectionBkgColor: colors.bg,
1623
- sectionBkgColor2: isDark ? shade(colors.primary, colors.bg, 0.6) : tint(colors.primary, 0.6),
1624
- todayLineColor: c.yellow,
1625
- // ── Quadrant ──
1626
- quadrant1Fill: isDark ? shade(c.green, colors.bg, 0.75) : tint(c.green, 0.75),
1627
- quadrant2Fill: isDark ? shade(c.blue, colors.bg, 0.75) : tint(c.blue, 0.75),
1628
- quadrant3Fill: isDark ? shade(c.red, colors.bg, 0.75) : tint(c.red, 0.75),
1629
- quadrant4Fill: isDark ? shade(c.yellow, colors.bg, 0.75) : tint(c.yellow, 0.75),
1630
- quadrant1TextFill: colors.text,
1631
- quadrant2TextFill: colors.text,
1632
- quadrant3TextFill: colors.text,
1633
- quadrant4TextFill: colors.text,
1634
- quadrantPointFill: isDark ? c.cyan : c.blue,
1635
- quadrantPointTextFill: colors.text,
1636
- quadrantXAxisTextFill: colors.text,
1637
- quadrantYAxisTextFill: colors.text,
1638
- quadrantTitleFill: colors.text,
1639
- quadrantInternalBorderStrokeFill: colors.border,
1640
- quadrantExternalBorderStrokeFill: colors.border
1641
- };
1642
- }
1643
- function buildThemeCSS(palette, isDark) {
1644
- const base = `
1645
- .branchLabelBkg { fill: transparent !important; stroke: transparent !important; }
1646
- .commit-label-bkg { fill: transparent !important; stroke: transparent !important; }
1647
- .tag-label-bkg { fill: transparent !important; stroke: transparent !important; }
1648
-
1649
- /* GitGraph: ensure commit and branch label text matches palette */
1650
- .commit-label { fill: ${palette.text} !important; }
1651
- .branch-label { fill: ${palette.text} !important; }
1652
- .tag-label { fill: ${palette.text} !important; }
1653
- `;
1654
- if (!isDark) return base;
1655
- return base + `
1656
- /* Flowchart: ensure node and edge label text is readable */
1657
- .nodeLabel, .label { color: ${palette.text} !important; fill: ${palette.text} !important; }
1658
- .edgeLabel { color: ${palette.text} !important; fill: ${palette.text} !important; }
1659
- .edgeLabel .label { color: ${palette.text} !important; fill: ${palette.text} !important; }
1660
- `;
1661
- }
1662
- var init_mermaid_bridge = __esm({
1663
- "src/palettes/mermaid-bridge.ts"() {
1664
- "use strict";
1665
- init_color_utils();
1666
- }
1667
- });
1668
-
1669
1701
  // src/palettes/index.ts
1670
1702
  var palettes_exports = {};
1671
1703
  __export(palettes_exports, {
1672
1704
  boldPalette: () => boldPalette,
1673
- buildMermaidThemeVars: () => buildMermaidThemeVars,
1674
- buildThemeCSS: () => buildThemeCSS,
1675
1705
  catppuccinPalette: () => catppuccinPalette,
1676
1706
  contrastText: () => contrastText,
1677
1707
  draculaPalette: () => draculaPalette,
@@ -1685,7 +1715,6 @@ __export(palettes_exports, {
1685
1715
  hslToHex: () => hslToHex,
1686
1716
  isValidHex: () => isValidHex,
1687
1717
  monokaiPalette: () => monokaiPalette,
1688
- mute: () => mute,
1689
1718
  nordPalette: () => nordPalette,
1690
1719
  oneDarkPalette: () => oneDarkPalette,
1691
1720
  registerPalette: () => registerPalette,
@@ -1710,7 +1739,6 @@ var init_palettes = __esm({
1710
1739
  init_tokyo_night();
1711
1740
  init_dracula();
1712
1741
  init_monokai();
1713
- init_mermaid_bridge();
1714
1742
  }
1715
1743
  });
1716
1744
 
@@ -3135,61 +3163,6 @@ var init_participant_inference = __esm({
3135
3163
  }
3136
3164
  });
3137
3165
 
3138
- // src/utils/arrows.ts
3139
- function parseArrow(line10) {
3140
- if (BIDI_SYNC_RE.test(line10) || BIDI_ASYNC_RE.test(line10)) {
3141
- return {
3142
- error: "Bidirectional arrows are no longer supported. Use two separate lines: 'A -msg-> B' and 'B -msg-> A'"
3143
- };
3144
- }
3145
- if (RETURN_SYNC_LABELED_RE.test(line10) || RETURN_ASYNC_LABELED_RE.test(line10)) {
3146
- const m = line10.match(RETURN_SYNC_LABELED_RE) ?? line10.match(RETURN_ASYNC_LABELED_RE);
3147
- const from = m[3];
3148
- const to = m[1];
3149
- const label = m[2].trim();
3150
- return {
3151
- error: `Left-pointing arrows are no longer supported. Write '${from} -${label}-> ${to}' instead`
3152
- };
3153
- }
3154
- const patterns = [
3155
- { re: SYNC_LABELED_RE, async: false },
3156
- { re: ASYNC_LABELED_RE, async: true }
3157
- ];
3158
- for (const { re, async: isAsync } of patterns) {
3159
- const m = line10.match(re);
3160
- if (!m) continue;
3161
- const label = m[2].trim();
3162
- if (!label) return null;
3163
- for (const arrow of ARROW_CHARS) {
3164
- if (label.includes(arrow)) {
3165
- return {
3166
- error: "Arrow characters (->, ~>) are not allowed inside labels"
3167
- };
3168
- }
3169
- }
3170
- return {
3171
- from: m[1],
3172
- to: m[3],
3173
- label,
3174
- async: isAsync
3175
- };
3176
- }
3177
- return null;
3178
- }
3179
- var SYNC_LABELED_RE, ASYNC_LABELED_RE, RETURN_SYNC_LABELED_RE, RETURN_ASYNC_LABELED_RE, BIDI_SYNC_RE, BIDI_ASYNC_RE, ARROW_CHARS;
3180
- var init_arrows = __esm({
3181
- "src/utils/arrows.ts"() {
3182
- "use strict";
3183
- SYNC_LABELED_RE = /^(.+?)\s*-(.+)->\s*(.+)$/;
3184
- ASYNC_LABELED_RE = /^(.+?)\s*~(.+)~>\s*(.+)$/;
3185
- RETURN_SYNC_LABELED_RE = /^(.+?)\s*<-(.+)-\s*(.+)$/;
3186
- RETURN_ASYNC_LABELED_RE = /^(.+?)\s*<~(.+)~\s*(.+)$/;
3187
- BIDI_SYNC_RE = /^(.+?)\s*<-(.+)->\s*(.+)$/;
3188
- BIDI_ASYNC_RE = /^(.+?)\s*<~(.+)~>\s*(.+)$/;
3189
- ARROW_CHARS = ["->", "~>"];
3190
- }
3191
- });
3192
-
3193
3166
  // src/sequence/parser.ts
3194
3167
  var parser_exports = {};
3195
3168
  __export(parser_exports, {
@@ -3742,8 +3715,11 @@ function parseSequenceDgmo(content) {
3742
3715
  }
3743
3716
  if (labeledArrow) {
3744
3717
  contentStarted = true;
3745
- const { from, to, label, async: isAsync } = labeledArrow;
3718
+ const { from, to, label: rawLabel, async: isAsync } = labeledArrow;
3746
3719
  lastMsgFrom = from;
3720
+ const labelResult = parseInArrowLabel(rawLabel, lineNumber);
3721
+ labelResult.diagnostics.forEach((d) => result.diagnostics.push(d));
3722
+ const label = labelResult.label ?? rawLabel;
3747
3723
  const msg = {
3748
3724
  from,
3749
3725
  to,
@@ -4143,42 +4119,52 @@ function parseNodeRef(text, palette) {
4143
4119
  }
4144
4120
  function splitArrows(line10) {
4145
4121
  const segments = [];
4146
- let lastIndex = 0;
4147
4122
  const arrowPositions = [];
4148
4123
  let searchFrom = 0;
4124
+ let scanFloor = 0;
4149
4125
  while (searchFrom < line10.length) {
4150
4126
  const idx = line10.indexOf("->", searchFrom);
4151
4127
  if (idx === -1) break;
4152
- let arrowStart = idx;
4128
+ let runStart = idx;
4129
+ while (runStart > scanFloor && line10[runStart - 1] === "-") runStart--;
4130
+ const arrowEnd = idx + 2;
4131
+ let arrowStart;
4153
4132
  let label;
4154
4133
  let color;
4155
- if (idx > 0 && line10[idx - 1] !== " " && line10[idx - 1] !== " ") {
4156
- let scanBack = idx - 1;
4157
- while (scanBack > 0 && line10[scanBack] !== "-") {
4158
- scanBack--;
4159
- }
4160
- if (line10[scanBack] === "-" && (scanBack === 0 || /\s/.test(line10[scanBack - 1]))) {
4161
- let arrowContent = line10.substring(scanBack + 1, idx);
4162
- if (arrowContent.endsWith("-"))
4163
- arrowContent = arrowContent.slice(0, -1);
4164
- const colorMatch = arrowContent.match(/\(([^)]+)\)\s*$/);
4165
- if (colorMatch) {
4166
- color = colorMatch[1].trim();
4167
- const labelPart = arrowContent.substring(0, colorMatch.index).trim();
4168
- if (labelPart) label = labelPart;
4169
- } else {
4170
- const labelPart = arrowContent.trim();
4171
- if (labelPart) label = labelPart;
4172
- }
4173
- arrowStart = scanBack;
4134
+ let openingStart = -1;
4135
+ for (let i = scanFloor; i < runStart; i++) {
4136
+ if (line10[i] !== "-") continue;
4137
+ const prevIsWsOrFloor = i === 0 || i === scanFloor || /\s/.test(line10[i - 1]);
4138
+ if (prevIsWsOrFloor) {
4139
+ openingStart = i;
4140
+ break;
4174
4141
  }
4175
4142
  }
4176
- arrowPositions.push({ start: arrowStart, end: idx + 2, label, color });
4177
- searchFrom = idx + 2;
4143
+ if (openingStart !== -1) {
4144
+ let openingEnd = openingStart;
4145
+ while (openingEnd < runStart && line10[openingEnd] === "-") openingEnd++;
4146
+ const arrowContent = line10.substring(openingEnd, runStart);
4147
+ const colorMatch = arrowContent.match(/\(([^)]+)\)\s*$/);
4148
+ if (colorMatch) {
4149
+ color = colorMatch[1].trim();
4150
+ const labelPart = arrowContent.substring(0, colorMatch.index).trim();
4151
+ if (labelPart) label = labelPart;
4152
+ } else {
4153
+ const labelPart = arrowContent.trim();
4154
+ if (labelPart) label = labelPart;
4155
+ }
4156
+ arrowStart = openingStart;
4157
+ } else {
4158
+ arrowStart = runStart;
4159
+ }
4160
+ arrowPositions.push({ start: arrowStart, end: arrowEnd, label, color });
4161
+ searchFrom = arrowEnd;
4162
+ scanFloor = arrowEnd;
4178
4163
  }
4179
4164
  if (arrowPositions.length === 0) {
4180
4165
  return [line10];
4181
4166
  }
4167
+ let lastIndex = 0;
4182
4168
  for (let i = 0; i < arrowPositions.length; i++) {
4183
4169
  const arrow = arrowPositions[i];
4184
4170
  const beforeText = line10.substring(lastIndex, arrow.start).trim();
@@ -4201,20 +4187,26 @@ function splitArrows(line10) {
4201
4187
  }
4202
4188
  function parseArrowToken(token, palette, lineNumber, diagnostics) {
4203
4189
  if (token === "->") return {};
4204
- const colorOnly = token.match(/^-\(([^)]+)\)->$/);
4205
- if (colorOnly) {
4206
- return {
4207
- color: resolveColorWithDiagnostic(
4208
- colorOnly[1].trim(),
4209
- lineNumber,
4210
- diagnostics,
4211
- palette
4212
- )
4213
- };
4190
+ const bareParen = token.match(/^-(\([A-Za-z]+\))->$/);
4191
+ if (bareParen) {
4192
+ const colorName = matchColorParens(bareParen[1]);
4193
+ if (colorName) {
4194
+ return {
4195
+ color: resolveColorWithDiagnostic(
4196
+ colorName,
4197
+ lineNumber,
4198
+ diagnostics,
4199
+ palette
4200
+ )
4201
+ };
4202
+ }
4214
4203
  }
4215
4204
  const m = token.match(/^-(.+?)(?:\(([^)]+)\))?->$/);
4216
4205
  if (m) {
4217
- const label = m[1]?.trim() || void 0;
4206
+ const rawLabel = m[1] ?? "";
4207
+ const labelResult = parseInArrowLabel(rawLabel, lineNumber);
4208
+ diagnostics.push(...labelResult.diagnostics);
4209
+ const label = labelResult.label;
4218
4210
  let color = m[2] ? resolveColorWithDiagnostic(
4219
4211
  m[2].trim(),
4220
4212
  lineNumber,
@@ -4442,6 +4434,7 @@ var init_flowchart_parser = __esm({
4442
4434
  "use strict";
4443
4435
  init_colors();
4444
4436
  init_diagnostics();
4437
+ init_arrows();
4445
4438
  init_parsing();
4446
4439
  NODE_ID_RE = /^([a-zA-Z_][\w-]*)[\s([</{]/;
4447
4440
  }
@@ -4457,35 +4450,45 @@ function splitArrows2(line10) {
4457
4450
  const segments = [];
4458
4451
  const arrowPositions = [];
4459
4452
  let searchFrom = 0;
4453
+ let scanFloor = 0;
4460
4454
  while (searchFrom < line10.length) {
4461
4455
  const idx = line10.indexOf("->", searchFrom);
4462
4456
  if (idx === -1) break;
4463
- let arrowStart = idx;
4457
+ let runStart = idx;
4458
+ while (runStart > scanFloor && line10[runStart - 1] === "-") runStart--;
4459
+ const arrowEnd = idx + 2;
4460
+ let arrowStart;
4464
4461
  let label;
4465
4462
  let color;
4466
- if (idx > 0 && line10[idx - 1] !== " " && line10[idx - 1] !== " ") {
4467
- let scanBack = idx - 1;
4468
- while (scanBack > 0 && line10[scanBack] !== "-") {
4469
- scanBack--;
4470
- }
4471
- if (line10[scanBack] === "-" && (scanBack === 0 || /\s/.test(line10[scanBack - 1]))) {
4472
- let arrowContent = line10.substring(scanBack + 1, idx);
4473
- if (arrowContent.endsWith("-"))
4474
- arrowContent = arrowContent.slice(0, -1);
4475
- const colorMatch = arrowContent.match(/\(([^)]+)\)\s*$/);
4476
- if (colorMatch) {
4477
- color = colorMatch[1].trim();
4478
- const labelPart = arrowContent.substring(0, colorMatch.index).trim();
4479
- if (labelPart) label = labelPart;
4480
- } else {
4481
- const labelPart = arrowContent.trim();
4482
- if (labelPart) label = labelPart;
4483
- }
4484
- arrowStart = scanBack;
4463
+ let openingStart = -1;
4464
+ for (let i = scanFloor; i < runStart; i++) {
4465
+ if (line10[i] !== "-") continue;
4466
+ const prevIsWsOrFloor = i === 0 || i === scanFloor || /\s/.test(line10[i - 1]);
4467
+ if (prevIsWsOrFloor) {
4468
+ openingStart = i;
4469
+ break;
4485
4470
  }
4486
4471
  }
4487
- arrowPositions.push({ start: arrowStart, end: idx + 2, label, color });
4488
- searchFrom = idx + 2;
4472
+ if (openingStart !== -1) {
4473
+ let openingEnd = openingStart;
4474
+ while (openingEnd < runStart && line10[openingEnd] === "-") openingEnd++;
4475
+ const arrowContent = line10.substring(openingEnd, runStart);
4476
+ const colorMatch = arrowContent.match(/\(([^)]+)\)\s*$/);
4477
+ if (colorMatch) {
4478
+ color = colorMatch[1].trim();
4479
+ const labelPart = arrowContent.substring(0, colorMatch.index).trim();
4480
+ if (labelPart) label = labelPart;
4481
+ } else {
4482
+ const labelPart = arrowContent.trim();
4483
+ if (labelPart) label = labelPart;
4484
+ }
4485
+ arrowStart = openingStart;
4486
+ } else {
4487
+ arrowStart = runStart;
4488
+ }
4489
+ arrowPositions.push({ start: arrowStart, end: arrowEnd, label, color });
4490
+ searchFrom = arrowEnd;
4491
+ scanFloor = arrowEnd;
4489
4492
  }
4490
4493
  if (arrowPositions.length === 0) return [line10];
4491
4494
  let lastIndex = 0;
@@ -4507,19 +4510,26 @@ function splitArrows2(line10) {
4507
4510
  }
4508
4511
  function parseArrowToken2(token, palette, lineNumber, diagnostics) {
4509
4512
  if (token === "->") return {};
4510
- const colorOnly = token.match(/^-\(([^)]+)\)->$/);
4511
- if (colorOnly)
4512
- return {
4513
- color: resolveColorWithDiagnostic(
4514
- colorOnly[1].trim(),
4515
- lineNumber,
4516
- diagnostics,
4517
- palette
4518
- )
4519
- };
4513
+ const bareParen = token.match(/^-(\([A-Za-z]+\))->$/);
4514
+ if (bareParen) {
4515
+ const colorName = matchColorParens(bareParen[1]);
4516
+ if (colorName) {
4517
+ return {
4518
+ color: resolveColorWithDiagnostic(
4519
+ colorName,
4520
+ lineNumber,
4521
+ diagnostics,
4522
+ palette
4523
+ )
4524
+ };
4525
+ }
4526
+ }
4520
4527
  const m = token.match(/^-(.+?)(?:\(([^)]+)\))?->$/);
4521
4528
  if (m) {
4522
- const label = m[1]?.trim() || void 0;
4529
+ const rawLabel = m[1] ?? "";
4530
+ const labelResult = parseInArrowLabel(rawLabel, lineNumber);
4531
+ diagnostics.push(...labelResult.diagnostics);
4532
+ const label = labelResult.label;
4523
4533
  const color = m[2] ? resolveColorWithDiagnostic(
4524
4534
  m[2].trim(),
4525
4535
  lineNumber,
@@ -4760,6 +4770,7 @@ var init_state_parser = __esm({
4760
4770
  "use strict";
4761
4771
  init_colors();
4762
4772
  init_diagnostics();
4773
+ init_arrows();
4763
4774
  init_parsing();
4764
4775
  PSEUDOSTATE_ID = "pseudostate:[*]";
4765
4776
  PSEUDOSTATE_LABEL = "[*]";
@@ -4916,6 +4927,11 @@ function parseClassDiagram(content, palette) {
4916
4927
  const targetName = indentRel[2];
4917
4928
  const label = indentRel[3]?.trim();
4918
4929
  getOrCreateClass(targetName, lineNumber);
4930
+ if (label) {
4931
+ result.diagnostics.push(
4932
+ ...validateLabelCharacters(label, lineNumber)
4933
+ );
4934
+ }
4919
4935
  result.relationships.push({
4920
4936
  source: currentClass.id,
4921
4937
  target: classId(targetName),
@@ -5090,6 +5106,7 @@ var init_parser2 = __esm({
5090
5106
  "use strict";
5091
5107
  init_colors();
5092
5108
  init_diagnostics();
5109
+ init_arrows();
5093
5110
  init_parsing();
5094
5111
  CLASS_DECL_RE = /^(?:(abstract|interface|enum)\s+)?([A-Z][A-Za-z0-9_]*)(?:\s+(extends|implements)\s+([A-Z][A-Za-z0-9_]*))?(?:\s+\[(abstract|interface|enum)\])?(?:\s+\(([^)]+)\))?\s*$/;
5095
5112
  INDENT_REL_ARROW_RE = /^(--\|>|\.\.\|>|\*--|o--|\.\.>|->)\s*([A-Z][A-Za-z0-9_]*)(?:\s+:?\s*(.+))?$/;
@@ -5129,12 +5146,18 @@ function parseRelationship(trimmed, lineNumber, pushError) {
5129
5146
  const fromCard = parseCardSide(sym[2]);
5130
5147
  const toCard = parseCardSide(sym[3]);
5131
5148
  if (fromCard && toCard) {
5149
+ const label = sym[5]?.trim();
5150
+ if (label) {
5151
+ validateLabelCharacters(label, lineNumber).forEach(
5152
+ (d) => pushError(d.line, d.message)
5153
+ );
5154
+ }
5132
5155
  return {
5133
5156
  source: sym[1],
5134
5157
  target: sym[4],
5135
5158
  from: fromCard,
5136
5159
  to: toCard,
5137
- label: sym[5]?.trim()
5160
+ label
5138
5161
  };
5139
5162
  }
5140
5163
  }
@@ -5297,11 +5320,17 @@ function parseERDiagram(content, palette) {
5297
5320
  if (fromCard && toCard) {
5298
5321
  const targetName = indentRel[4];
5299
5322
  getOrCreateTable(targetName, lineNumber);
5323
+ const rawLabel = indentRel[2]?.trim();
5324
+ if (rawLabel) {
5325
+ result.diagnostics.push(
5326
+ ...validateLabelCharacters(rawLabel, lineNumber)
5327
+ );
5328
+ }
5300
5329
  result.relationships.push({
5301
5330
  source: currentTable.id,
5302
5331
  target: tableId(targetName),
5303
5332
  cardinality: { from: fromCard, to: toCard },
5304
- ...indentRel[2]?.trim() && { label: indentRel[2].trim() },
5333
+ ...rawLabel && { label: rawLabel },
5305
5334
  lineNumber
5306
5335
  });
5307
5336
  }
@@ -5465,6 +5494,7 @@ var init_parser3 = __esm({
5465
5494
  "use strict";
5466
5495
  init_colors();
5467
5496
  init_diagnostics();
5497
+ init_arrows();
5468
5498
  init_parsing();
5469
5499
  init_tag_groups();
5470
5500
  TABLE_DECL_RE = /^([a-zA-Z_]\w*)(?:\s*\(([^)]+)\))?(?:\s*\|(.+))?$/;
@@ -7985,7 +8015,7 @@ function buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor,
7985
8015
  series
7986
8016
  };
7987
8017
  }
7988
- async function renderExtendedChartForExport(content, theme, palette, options) {
8018
+ async function renderExtendedChartForExport(content, theme, palette) {
7989
8019
  const isDark = theme === "dark";
7990
8020
  const { getPalette: getPalette2 } = await Promise.resolve().then(() => (init_palettes(), palettes_exports));
7991
8021
  const effectivePalette = palette ?? (isDark ? getPalette2("nord").dark : getPalette2("nord").light);
@@ -8056,22 +8086,20 @@ async function renderExtendedChartForExport(content, theme, palette, options) {
8056
8086
  `$1<g transform="translate(0,${legendY})">${legendSvgStr}</g>`
8057
8087
  );
8058
8088
  }
8059
- if (options?.branding !== false) {
8060
- const brandColor = theme === "transparent" ? "#888" : effectivePalette.textMuted;
8061
- result = injectBranding(result, brandColor);
8062
- }
8063
8089
  return result;
8064
8090
  } finally {
8065
8091
  chart.dispose();
8066
8092
  }
8067
8093
  }
8068
- var echarts, EMPHASIS_SELF, EMPHASIS_SERIES, BLUR_DIM, EMPHASIS_LINE, CHART_BASE, CHART_BORDER_WIDTH, VALID_EXTENDED_TYPES, KNOWN_EXTENDED_OPTIONS, ECHART_EXPORT_WIDTH, ECHART_EXPORT_HEIGHT, STANDARD_CHART_TYPES;
8094
+ var echarts, import_charts, import_components, import_renderers, EMPHASIS_SELF, EMPHASIS_SERIES, BLUR_DIM, EMPHASIS_LINE, CHART_BASE, CHART_BORDER_WIDTH, VALID_EXTENDED_TYPES, KNOWN_EXTENDED_OPTIONS, ECHART_EXPORT_WIDTH, ECHART_EXPORT_HEIGHT, STANDARD_CHART_TYPES;
8069
8095
  var init_echarts = __esm({
8070
8096
  "src/echarts.ts"() {
8071
8097
  "use strict";
8072
- echarts = __toESM(require("echarts"), 1);
8098
+ echarts = __toESM(require("echarts/core"), 1);
8099
+ import_charts = require("echarts/charts");
8100
+ import_components = require("echarts/components");
8101
+ import_renderers = require("echarts/renderers");
8073
8102
  init_fonts();
8074
- init_branding();
8075
8103
  init_legend_svg();
8076
8104
  init_label_layout();
8077
8105
  init_palettes();
@@ -8081,6 +8109,25 @@ var init_echarts = __esm({
8081
8109
  init_colors();
8082
8110
  init_parsing();
8083
8111
  init_chart();
8112
+ echarts.use([
8113
+ import_charts.BarChart,
8114
+ import_charts.LineChart,
8115
+ import_charts.PieChart,
8116
+ import_charts.ScatterChart,
8117
+ import_charts.RadarChart,
8118
+ import_charts.SankeyChart,
8119
+ import_charts.GraphChart,
8120
+ import_charts.HeatmapChart,
8121
+ import_charts.FunnelChart,
8122
+ import_components.GridComponent,
8123
+ import_components.TitleComponent,
8124
+ import_components.TooltipComponent,
8125
+ import_components.LegendComponent,
8126
+ import_components.RadarComponent,
8127
+ import_components.VisualMapComponent,
8128
+ import_components.GraphicComponent,
8129
+ import_renderers.SVGRenderer
8130
+ ]);
8084
8131
  EMPHASIS_SELF = {
8085
8132
  focus: "self",
8086
8133
  blurScope: "global",
@@ -9043,13 +9090,10 @@ function parseC4(content, palette) {
9043
9090
  labeledHandled = true;
9044
9091
  break;
9045
9092
  }
9046
- let label = rawLabel;
9093
+ const labelResult = parseInArrowLabel(rawLabel, lineNumber);
9094
+ labelResult.diagnostics.forEach((d) => result.diagnostics.push(d));
9095
+ const label = labelResult.label;
9047
9096
  let technology;
9048
- const techMatch = rawLabel.match(/\[([^\]]+)\]\s*$/);
9049
- if (techMatch) {
9050
- label = rawLabel.substring(0, techMatch.index).trim() || void 0;
9051
- technology = techMatch[1].trim();
9052
- }
9053
9097
  let target = targetBody;
9054
9098
  const pipeIdx = targetBody.indexOf("|");
9055
9099
  if (pipeIdx !== -1) {
@@ -9385,6 +9429,7 @@ var init_parser6 = __esm({
9385
9429
  "src/c4/parser.ts"() {
9386
9430
  "use strict";
9387
9431
  init_diagnostics();
9432
+ init_arrows();
9388
9433
  init_tag_groups();
9389
9434
  init_participant_inference();
9390
9435
  init_parsing();
@@ -10185,7 +10230,10 @@ function parseInfra(content) {
10185
10230
  }
10186
10231
  const asyncConnMatch = trimmed.match(ASYNC_CONNECTION_RE);
10187
10232
  if (asyncConnMatch) {
10188
- const label = asyncConnMatch[1]?.trim() || "";
10233
+ const rawLabel = asyncConnMatch[1] ?? "";
10234
+ const labelResult = parseInArrowLabel(rawLabel, lineNumber);
10235
+ result.diagnostics.push(...labelResult.diagnostics);
10236
+ const label = labelResult.label ?? "";
10189
10237
  const targetRaw = asyncConnMatch[2].trim();
10190
10238
  const pipeMeta = extractPipeMetadata(targetRaw);
10191
10239
  const targetName = pipeMeta.clean || targetRaw;
@@ -10245,7 +10293,10 @@ function parseInfra(content) {
10245
10293
  }
10246
10294
  const connMatch = trimmed.match(CONNECTION_RE);
10247
10295
  if (connMatch) {
10248
- const label = connMatch[1]?.trim() || "";
10296
+ const rawLabel = connMatch[1] ?? "";
10297
+ const labelResult = parseInArrowLabel(rawLabel, lineNumber);
10298
+ result.diagnostics.push(...labelResult.diagnostics);
10299
+ const label = labelResult.label ?? "";
10249
10300
  const targetRaw = connMatch[2].trim();
10250
10301
  const pipeMeta = extractPipeMetadata(targetRaw);
10251
10302
  const targetName = pipeMeta.clean || targetRaw;
@@ -10444,6 +10495,7 @@ var init_parser8 = __esm({
10444
10495
  "use strict";
10445
10496
  init_diagnostics();
10446
10497
  init_colors();
10498
+ init_arrows();
10447
10499
  init_parsing();
10448
10500
  init_tag_groups();
10449
10501
  init_types();
@@ -11975,7 +12027,9 @@ function parseEdgeLine(trimmed, lineNum, aliasMap, diagnostics) {
11975
12027
  const biLabeledMatch = trimmed.match(/^(.+?)\s*<-(.+)->\s*(.+)$/);
11976
12028
  if (biLabeledMatch) {
11977
12029
  const source2 = resolveEndpoint(biLabeledMatch[1].trim());
11978
- const label = biLabeledMatch[2].trim();
12030
+ const labelResult = parseInArrowLabel(biLabeledMatch[2], lineNum);
12031
+ diagnostics.push(...labelResult.diagnostics);
12032
+ const label = labelResult.label;
11979
12033
  let rest2 = biLabeledMatch[3].trim();
11980
12034
  let metadata2 = {};
11981
12035
  const pipeIdx2 = rest2.indexOf("|");
@@ -11996,7 +12050,7 @@ function parseEdgeLine(trimmed, lineNum, aliasMap, diagnostics) {
11996
12050
  return {
11997
12051
  source: source2,
11998
12052
  target: resolveEndpoint(rest2),
11999
- label: label || void 0,
12053
+ label,
12000
12054
  bidirectional: true,
12001
12055
  lineNumber: lineNum,
12002
12056
  metadata: metadata2
@@ -12033,7 +12087,9 @@ function parseEdgeLine(trimmed, lineNum, aliasMap, diagnostics) {
12033
12087
  const labeledMatch = trimmed.match(/^(.+?)\s+-(.+)->\s*(.+)$/);
12034
12088
  if (labeledMatch) {
12035
12089
  const source2 = resolveEndpoint(labeledMatch[1].trim());
12036
- const label = labeledMatch[2].trim();
12090
+ const labelResult = parseInArrowLabel(labeledMatch[2], lineNum);
12091
+ diagnostics.push(...labelResult.diagnostics);
12092
+ const label = labelResult.label;
12037
12093
  let rest2 = labeledMatch[3].trim();
12038
12094
  if (label) {
12039
12095
  let metadata2 = {};
@@ -12096,6 +12152,7 @@ var init_parser10 = __esm({
12096
12152
  "src/boxes-and-lines/parser.ts"() {
12097
12153
  "use strict";
12098
12154
  init_diagnostics();
12155
+ init_arrows();
12099
12156
  init_tag_groups();
12100
12157
  init_parsing();
12101
12158
  MAX_GROUP_DEPTH = 1;
@@ -12171,19 +12228,78 @@ function getAllChartTypes() {
12171
12228
  function parseDgmo(content) {
12172
12229
  const chartType = parseDgmoChartType(content);
12173
12230
  if (!chartType) {
12231
+ const colonDiag = detectColonChartType(content);
12232
+ if (colonDiag) {
12233
+ const fallback = parseVisualization(content).diagnostics;
12234
+ return { diagnostics: [colonDiag, ...fallback] };
12235
+ }
12174
12236
  return { diagnostics: parseVisualization(content).diagnostics };
12175
12237
  }
12176
12238
  const directParser = PARSE_DISPATCH.get(chartType);
12177
- if (directParser) return { diagnostics: directParser(content).diagnostics };
12239
+ if (directParser) {
12240
+ const result2 = directParser(content);
12241
+ return {
12242
+ diagnostics: [...result2.diagnostics, ...detectEmptyContent(content)]
12243
+ };
12244
+ }
12178
12245
  if (STANDARD_CHART_TYPES2.has(chartType)) {
12179
- return { diagnostics: parseChart(content).diagnostics };
12246
+ const result2 = parseChart(content);
12247
+ return {
12248
+ diagnostics: [...result2.diagnostics, ...detectEmptyContent(content)]
12249
+ };
12180
12250
  }
12181
12251
  if (ECHART_TYPES.has(chartType)) {
12182
- return { diagnostics: parseExtendedChart(content).diagnostics };
12252
+ const result2 = parseExtendedChart(content);
12253
+ return {
12254
+ diagnostics: [...result2.diagnostics, ...detectEmptyContent(content)]
12255
+ };
12183
12256
  }
12184
- return { diagnostics: parseVisualization(content).diagnostics };
12257
+ const result = parseVisualization(content);
12258
+ return {
12259
+ diagnostics: [...result.diagnostics, ...detectEmptyContent(content)]
12260
+ };
12185
12261
  }
12186
- var GANTT_DURATION_RE, GANTT_DATE_RE, C4_TYPE_RE, DATA_CHART_TYPES, VISUALIZATION_TYPES, DIAGRAM_TYPES, EXTENDED_CHART_TYPES, STANDARD_CHART_TYPES2, ECHART_TYPES, PARSE_DISPATCH;
12262
+ function detectColonChartType(content) {
12263
+ const lines = content.split("\n");
12264
+ for (let i = 0; i < lines.length; i++) {
12265
+ const trimmed = lines[i].trim();
12266
+ if (!trimmed || trimmed.startsWith("#") || trimmed.startsWith("//"))
12267
+ continue;
12268
+ const match = trimmed.match(/^(\w[\w-]*)\s*:\s*(.*)$/);
12269
+ if (!match) return null;
12270
+ const word = match[1].toLowerCase();
12271
+ const rest = match[2].trim();
12272
+ if (ALL_KNOWN_TYPES.has(word)) {
12273
+ const example = rest ? `${word} ${rest}` : word;
12274
+ return makeDgmoError(
12275
+ i + 1,
12276
+ `Remove the colon \u2014 use '${example}' instead of '${trimmed}'. DGMO chart types don't use colons.`
12277
+ );
12278
+ }
12279
+ const hint = suggest(word, [...ALL_KNOWN_TYPES]);
12280
+ if (hint) {
12281
+ return makeDgmoError(
12282
+ i + 1,
12283
+ `Unknown chart type: ${word}. ${hint} Also, DGMO chart types don't use colons.`
12284
+ );
12285
+ }
12286
+ return null;
12287
+ }
12288
+ return null;
12289
+ }
12290
+ function detectEmptyContent(content) {
12291
+ const lines = content.split("\n");
12292
+ const nonEmpty = lines.filter(
12293
+ (l) => l.trim() && !l.trim().startsWith("#") && !l.trim().startsWith("//")
12294
+ );
12295
+ if (nonEmpty.length <= 1) {
12296
+ return [
12297
+ makeDgmoError(1, "No content after chart type declaration.", "warning")
12298
+ ];
12299
+ }
12300
+ return [];
12301
+ }
12302
+ var GANTT_DURATION_RE, GANTT_DATE_RE, C4_TYPE_RE, DATA_CHART_TYPES, VISUALIZATION_TYPES, DIAGRAM_TYPES, EXTENDED_CHART_TYPES, STANDARD_CHART_TYPES2, ECHART_TYPES, PARSE_DISPATCH, ALL_KNOWN_TYPES;
12187
12303
  var init_dgmo_router = __esm({
12188
12304
  "src/dgmo-router.ts"() {
12189
12305
  "use strict";
@@ -12203,6 +12319,7 @@ var init_dgmo_router = __esm({
12203
12319
  init_parser9();
12204
12320
  init_parser10();
12205
12321
  init_parsing();
12322
+ init_diagnostics();
12206
12323
  GANTT_DURATION_RE = /^\d+(?:\.\d+)?(?:min|bd|d|w|m|q|y|h)(?:\?)?\s+/;
12207
12324
  GANTT_DATE_RE = /^\d{4}-\d{2}-\d{2}(?:\s\d{2}:\d{2})?\s+/;
12208
12325
  C4_TYPE_RE = /\bis\s+an?\s+(person|system|container|component)\b/i;
@@ -12286,6 +12403,11 @@ var init_dgmo_router = __esm({
12286
12403
  ["gantt", (c) => parseGantt(c)],
12287
12404
  ["boxes-and-lines", (c) => parseBoxesAndLines(c)]
12288
12405
  ]);
12406
+ ALL_KNOWN_TYPES = /* @__PURE__ */ new Set([
12407
+ ...DATA_CHART_TYPES,
12408
+ ...VISUALIZATION_TYPES,
12409
+ ...DIAGRAM_TYPES
12410
+ ]);
12289
12411
  }
12290
12412
  });
12291
12413
 
@@ -14458,7 +14580,6 @@ async function renderSitemapForExport(content, theme, palette) {
14458
14580
  const { parseSitemap: parseSitemap2 } = await Promise.resolve().then(() => (init_parser7(), parser_exports7));
14459
14581
  const { layoutSitemap: layoutSitemap2 } = await Promise.resolve().then(() => (init_layout2(), layout_exports2));
14460
14582
  const { getPalette: getPalette2 } = await Promise.resolve().then(() => (init_palettes(), palettes_exports));
14461
- const { injectBranding: injectBranding2 } = await Promise.resolve().then(() => (init_branding(), branding_exports));
14462
14583
  const isDark = theme === "dark";
14463
14584
  const effectivePalette = palette ?? (isDark ? getPalette2("nord").dark : getPalette2("nord").light);
14464
14585
  const parsed = parseSitemap2(content, effectivePalette);
@@ -14500,8 +14621,7 @@ async function renderSitemapForExport(content, theme, palette) {
14500
14621
  svgEl.style.fontFamily = FONT_FAMILY;
14501
14622
  const svgHtml = svgEl.outerHTML;
14502
14623
  document.body.removeChild(container);
14503
- const brandColor = theme === "transparent" ? "#888" : effectivePalette.textMuted;
14504
- return injectBranding2(svgHtml, brandColor);
14624
+ return svgHtml;
14505
14625
  }
14506
14626
  var d3Selection2, d3Shape, DIAGRAM_PADDING2, MAX_SCALE2, TITLE_HEIGHT2, LABEL_FONT_SIZE2, META_FONT_SIZE2, META_LINE_HEIGHT4, HEADER_HEIGHT4, SEPARATOR_GAP4, EDGE_STROKE_WIDTH2, NODE_STROKE_WIDTH2, CARD_RADIUS2, CONTAINER_RADIUS2, CONTAINER_LABEL_FONT_SIZE2, CONTAINER_META_FONT_SIZE2, CONTAINER_META_LINE_HEIGHT4, CONTAINER_HEADER_HEIGHT2, ARROWHEAD_W, ARROWHEAD_H, EDGE_LABEL_FONT_SIZE, COLLAPSE_BAR_HEIGHT2, LEGEND_FIXED_GAP2, lineGenerator, lineGeneratorLinear;
14507
14627
  var init_renderer2 = __esm({
@@ -14707,7 +14827,6 @@ var init_mutations = __esm({
14707
14827
  // src/kanban/renderer.ts
14708
14828
  var renderer_exports3 = {};
14709
14829
  __export(renderer_exports3, {
14710
- bucketCardsBySwimlane: () => bucketCardsBySwimlane,
14711
14830
  renderKanban: () => renderKanban,
14712
14831
  renderKanbanForExport: () => renderKanbanForExport
14713
14832
  });
@@ -23718,8 +23837,8 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
23718
23837
  });
23719
23838
  }
23720
23839
  drawLegend();
23721
- const startTime = dateToFractionalYear(resolved.startDate);
23722
- const endTime = dateToFractionalYear(resolved.endDate);
23840
+ const startTime = dateToFractionalYear2(resolved.startDate);
23841
+ const endTime = dateToFractionalYear2(resolved.endDate);
23723
23842
  const domainPad = Math.max((endTime - startTime) * 0.02, 0.01);
23724
23843
  const domainMin = startTime - domainPad;
23725
23844
  const domainMax = endTime + domainPad;
@@ -23750,7 +23869,7 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
23750
23869
  } else {
23751
23870
  todayDate = /* @__PURE__ */ new Date(resolved.options.todayMarker + "T00:00:00");
23752
23871
  }
23753
- todayX = xScale(dateToFractionalYear(todayDate));
23872
+ todayX = xScale(dateToFractionalYear2(todayDate));
23754
23873
  if (todayX >= 0 && todayX <= innerWidth) {
23755
23874
  const todayLine = g.append("line").attr("class", "gantt-today").attr("x1", todayX).attr("y1", 0).attr("x2", todayX).attr("y2", innerHeight + 10).attr("stroke", todayColor).attr("stroke-width", 2).attr("stroke-dasharray", "6 4").attr("opacity", 0.7).attr("pointer-events", "none");
23756
23875
  if (todayMarkerLineNum)
@@ -23792,8 +23911,8 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
23792
23911
  let lx2 = innerWidth;
23793
23912
  let laneBarWidth = innerWidth;
23794
23913
  if (row.laneStartDate && row.laneEndDate) {
23795
- lx1 = xScale(dateToFractionalYear(row.laneStartDate));
23796
- lx2 = xScale(dateToFractionalYear(row.laneEndDate));
23914
+ lx1 = xScale(dateToFractionalYear2(row.laneStartDate));
23915
+ lx2 = xScale(dateToFractionalYear2(row.laneEndDate));
23797
23916
  laneBarWidth = Math.max(lx2 - lx1, 2);
23798
23917
  }
23799
23918
  lanePositions.set(row.laneName, {
@@ -23899,8 +24018,8 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
23899
24018
  labelG.append("text").attr("x", labelX).attr("y", marginTop + yOffset + BAR_H / 2).attr("dy", "0.35em").attr("text-anchor", "start").attr("font-size", "11px").attr("font-weight", "bold").attr("fill", palette.text).text(
23900
24019
  toggleIcon + " " + group.name + (group.progress !== null ? ` ${Math.round(group.progress)}%` : "")
23901
24020
  );
23902
- const gStart = dateToFractionalYear(group.startDate);
23903
- const gEnd = dateToFractionalYear(group.endDate);
24021
+ const gStart = dateToFractionalYear2(group.startDate);
24022
+ const gEnd = dateToFractionalYear2(group.endDate);
23904
24023
  const gx1 = xScale(gStart);
23905
24024
  const gx2 = xScale(gEnd);
23906
24025
  if (gx2 > gx1) {
@@ -24014,7 +24133,7 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
24014
24133
  taskLabel.attr("data-critical-path", "true");
24015
24134
  }
24016
24135
  if (rt.isMilestone) {
24017
- const mx = xScale(dateToFractionalYear(rt.startDate));
24136
+ const mx = xScale(dateToFractionalYear2(rt.startDate));
24018
24137
  const my = yOffset + BAR_H / 2;
24019
24138
  g.append("polygon").attr("class", "gantt-milestone").attr("points", diamondPoints(mx, my, MILESTONE_SIZE)).attr("fill", barColor).attr("stroke", barColor).attr("stroke-width", 1.5).attr("data-line-number", String(task.lineNumber)).attr("data-task-name", task.label).attr("data-task-id", task.id).attr("data-group", topGroup).style("cursor", onClickItem ? "pointer" : "default").on("click", () => {
24020
24139
  if (onClickItem) onClickItem(task.lineNumber);
@@ -24036,8 +24155,8 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
24036
24155
  });
24037
24156
  taskPositions.set(task.id, { x1: mx, x2: mx, y: my });
24038
24157
  } else {
24039
- const tStart = dateToFractionalYear(rt.startDate);
24040
- const tEnd = dateToFractionalYear(rt.endDate);
24158
+ const tStart = dateToFractionalYear2(rt.startDate);
24159
+ const tEnd = dateToFractionalYear2(rt.endDate);
24041
24160
  const x1 = xScale(tStart);
24042
24161
  const x2 = xScale(tEnd);
24043
24162
  const barWidth = Math.max(x2 - x1, 2);
@@ -24272,14 +24391,14 @@ function renderHolidayBands(g, svg, resolved, xScale, innerHeight, palette, isDa
24272
24391
  }
24273
24392
  }
24274
24393
  function drawBand(g, xScale, start, end, height, palette, _isDark, className, opacity) {
24275
- const x1 = xScale(dateToFractionalYear(start));
24276
- const x2 = xScale(dateToFractionalYear(end));
24394
+ const x1 = xScale(dateToFractionalYear2(start));
24395
+ const x2 = xScale(dateToFractionalYear2(end));
24277
24396
  if (x2 <= x1) return;
24278
24397
  g.append("rect").attr("class", className).attr("x", x1).attr("y", 0).attr("width", x2 - x1).attr("height", height).attr("fill", palette.text).attr("opacity", opacity).attr("pointer-events", "none");
24279
24398
  }
24280
24399
  function drawHolidayBand(g, svg, xScale, start, end, height, palette, _isDark, label, lineNumber, headerY, chartLeftMargin, onClickItem) {
24281
- const x1 = xScale(dateToFractionalYear(start));
24282
- const x2 = xScale(dateToFractionalYear(end));
24400
+ const x1 = xScale(dateToFractionalYear2(start));
24401
+ const x2 = xScale(dateToFractionalYear2(end));
24283
24402
  if (x2 <= x1) return;
24284
24403
  const bandW = Math.max(x2 - x1, 4);
24285
24404
  const baseOpacity = 0.08;
@@ -24801,8 +24920,8 @@ function renderSprintBands(g, svg, resolved, xScale, innerHeight, palette) {
24801
24920
  const chartMinX = 0;
24802
24921
  for (let i = 0; i < resolved.sprints.length; i++) {
24803
24922
  const sprint = resolved.sprints[i];
24804
- const rawSx = xScale(dateToFractionalYear(sprint.startDate));
24805
- const rawEx = xScale(dateToFractionalYear(sprint.endDate));
24923
+ const rawSx = xScale(dateToFractionalYear2(sprint.startDate));
24924
+ const rawEx = xScale(dateToFractionalYear2(sprint.endDate));
24806
24925
  if (rawEx <= rawSx) continue;
24807
24926
  const sx = Math.max(rawSx, chartMinX);
24808
24927
  const ex = rawEx;
@@ -24924,7 +25043,7 @@ function renderSprintBands(g, svg, resolved, xScale, innerHeight, palette) {
24924
25043
  });
24925
25044
  }
24926
25045
  const lastSprint = resolved.sprints[resolved.sprints.length - 1];
24927
- const lastEx = xScale(dateToFractionalYear(lastSprint.endDate));
25046
+ const lastEx = xScale(dateToFractionalYear2(lastSprint.endDate));
24928
25047
  g.append("line").attr("class", "gantt-sprint-boundary").attr("x1", lastEx).attr("y1", -6).attr("x2", lastEx).attr("y2", innerHeight).attr("stroke", bandColor).attr("stroke-width", 1).attr("stroke-dasharray", "3 3").attr("opacity", SPRINT_BOUNDARY_OPACITY);
24929
25048
  }
24930
25049
  function parseDateStringToDate(s) {
@@ -24935,7 +25054,7 @@ function parseDateStringToDate(s) {
24935
25054
  return new Date(year, month, day);
24936
25055
  }
24937
25056
  function parseDateToFractionalYear(s) {
24938
- return dateToFractionalYear(parseDateStringToDate(s));
25057
+ return dateToFractionalYear2(parseDateStringToDate(s));
24939
25058
  }
24940
25059
  function highlightDeps(g, svg, taskId, resolved) {
24941
25060
  const related = /* @__PURE__ */ new Set([taskId]);
@@ -25302,7 +25421,7 @@ function durationWeightedProgress(tasks) {
25302
25421
  }
25303
25422
  return hasProgress && totalDuration > 0 ? totalProgress / totalDuration : null;
25304
25423
  }
25305
- function dateToFractionalYear(d) {
25424
+ function dateToFractionalYear2(d) {
25306
25425
  const y = d.getFullYear();
25307
25426
  const startOfYear = new Date(y, 0, 1);
25308
25427
  const endOfYear = new Date(y + 1, 0, 1);
@@ -25314,7 +25433,7 @@ function diamondPoints(cx, cy, size) {
25314
25433
  return `${cx},${cy - half} ${cx + half},${cy} ${cx},${cy + half} ${cx - half},${cy}`;
25315
25434
  }
25316
25435
  function formatGanttDate(d) {
25317
- const base = `${MONTH_ABBR[d.getMonth()]} ${d.getDate()}, ${d.getFullYear()}`;
25436
+ const base = `${MONTH_ABBR2[d.getMonth()]} ${d.getDate()}, ${d.getFullYear()}`;
25318
25437
  if (d.getHours() === 0 && d.getMinutes() === 0) return base;
25319
25438
  const hh = String(d.getHours()).padStart(2, "0");
25320
25439
  const mm = String(d.getMinutes()).padStart(2, "0");
@@ -25325,7 +25444,7 @@ function showGanttDateIndicators(g, xScale, startDate, endDate, innerHeight, col
25325
25444
  g.selectAll(".gantt-today").attr("opacity", 0.05);
25326
25445
  const hg = g.append("g").attr("class", "gantt-hover-date").attr("pointer-events", "none");
25327
25446
  const tickLen = 6;
25328
- const startPos = xScale(dateToFractionalYear(startDate));
25447
+ const startPos = xScale(dateToFractionalYear2(startDate));
25329
25448
  const startLabel = formatGanttDate(startDate);
25330
25449
  if (!options?.skipStartLine) {
25331
25450
  hg.append("line").attr("class", "gantt-hover-date").attr("x1", startPos).attr("y1", -tickLen).attr("x2", startPos).attr("y2", innerHeight).attr("stroke", color).attr("stroke-width", 1.5).attr("stroke-dasharray", "4 4").attr("opacity", 0.6);
@@ -25333,7 +25452,7 @@ function showGanttDateIndicators(g, xScale, startDate, endDate, innerHeight, col
25333
25452
  hg.append("text").attr("class", "gantt-hover-date").attr("x", startPos).attr("y", -tickLen - 4).attr("text-anchor", "middle").attr("fill", color).attr("font-size", "10px").attr("font-weight", "600").text(startLabel);
25334
25453
  hg.append("text").attr("class", "gantt-hover-date").attr("x", startPos).attr("y", innerHeight + tickLen + 12).attr("text-anchor", "middle").attr("fill", color).attr("font-size", "10px").attr("font-weight", "600").text(startLabel);
25335
25454
  if (endDate && endDate.getTime() !== startDate.getTime()) {
25336
- const endPos = xScale(dateToFractionalYear(endDate));
25455
+ const endPos = xScale(dateToFractionalYear2(endDate));
25337
25456
  const endLabel = formatGanttDate(endDate);
25338
25457
  const minLabelGap = 90;
25339
25458
  const gap = endPos - startPos;
@@ -25403,7 +25522,7 @@ function renderTimeScaleHorizontal(g, scale, innerWidth, innerHeight, textColor)
25403
25522
  g.append("text").attr("class", "gantt-scale-tick").attr("x", tick.pos).attr("y", innerHeight + tickLen + 12).attr("text-anchor", "middle").attr("font-size", "10px").attr("fill", textColor).attr("opacity", opacity).text(tick.label);
25404
25523
  }
25405
25524
  }
25406
- var d3Scale, d3Selection10, BAR_H, ROW_GAP, GROUP_GAP2, MILESTONE_SIZE, MIN_LEFT_MARGIN, BOTTOM_MARGIN, RIGHT_MARGIN, CHAR_W2, LABEL_PAD, LABEL_GAP, BAND_ACCENT_W, BAND_RADIUS, bandClipCounter, JS_DAY_TO_WEEKDAY2, ERA_COLORS, SPRINT_BAND_OPACITY, SPRINT_HOVER_OPACITY, SPRINT_BOUNDARY_OPACITY, FADE_OPACITY, MONTH_ABBR;
25525
+ var d3Scale, d3Selection10, BAR_H, ROW_GAP, GROUP_GAP2, MILESTONE_SIZE, MIN_LEFT_MARGIN, BOTTOM_MARGIN, RIGHT_MARGIN, CHAR_W2, LABEL_PAD, LABEL_GAP, BAND_ACCENT_W, BAND_RADIUS, bandClipCounter, JS_DAY_TO_WEEKDAY2, ERA_COLORS, SPRINT_BAND_OPACITY, SPRINT_HOVER_OPACITY, SPRINT_BOUNDARY_OPACITY, FADE_OPACITY, MONTH_ABBR2;
25407
25526
  var init_renderer9 = __esm({
25408
25527
  "src/gantt/renderer.ts"() {
25409
25528
  "use strict";
@@ -25413,7 +25532,7 @@ var init_renderer9 = __esm({
25413
25532
  init_palettes();
25414
25533
  init_color_utils();
25415
25534
  init_tag_groups();
25416
- init_d3();
25535
+ init_time_ticks();
25417
25536
  init_legend_constants();
25418
25537
  init_legend_d3();
25419
25538
  init_legend_layout();
@@ -25445,7 +25564,7 @@ var init_renderer9 = __esm({
25445
25564
  SPRINT_HOVER_OPACITY = 0.12;
25446
25565
  SPRINT_BOUNDARY_OPACITY = 0.3;
25447
25566
  FADE_OPACITY = 0.1;
25448
- MONTH_ABBR = [
25567
+ MONTH_ABBR2 = [
25449
25568
  "Jan",
25450
25569
  "Feb",
25451
25570
  "Mar",
@@ -27089,7 +27208,7 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
27089
27208
  if (tagKey && msgTagValue) {
27090
27209
  labelEl.attr(`data-tag-${tagKey}`, msgTagValue.toLowerCase());
27091
27210
  }
27092
- renderInlineText(labelEl, step.label, palette);
27211
+ labelEl.text(step.label);
27093
27212
  }
27094
27213
  } else {
27095
27214
  const goingRight = fromX < toX;
@@ -27116,7 +27235,7 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
27116
27235
  if (tagKey && msgTagValue) {
27117
27236
  labelEl.attr(`data-tag-${tagKey}`, msgTagValue.toLowerCase());
27118
27237
  }
27119
- renderInlineText(labelEl, step.label, palette);
27238
+ labelEl.text(step.label);
27120
27239
  }
27121
27240
  }
27122
27241
  } else {
@@ -27147,7 +27266,7 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
27147
27266
  if (tagKey && msgTagValue) {
27148
27267
  labelEl.attr(`data-tag-${tagKey}`, msgTagValue.toLowerCase());
27149
27268
  }
27150
- renderInlineText(labelEl, step.label, palette);
27269
+ labelEl.text(step.label);
27151
27270
  }
27152
27271
  }
27153
27272
  });
@@ -27420,23 +27539,6 @@ function parseTimelineDate(s) {
27420
27539
  const day = parts.length >= 3 ? parts[2] : 1;
27421
27540
  return year + (month - 1) / 12 + (day - 1) / 365 + hour / 8760 + minute / 525600;
27422
27541
  }
27423
- function fractionalYearToDate(frac) {
27424
- const year = Math.floor(frac);
27425
- const remainder = frac - year;
27426
- const monthFrac = remainder * 12;
27427
- const month = Math.floor(monthFrac);
27428
- const monthRemainder = remainder - month / 12;
27429
- const dayFrac = monthRemainder * 365;
27430
- const day = Math.floor(dayFrac) + 1;
27431
- const dayRemainder = dayFrac - Math.floor(dayFrac);
27432
- const hourFrac = dayRemainder * 24;
27433
- const hour = Math.floor(hourFrac);
27434
- const minute = Math.round((hourFrac - hour) * 60);
27435
- return new Date(year, month, day, hour, minute);
27436
- }
27437
- function dateToFractionalYear2(d) {
27438
- return d.getFullYear() + d.getMonth() / 12 + (d.getDate() - 1) / 365 + d.getHours() / 8760 + d.getMinutes() / 525600;
27439
- }
27440
27542
  function addDurationToDate(startDate, amount, unit) {
27441
27543
  const spaceIdx = startDate.indexOf(" ");
27442
27544
  let datePart = startDate;
@@ -28991,7 +29093,7 @@ function formatDateLabel(dateStr) {
28991
29093
  const parts = datePart.split("-");
28992
29094
  const year = parts[0];
28993
29095
  if (parts.length === 1) return year + timeSuffix;
28994
- const month = MONTH_ABBR2[parseInt(parts[1], 10) - 1];
29096
+ const month = MONTH_ABBR[parseInt(parts[1], 10) - 1];
28995
29097
  if (parts.length === 2) return `${month} ${year}${timeSuffix}`;
28996
29098
  const day = parseInt(parts[2], 10);
28997
29099
  return `${month} ${day}, ${year}${timeSuffix}`;
@@ -29008,123 +29110,6 @@ function formatBoundaryLabel(dateStr, otherDateStr) {
29008
29110
  }
29009
29111
  return formatDateLabel(dateStr);
29010
29112
  }
29011
- function computeTimeTicks(domainMin, domainMax, scale, boundaryStart, boundaryEnd, boundaryStartLabel, boundaryEndLabel) {
29012
- const minYear = Math.floor(domainMin);
29013
- const maxYear = Math.floor(domainMax);
29014
- const span = domainMax - domainMin;
29015
- let ticks = [];
29016
- const firstYear = Math.ceil(domainMin);
29017
- const lastYear = Math.floor(domainMax);
29018
- if (lastYear >= firstYear + 1) {
29019
- const yearSpan = lastYear - firstYear;
29020
- let step = 1;
29021
- if (yearSpan > 80) step = 20;
29022
- else if (yearSpan > 40) step = 10;
29023
- else if (yearSpan > 20) step = 5;
29024
- else if (yearSpan > 10) step = 2;
29025
- const alignedFirst = Math.ceil(firstYear / step) * step;
29026
- for (let y = alignedFirst; y <= lastYear; y += step) {
29027
- ticks.push({ pos: scale(y), label: String(y) });
29028
- }
29029
- } else if (span > 0.25) {
29030
- const crossesYear = maxYear > minYear;
29031
- for (let y = minYear; y <= maxYear + 1; y++) {
29032
- for (let m = 1; m <= 12; m++) {
29033
- const val = y + (m - 1) / 12;
29034
- if (val > domainMax) break;
29035
- if (val >= domainMin) {
29036
- ticks.push({
29037
- pos: scale(val),
29038
- label: crossesYear ? `${MONTH_ABBR2[m - 1]} '${String(y).slice(-2)}` : MONTH_ABBR2[m - 1]
29039
- });
29040
- }
29041
- }
29042
- }
29043
- } else if (span <= 685e-6) {
29044
- let stepMin = 5;
29045
- const spanHours = span * 8760;
29046
- if (spanHours > 3) stepMin = 30;
29047
- else if (spanHours > 1) stepMin = 15;
29048
- else if (spanHours > 0.5) stepMin = 10;
29049
- const startDate = fractionalYearToDate(domainMin);
29050
- startDate.setMinutes(
29051
- Math.floor(startDate.getMinutes() / stepMin) * stepMin,
29052
- 0,
29053
- 0
29054
- );
29055
- while (true) {
29056
- const val = dateToFractionalYear2(startDate);
29057
- if (val > domainMax) break;
29058
- if (val >= domainMin) {
29059
- const hh = String(startDate.getHours()).padStart(2, "0");
29060
- const mm = String(startDate.getMinutes()).padStart(2, "0");
29061
- ticks.push({ pos: scale(val), label: `${hh}:${mm}` });
29062
- }
29063
- startDate.setMinutes(startDate.getMinutes() + stepMin);
29064
- }
29065
- } else if (span <= 822e-5) {
29066
- let stepHour = 1;
29067
- const spanHours = span * 8760;
29068
- if (spanHours > 48) stepHour = 6;
29069
- else if (spanHours > 24) stepHour = 3;
29070
- else if (spanHours > 12) stepHour = 2;
29071
- const singleDay = spanHours <= 24;
29072
- const startDate = fractionalYearToDate(domainMin);
29073
- startDate.setHours(
29074
- Math.floor(startDate.getHours() / stepHour) * stepHour,
29075
- 0,
29076
- 0,
29077
- 0
29078
- );
29079
- while (true) {
29080
- const val = dateToFractionalYear2(startDate);
29081
- if (val > domainMax) break;
29082
- if (val >= domainMin) {
29083
- const hh = String(startDate.getHours()).padStart(2, "0");
29084
- const mm = String(startDate.getMinutes()).padStart(2, "0");
29085
- if (singleDay) {
29086
- ticks.push({ pos: scale(val), label: `${hh}:${mm}` });
29087
- } else {
29088
- const mon = MONTH_ABBR2[startDate.getMonth()];
29089
- const d = startDate.getDate();
29090
- ticks.push({ pos: scale(val), label: `${mon} ${d} ${hh}:${mm}` });
29091
- }
29092
- }
29093
- startDate.setHours(startDate.getHours() + stepHour);
29094
- }
29095
- } else {
29096
- for (let y = minYear; y <= maxYear + 1; y++) {
29097
- for (let m = 1; m <= 12; m++) {
29098
- for (const d of [1, 8, 15, 22]) {
29099
- const val = y + (m - 1) / 12 + (d - 1) / 365;
29100
- if (val > domainMax) break;
29101
- if (val >= domainMin) {
29102
- ticks.push({
29103
- pos: scale(val),
29104
- label: `${MONTH_ABBR2[m - 1]} ${d}`
29105
- });
29106
- }
29107
- }
29108
- }
29109
- }
29110
- }
29111
- const collisionThreshold = 40;
29112
- if (boundaryStart !== void 0 && boundaryStartLabel) {
29113
- const boundaryPos = scale(boundaryStart);
29114
- ticks = ticks.filter(
29115
- (t) => Math.abs(t.pos - boundaryPos) >= collisionThreshold
29116
- );
29117
- ticks.unshift({ pos: boundaryPos, label: boundaryStartLabel });
29118
- }
29119
- if (boundaryEnd !== void 0 && boundaryEndLabel) {
29120
- const boundaryPos = scale(boundaryEnd);
29121
- ticks = ticks.filter(
29122
- (t) => Math.abs(t.pos - boundaryPos) >= collisionThreshold
29123
- );
29124
- ticks.push({ pos: boundaryPos, label: boundaryEndLabel });
29125
- }
29126
- return ticks;
29127
- }
29128
29113
  function renderTimeScale(g, scale, isVertical, innerWidth, innerHeight, textColor, boundaryStart, boundaryEnd, boundaryStartLabel, boundaryEndLabel) {
29129
29114
  const [domainMin, domainMax] = scale.domain();
29130
29115
  const ticks = computeTimeTicks(
@@ -31052,7 +31037,7 @@ function createExportContainer(width, height) {
31052
31037
  document.body.appendChild(container);
31053
31038
  return container;
31054
31039
  }
31055
- function finalizeSvgExport(container, theme, palette, options) {
31040
+ function finalizeSvgExport(container, theme, palette) {
31056
31041
  const svgEl = container.querySelector("svg");
31057
31042
  if (!svgEl) return "";
31058
31043
  if (theme === "transparent") {
@@ -31065,10 +31050,6 @@ function finalizeSvgExport(container, theme, palette, options) {
31065
31050
  svgEl.querySelectorAll("[data-export-ignore]").forEach((el) => el.remove());
31066
31051
  const svgHtml = svgEl.outerHTML;
31067
31052
  document.body.removeChild(container);
31068
- if (options?.branding !== false) {
31069
- const brandColor = theme === "transparent" ? "#888" : palette.textMuted;
31070
- return injectBranding(svgHtml, brandColor);
31071
- }
31072
31053
  return svgHtml;
31073
31054
  }
31074
31055
  async function renderForExport(content, theme, palette, orgExportState, options) {
@@ -31115,7 +31096,7 @@ async function renderForExport(content, theme, palette, orgExportState, options)
31115
31096
  activeTagGroup,
31116
31097
  hiddenAttributes
31117
31098
  );
31118
- return finalizeSvgExport(container2, theme, effectivePalette2, options);
31099
+ return finalizeSvgExport(container2, theme, effectivePalette2);
31119
31100
  }
31120
31101
  if (detectedType === "sitemap") {
31121
31102
  const { parseSitemap: parseSitemap2 } = await Promise.resolve().then(() => (init_parser7(), parser_exports7));
@@ -31157,7 +31138,7 @@ async function renderForExport(content, theme, palette, orgExportState, options)
31157
31138
  activeTagGroup,
31158
31139
  hiddenAttributes
31159
31140
  );
31160
- return finalizeSvgExport(container2, theme, effectivePalette2, options);
31141
+ return finalizeSvgExport(container2, theme, effectivePalette2);
31161
31142
  }
31162
31143
  if (detectedType === "kanban") {
31163
31144
  const { parseKanban: parseKanban2 } = await Promise.resolve().then(() => (init_parser5(), parser_exports5));
@@ -31176,7 +31157,7 @@ async function renderForExport(content, theme, palette, orgExportState, options)
31176
31157
  options?.tagGroup
31177
31158
  )
31178
31159
  });
31179
- return finalizeSvgExport(container2, theme, effectivePalette2, options);
31160
+ return finalizeSvgExport(container2, theme, effectivePalette2);
31180
31161
  }
31181
31162
  if (detectedType === "class") {
31182
31163
  const { parseClassDiagram: parseClassDiagram2 } = await Promise.resolve().then(() => (init_parser2(), parser_exports2));
@@ -31200,7 +31181,7 @@ async function renderForExport(content, theme, palette, orgExportState, options)
31200
31181
  void 0,
31201
31182
  { width: exportWidth, height: exportHeight }
31202
31183
  );
31203
- return finalizeSvgExport(container2, theme, effectivePalette2, options);
31184
+ return finalizeSvgExport(container2, theme, effectivePalette2);
31204
31185
  }
31205
31186
  if (detectedType === "er") {
31206
31187
  const { parseERDiagram: parseERDiagram2 } = await Promise.resolve().then(() => (init_parser3(), parser_exports3));
@@ -31229,7 +31210,7 @@ async function renderForExport(content, theme, palette, orgExportState, options)
31229
31210
  options?.tagGroup
31230
31211
  )
31231
31212
  );
31232
- return finalizeSvgExport(container2, theme, effectivePalette2, options);
31213
+ return finalizeSvgExport(container2, theme, effectivePalette2);
31233
31214
  }
31234
31215
  if (detectedType === "boxes-and-lines") {
31235
31216
  const { parseBoxesAndLines: parseBoxesAndLines2 } = await Promise.resolve().then(() => (init_parser10(), parser_exports10));
@@ -31255,7 +31236,7 @@ async function renderForExport(content, theme, palette, orgExportState, options)
31255
31236
  activeTagGroup: options?.tagGroup
31256
31237
  }
31257
31238
  );
31258
- return finalizeSvgExport(container2, theme, effectivePalette2, options);
31239
+ return finalizeSvgExport(container2, theme, effectivePalette2);
31259
31240
  }
31260
31241
  if (detectedType === "c4") {
31261
31242
  const { parseC4: parseC42 } = await Promise.resolve().then(() => (init_parser6(), parser_exports6));
@@ -31294,7 +31275,7 @@ async function renderForExport(content, theme, palette, orgExportState, options)
31294
31275
  options?.tagGroup
31295
31276
  )
31296
31277
  );
31297
- return finalizeSvgExport(container2, theme, effectivePalette2, options);
31278
+ return finalizeSvgExport(container2, theme, effectivePalette2);
31298
31279
  }
31299
31280
  if (detectedType === "flowchart") {
31300
31281
  const { parseFlowchart: parseFlowchart2 } = await Promise.resolve().then(() => (init_flowchart_parser(), flowchart_parser_exports));
@@ -31314,7 +31295,7 @@ async function renderForExport(content, theme, palette, orgExportState, options)
31314
31295
  void 0,
31315
31296
  { width: EXPORT_WIDTH, height: EXPORT_HEIGHT }
31316
31297
  );
31317
- return finalizeSvgExport(container2, theme, effectivePalette2, options);
31298
+ return finalizeSvgExport(container2, theme, effectivePalette2);
31318
31299
  }
31319
31300
  if (detectedType === "infra") {
31320
31301
  const { parseInfra: parseInfra2 } = await Promise.resolve().then(() => (init_parser8(), parser_exports8));
@@ -31360,7 +31341,7 @@ async function renderForExport(content, theme, palette, orgExportState, options)
31360
31341
  infraSvg.setAttribute("width", String(exportWidth));
31361
31342
  infraSvg.setAttribute("height", String(exportHeight));
31362
31343
  }
31363
- return finalizeSvgExport(container2, theme, effectivePalette2, options);
31344
+ return finalizeSvgExport(container2, theme, effectivePalette2);
31364
31345
  }
31365
31346
  if (detectedType === "gantt") {
31366
31347
  const { parseGantt: parseGantt2 } = await Promise.resolve().then(() => (init_parser9(), parser_exports9));
@@ -31381,7 +31362,7 @@ async function renderForExport(content, theme, palette, orgExportState, options)
31381
31362
  void 0,
31382
31363
  { width: EXPORT_W, height: EXPORT_H }
31383
31364
  );
31384
- return finalizeSvgExport(container2, theme, effectivePalette2, options);
31365
+ return finalizeSvgExport(container2, theme, effectivePalette2);
31385
31366
  }
31386
31367
  if (detectedType === "state") {
31387
31368
  const { parseState: parseState2 } = await Promise.resolve().then(() => (init_state_parser(), state_parser_exports));
@@ -31401,7 +31382,7 @@ async function renderForExport(content, theme, palette, orgExportState, options)
31401
31382
  void 0,
31402
31383
  { width: EXPORT_WIDTH, height: EXPORT_HEIGHT }
31403
31384
  );
31404
- return finalizeSvgExport(container2, theme, effectivePalette2, options);
31385
+ return finalizeSvgExport(container2, theme, effectivePalette2);
31405
31386
  }
31406
31387
  const parsed = parseVisualization(content, palette);
31407
31388
  if (parsed.error && parsed.type !== "sequence") {
@@ -31493,9 +31474,9 @@ async function renderForExport(content, theme, palette, orgExportState, options)
31493
31474
  dims
31494
31475
  );
31495
31476
  }
31496
- return finalizeSvgExport(container, theme, effectivePalette, options);
31477
+ return finalizeSvgExport(container, theme, effectivePalette);
31497
31478
  }
31498
- var d3Scale2, d3Selection13, d3Shape9, d3Array, import_d3_cloud, DEFAULT_CLOUD_OPTIONS, STOP_WORDS, SLOPE_MARGIN, SLOPE_LABEL_FONT_SIZE, SLOPE_CHAR_WIDTH, ARC_MARGIN, MONTH_ABBR2, EXPORT_WIDTH, EXPORT_HEIGHT;
31479
+ var d3Scale2, d3Selection13, d3Shape9, d3Array, import_d3_cloud, DEFAULT_CLOUD_OPTIONS, STOP_WORDS, SLOPE_MARGIN, SLOPE_LABEL_FONT_SIZE, SLOPE_CHAR_WIDTH, ARC_MARGIN, EXPORT_WIDTH, EXPORT_HEIGHT;
31499
31480
  var init_d3 = __esm({
31500
31481
  "src/d3.ts"() {
31501
31482
  "use strict";
@@ -31505,8 +31486,8 @@ var init_d3 = __esm({
31505
31486
  d3Array = __toESM(require("d3-array"), 1);
31506
31487
  import_d3_cloud = __toESM(require("d3-cloud"), 1);
31507
31488
  init_fonts();
31508
- init_branding();
31509
31489
  init_label_layout();
31490
+ init_time_ticks();
31510
31491
  init_colors();
31511
31492
  init_palettes();
31512
31493
  init_color_utils();
@@ -31637,20 +31618,6 @@ var init_d3 = __esm({
31637
31618
  SLOPE_LABEL_FONT_SIZE = 14;
31638
31619
  SLOPE_CHAR_WIDTH = 8;
31639
31620
  ARC_MARGIN = { top: 60, right: 40, bottom: 60, left: 40 };
31640
- MONTH_ABBR2 = [
31641
- "Jan",
31642
- "Feb",
31643
- "Mar",
31644
- "Apr",
31645
- "May",
31646
- "Jun",
31647
- "Jul",
31648
- "Aug",
31649
- "Sep",
31650
- "Oct",
31651
- "Nov",
31652
- "Dec"
31653
- ];
31654
31621
  EXPORT_WIDTH = 1200;
31655
31622
  EXPORT_HEIGHT = 800;
31656
31623
  }
@@ -32117,6 +32084,7 @@ var require_lz_string = __commonJS({
32117
32084
  var index_exports = {};
32118
32085
  __export(index_exports, {
32119
32086
  ALL_CHART_TYPES: () => ALL_CHART_TYPES,
32087
+ ARROW_DIAGNOSTIC_CODES: () => ARROW_DIAGNOSTIC_CODES,
32120
32088
  CHART_TYPES: () => CHART_TYPES,
32121
32089
  COMPLETION_REGISTRY: () => COMPLETION_REGISTRY,
32122
32090
  ENTITY_TYPES: () => ENTITY_TYPES,
@@ -32132,13 +32100,10 @@ __export(index_exports, {
32132
32100
  applyPositionOverrides: () => applyPositionOverrides,
32133
32101
  boldPalette: () => boldPalette,
32134
32102
  buildExtendedChartOption: () => buildExtendedChartOption,
32135
- buildMermaidQuadrant: () => buildMermaidQuadrant,
32136
- buildMermaidThemeVars: () => buildMermaidThemeVars,
32137
32103
  buildNoteMessageMap: () => buildNoteMessageMap,
32138
32104
  buildRenderSequence: () => buildRenderSequence,
32139
32105
  buildSimpleChartOption: () => buildSimpleChartOption,
32140
32106
  buildTagLaneRowList: () => buildTagLaneRowList,
32141
- buildThemeCSS: () => buildThemeCSS,
32142
32107
  calculateSchedule: () => calculateSchedule,
32143
32108
  catppuccinPalette: () => catppuccinPalette,
32144
32109
  collapseBoxesAndLines: () => collapseBoxesAndLines,
@@ -32179,7 +32144,6 @@ __export(index_exports, {
32179
32144
  hslToHex: () => hslToHex,
32180
32145
  inferParticipantType: () => inferParticipantType,
32181
32146
  inferRoles: () => inferRoles,
32182
- injectBranding: () => injectBranding,
32183
32147
  isArchiveColumn: () => isArchiveColumn,
32184
32148
  isExtendedChartType: () => isExtendedChartType,
32185
32149
  isRecognizedColorName: () => isRecognizedColorName,
@@ -32204,8 +32168,8 @@ __export(index_exports, {
32204
32168
  looksLikeSitemap: () => looksLikeSitemap,
32205
32169
  looksLikeState: () => looksLikeState,
32206
32170
  makeDgmoError: () => makeDgmoError,
32171
+ matchColorParens: () => matchColorParens,
32207
32172
  monokaiPalette: () => monokaiPalette,
32208
- mute: () => mute,
32209
32173
  nord: () => nord,
32210
32174
  nordPalette: () => nordPalette,
32211
32175
  oneDarkPalette: () => oneDarkPalette,
@@ -32223,11 +32187,11 @@ __export(index_exports, {
32223
32187
  parseFirstLine: () => parseFirstLine,
32224
32188
  parseFlowchart: () => parseFlowchart,
32225
32189
  parseGantt: () => parseGantt,
32190
+ parseInArrowLabel: () => parseInArrowLabel,
32226
32191
  parseInfra: () => parseInfra,
32227
32192
  parseInlineMarkdown: () => parseInlineMarkdown,
32228
32193
  parseKanban: () => parseKanban,
32229
32194
  parseOrg: () => parseOrg,
32230
- parseQuadrant: () => parseQuadrant,
32231
32195
  parseSequenceDgmo: () => parseSequenceDgmo,
32232
32196
  parseSitemap: () => parseSitemap,
32233
32197
  parseState: () => parseState,
@@ -32286,10 +32250,12 @@ __export(index_exports, {
32286
32250
  tokyoNightPalette: () => tokyoNightPalette,
32287
32251
  truncateBareUrl: () => truncateBareUrl,
32288
32252
  validateComputed: () => validateComputed,
32289
- validateInfra: () => validateInfra
32253
+ validateInfra: () => validateInfra,
32254
+ validateLabelCharacters: () => validateLabelCharacters
32290
32255
  });
32291
32256
  module.exports = __toCommonJS(index_exports);
32292
32257
  init_diagnostics();
32258
+ init_arrows();
32293
32259
 
32294
32260
  // src/render.ts
32295
32261
  init_d3();
@@ -32325,8 +32291,8 @@ async function ensureDom() {
32325
32291
  async function render(content, options) {
32326
32292
  const theme = options?.theme ?? "light";
32327
32293
  const paletteName = options?.palette ?? "nord";
32328
- const branding = options?.branding ?? false;
32329
32294
  const paletteColors = getPalette(paletteName)[theme === "dark" ? "dark" : "light"];
32295
+ const { diagnostics } = parseDgmo(content);
32330
32296
  const chartType = parseDgmoChartType(content);
32331
32297
  const category = chartType ? getRenderCategory(chartType) : null;
32332
32298
  const legendExportState = options?.legendState ? {
@@ -32334,18 +32300,27 @@ async function render(content, options) {
32334
32300
  hiddenAttributes: options.legendState.hiddenAttributes ? new Set(options.legendState.hiddenAttributes) : void 0
32335
32301
  } : void 0;
32336
32302
  if (category === "data-chart") {
32337
- return renderExtendedChartForExport(content, theme, paletteColors, {
32338
- branding
32339
- });
32303
+ const svg2 = await renderExtendedChartForExport(
32304
+ content,
32305
+ theme,
32306
+ paletteColors
32307
+ );
32308
+ return { svg: svg2, diagnostics };
32340
32309
  }
32341
32310
  await ensureDom();
32342
- return renderForExport(content, theme, paletteColors, legendExportState, {
32343
- branding,
32344
- c4Level: options?.c4Level,
32345
- c4System: options?.c4System,
32346
- c4Container: options?.c4Container,
32347
- tagGroup: options?.tagGroup
32348
- });
32311
+ const svg = await renderForExport(
32312
+ content,
32313
+ theme,
32314
+ paletteColors,
32315
+ legendExportState,
32316
+ {
32317
+ c4Level: options?.c4Level,
32318
+ c4System: options?.c4System,
32319
+ c4Container: options?.c4Container,
32320
+ tagGroup: options?.tagGroup
32321
+ }
32322
+ );
32323
+ return { svg, diagnostics };
32349
32324
  }
32350
32325
 
32351
32326
  // src/index.ts
@@ -32353,172 +32328,9 @@ init_dgmo_router();
32353
32328
  init_chart();
32354
32329
  init_echarts();
32355
32330
  init_d3();
32331
+ init_time_ticks();
32356
32332
  init_parser();
32357
32333
  init_participant_inference();
32358
-
32359
- // src/dgmo-mermaid.ts
32360
- init_colors();
32361
- init_diagnostics();
32362
- var QUADRANT_LABEL_RE = /^(.+?)(?:\s*\(([^)]+)\))?\s*$/;
32363
- var DATA_POINT_RE = /^(.+?)\s+([0-9]*\.?[0-9]+)\s*,\s*([0-9]*\.?[0-9]+)\s*$/;
32364
- var QUADRANT_POSITIONS = /* @__PURE__ */ new Set([
32365
- "top-right",
32366
- "top-left",
32367
- "bottom-left",
32368
- "bottom-right"
32369
- ]);
32370
- function parseQuadrant(content) {
32371
- const result = {
32372
- title: null,
32373
- titleLineNumber: null,
32374
- xAxis: null,
32375
- xAxisLineNumber: null,
32376
- yAxis: null,
32377
- yAxisLineNumber: null,
32378
- quadrants: {
32379
- topRight: null,
32380
- topLeft: null,
32381
- bottomLeft: null,
32382
- bottomRight: null
32383
- },
32384
- points: [],
32385
- diagnostics: [],
32386
- error: null
32387
- };
32388
- const lines = content.split("\n");
32389
- for (let i = 0; i < lines.length; i++) {
32390
- const line10 = lines[i].trim();
32391
- const lineNumber = i + 1;
32392
- if (!line10 || line10.startsWith("//")) continue;
32393
- if (/^chart\s*:/i.test(line10)) continue;
32394
- const titleMatch = line10.match(/^title\s+(.+)/i);
32395
- if (titleMatch) {
32396
- result.title = titleMatch[1].trim();
32397
- result.titleLineNumber = lineNumber;
32398
- continue;
32399
- }
32400
- const xMatch = line10.match(/^x-label\s+(.+)/i);
32401
- if (xMatch) {
32402
- const parts = xMatch[1].split(",").map((s) => s.trim());
32403
- if (parts.length >= 2) {
32404
- result.xAxis = [parts[0], parts[1]];
32405
- result.xAxisLineNumber = lineNumber;
32406
- }
32407
- continue;
32408
- }
32409
- const yMatch = line10.match(/^y-label\s+(.+)/i);
32410
- if (yMatch) {
32411
- const parts = yMatch[1].split(",").map((s) => s.trim());
32412
- if (parts.length >= 2) {
32413
- result.yAxis = [parts[0], parts[1]];
32414
- result.yAxisLineNumber = lineNumber;
32415
- }
32416
- continue;
32417
- }
32418
- const posMatch = line10.match(
32419
- /^(top-right|top-left|bottom-left|bottom-right)\s+(.+)/i
32420
- );
32421
- if (posMatch) {
32422
- const position = posMatch[1].toLowerCase();
32423
- const labelMatch = posMatch[2].match(QUADRANT_LABEL_RE);
32424
- if (labelMatch) {
32425
- const label = {
32426
- text: labelMatch[1].trim(),
32427
- color: labelMatch[2] ? resolveColorWithDiagnostic(
32428
- labelMatch[2].trim(),
32429
- lineNumber,
32430
- result.diagnostics
32431
- ) ?? null : null,
32432
- lineNumber
32433
- };
32434
- if (position === "top-right") result.quadrants.topRight = label;
32435
- else if (position === "top-left") result.quadrants.topLeft = label;
32436
- else if (position === "bottom-left")
32437
- result.quadrants.bottomLeft = label;
32438
- else if (position === "bottom-right")
32439
- result.quadrants.bottomRight = label;
32440
- }
32441
- continue;
32442
- }
32443
- const pointMatch = line10.match(DATA_POINT_RE);
32444
- if (pointMatch) {
32445
- const key = pointMatch[1].trim().toLowerCase();
32446
- if (!QUADRANT_POSITIONS.has(key)) {
32447
- result.points.push({
32448
- label: pointMatch[1].trim(),
32449
- x: parseFloat(pointMatch[2]),
32450
- y: parseFloat(pointMatch[3]),
32451
- lineNumber
32452
- });
32453
- }
32454
- continue;
32455
- }
32456
- }
32457
- if (result.points.length === 0) {
32458
- const diag = makeDgmoError(
32459
- 1,
32460
- "No data points found. Add lines like: Label 0.5, 0.7"
32461
- );
32462
- result.diagnostics.push(diag);
32463
- result.error = formatDgmoError(diag);
32464
- }
32465
- return result;
32466
- }
32467
- function buildMermaidQuadrant(parsed, options = {}) {
32468
- const { isDark = false, textColor, mutedTextColor } = options;
32469
- const lines = [];
32470
- const fillAlpha = isDark ? "30" : "55";
32471
- const primaryText = textColor ?? (isDark ? "#d0d0d0" : "#333333");
32472
- const quadrantLabelText = mutedTextColor ?? (isDark ? "#888888" : "#666666");
32473
- const colorMap = {};
32474
- if (parsed.quadrants.topRight?.color)
32475
- colorMap.quadrant1Fill = parsed.quadrants.topRight.color + fillAlpha;
32476
- if (parsed.quadrants.topLeft?.color)
32477
- colorMap.quadrant2Fill = parsed.quadrants.topLeft.color + fillAlpha;
32478
- if (parsed.quadrants.bottomLeft?.color)
32479
- colorMap.quadrant3Fill = parsed.quadrants.bottomLeft.color + fillAlpha;
32480
- if (parsed.quadrants.bottomRight?.color)
32481
- colorMap.quadrant4Fill = parsed.quadrants.bottomRight.color + fillAlpha;
32482
- colorMap.quadrant1TextFill = quadrantLabelText;
32483
- colorMap.quadrant2TextFill = quadrantLabelText;
32484
- colorMap.quadrant3TextFill = quadrantLabelText;
32485
- colorMap.quadrant4TextFill = quadrantLabelText;
32486
- colorMap.quadrantPointTextFill = primaryText;
32487
- colorMap.quadrantXAxisTextFill = primaryText;
32488
- colorMap.quadrantYAxisTextFill = primaryText;
32489
- colorMap.quadrantTitleFill = primaryText;
32490
- const vars = JSON.stringify(colorMap);
32491
- lines.push(`%%{init: {"themeVariables": ${vars}}}%%`);
32492
- lines.push("quadrantChart");
32493
- if (parsed.title) {
32494
- lines.push(` title ${parsed.title}`);
32495
- }
32496
- if (parsed.xAxis) {
32497
- lines.push(` x-axis ${parsed.xAxis[0]} --> ${parsed.xAxis[1]}`);
32498
- }
32499
- if (parsed.yAxis) {
32500
- lines.push(` y-axis ${parsed.yAxis[0]} --> ${parsed.yAxis[1]}`);
32501
- }
32502
- const quote = (s) => /[\s,:[\]]/.test(s) ? `"${s}"` : s;
32503
- if (parsed.quadrants.topRight) {
32504
- lines.push(` quadrant-1 ${quote(parsed.quadrants.topRight.text)}`);
32505
- }
32506
- if (parsed.quadrants.topLeft) {
32507
- lines.push(` quadrant-2 ${quote(parsed.quadrants.topLeft.text)}`);
32508
- }
32509
- if (parsed.quadrants.bottomLeft) {
32510
- lines.push(` quadrant-3 ${quote(parsed.quadrants.bottomLeft.text)}`);
32511
- }
32512
- if (parsed.quadrants.bottomRight) {
32513
- lines.push(` quadrant-4 ${quote(parsed.quadrants.bottomRight.text)}`);
32514
- }
32515
- for (const point of parsed.points) {
32516
- lines.push(` ${quote(point.label)}: [${point.x}, ${point.y}]`);
32517
- }
32518
- return lines.join("\n");
32519
- }
32520
-
32521
- // src/index.ts
32522
32334
  init_flowchart_parser();
32523
32335
  init_state_parser();
32524
32336
  init_state_renderer();
@@ -33908,10 +33720,10 @@ registerExtractor("boxes-and-lines", extractBoxesAndLinesSymbols);
33908
33720
 
33909
33721
  // src/index.ts
33910
33722
  init_parsing();
33911
- init_branding();
33912
33723
  // Annotate the CommonJS export names for ESM import in node:
33913
33724
  0 && (module.exports = {
33914
33725
  ALL_CHART_TYPES,
33726
+ ARROW_DIAGNOSTIC_CODES,
33915
33727
  CHART_TYPES,
33916
33728
  COMPLETION_REGISTRY,
33917
33729
  ENTITY_TYPES,
@@ -33927,13 +33739,10 @@ init_branding();
33927
33739
  applyPositionOverrides,
33928
33740
  boldPalette,
33929
33741
  buildExtendedChartOption,
33930
- buildMermaidQuadrant,
33931
- buildMermaidThemeVars,
33932
33742
  buildNoteMessageMap,
33933
33743
  buildRenderSequence,
33934
33744
  buildSimpleChartOption,
33935
33745
  buildTagLaneRowList,
33936
- buildThemeCSS,
33937
33746
  calculateSchedule,
33938
33747
  catppuccinPalette,
33939
33748
  collapseBoxesAndLines,
@@ -33974,7 +33783,6 @@ init_branding();
33974
33783
  hslToHex,
33975
33784
  inferParticipantType,
33976
33785
  inferRoles,
33977
- injectBranding,
33978
33786
  isArchiveColumn,
33979
33787
  isExtendedChartType,
33980
33788
  isRecognizedColorName,
@@ -33999,8 +33807,8 @@ init_branding();
33999
33807
  looksLikeSitemap,
34000
33808
  looksLikeState,
34001
33809
  makeDgmoError,
33810
+ matchColorParens,
34002
33811
  monokaiPalette,
34003
- mute,
34004
33812
  nord,
34005
33813
  nordPalette,
34006
33814
  oneDarkPalette,
@@ -34018,11 +33826,11 @@ init_branding();
34018
33826
  parseFirstLine,
34019
33827
  parseFlowchart,
34020
33828
  parseGantt,
33829
+ parseInArrowLabel,
34021
33830
  parseInfra,
34022
33831
  parseInlineMarkdown,
34023
33832
  parseKanban,
34024
33833
  parseOrg,
34025
- parseQuadrant,
34026
33834
  parseSequenceDgmo,
34027
33835
  parseSitemap,
34028
33836
  parseState,
@@ -34081,6 +33889,7 @@ init_branding();
34081
33889
  tokyoNightPalette,
34082
33890
  truncateBareUrl,
34083
33891
  validateComputed,
34084
- validateInfra
33892
+ validateInfra,
33893
+ validateLabelCharacters
34085
33894
  });
34086
33895
  //# sourceMappingURL=index.cjs.map