@diagrammo/dgmo 0.8.23 → 0.8.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/.claude/commands/dgmo.md +43 -431
  2. package/.cursorrules +2 -2
  3. package/.windsurfrules +2 -2
  4. package/AGENTS.md +8 -5
  5. package/dist/cli.cjs +119 -114
  6. package/dist/editor.cjs +0 -2
  7. package/dist/editor.cjs.map +1 -1
  8. package/dist/editor.js +0 -2
  9. package/dist/editor.js.map +1 -1
  10. package/dist/highlight.cjs +0 -2
  11. package/dist/highlight.cjs.map +1 -1
  12. package/dist/highlight.js +0 -2
  13. package/dist/highlight.js.map +1 -1
  14. package/dist/index.cjs +719 -281
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +105 -18
  17. package/dist/index.d.ts +105 -18
  18. package/dist/index.js +709 -280
  19. package/dist/index.js.map +1 -1
  20. package/dist/internal.cjs +348 -51
  21. package/dist/internal.cjs.map +1 -1
  22. package/dist/internal.d.cts +93 -5
  23. package/dist/internal.d.ts +93 -5
  24. package/dist/internal.js +334 -38
  25. package/dist/internal.js.map +1 -1
  26. package/docs/guide/chart-area.md +17 -17
  27. package/docs/guide/chart-bar-stacked.md +12 -12
  28. package/docs/guide/chart-doughnut.md +10 -10
  29. package/docs/guide/chart-funnel.md +9 -9
  30. package/docs/guide/chart-heatmap.md +10 -10
  31. package/docs/guide/chart-kanban.md +2 -0
  32. package/docs/guide/chart-line.md +19 -19
  33. package/docs/guide/chart-multi-line.md +16 -16
  34. package/docs/guide/chart-pie.md +11 -11
  35. package/docs/guide/chart-polar-area.md +10 -10
  36. package/docs/guide/chart-radar.md +9 -9
  37. package/docs/guide/chart-scatter.md +24 -27
  38. package/docs/guide/index.md +3 -3
  39. package/docs/language-reference.md +46 -25
  40. package/fonts/Inter-Bold.ttf +0 -0
  41. package/fonts/Inter-Regular.ttf +0 -0
  42. package/fonts/LICENSE-Inter.txt +92 -0
  43. package/gallery/fixtures/bar-stacked.dgmo +12 -6
  44. package/gallery/fixtures/heatmap.dgmo +12 -6
  45. package/gallery/fixtures/multi-line.dgmo +11 -7
  46. package/gallery/fixtures/quadrant.dgmo +8 -8
  47. package/gallery/fixtures/scatter.dgmo +12 -12
  48. package/package.json +10 -3
  49. package/src/boxes-and-lines/parser.ts +13 -2
  50. package/src/boxes-and-lines/renderer.ts +22 -13
  51. package/src/chart-type-scoring.ts +162 -0
  52. package/src/chart-types.ts +437 -0
  53. package/src/cli.ts +147 -66
  54. package/src/completion.ts +0 -4
  55. package/src/d3.ts +40 -2
  56. package/src/dgmo-router.ts +85 -130
  57. package/src/editor/keywords.ts +0 -2
  58. package/src/fonts.ts +3 -2
  59. package/src/gantt/parser.ts +5 -1
  60. package/src/index.ts +24 -1
  61. package/src/infra/parser.ts +1 -1
  62. package/src/internal.ts +6 -2
  63. package/src/journey-map/layout.ts +8 -6
  64. package/src/journey-map/parser.ts +5 -1
  65. package/src/kanban/parser.ts +5 -1
  66. package/src/org/collapse.ts +1 -4
  67. package/src/org/parser.ts +1 -1
  68. package/src/org/renderer.ts +26 -17
  69. package/src/sequence/parser.ts +2 -2
  70. package/src/sequence/participant-inference.ts +0 -1
  71. package/src/sequence/renderer.ts +95 -263
  72. package/src/sharing.ts +0 -1
  73. package/src/sitemap/parser.ts +1 -1
  74. package/src/tech-radar/layout.ts +1 -2
  75. package/src/tech-radar/shared.ts +1 -37
  76. package/src/utils/tag-groups.ts +35 -5
  77. package/src/wireframe/parser.ts +3 -1
  78. package/src/tech-radar/index.ts +0 -14
package/src/index.ts CHANGED
@@ -23,6 +23,28 @@ export type { ParseInArrowLabelResult } from './utils/arrows';
23
23
 
24
24
  export { render } from './render';
25
25
 
26
+ // ============================================================
27
+ // Chart-type registry (single source of truth)
28
+ // ============================================================
29
+
30
+ export { chartTypes } from './chart-types';
31
+ export type { ChartTypeMeta } from './chart-types';
32
+
33
+ export {
34
+ normalize as normalizeChartTypePrompt,
35
+ matchesContiguously,
36
+ scoreChartType,
37
+ confidence as chartTypeConfidence,
38
+ suggestChartTypes,
39
+ MIN_PRIMARY_SCORE,
40
+ AMBIGUITY_THRESHOLD,
41
+ } from './chart-type-scoring';
42
+ export type {
43
+ ChartTypeScore,
44
+ Confidence as ChartTypeConfidence,
45
+ SuggestionResult as ChartTypeSuggestionResult,
46
+ } from './chart-type-scoring';
47
+
26
48
  // ============================================================
27
49
  // Router
28
50
  // ============================================================
@@ -34,6 +56,8 @@ export {
34
56
  isExtendedChartType,
35
57
  getAllChartTypes,
36
58
  CHART_TYPE_DESCRIPTIONS,
59
+ chartTypeParsers,
60
+ knownChartTypeIds,
37
61
  } from './dgmo-router';
38
62
  export type { RenderCategory } from './dgmo-router';
39
63
 
@@ -496,7 +520,6 @@ export {
496
520
  applyGroupOrdering,
497
521
  groupMessagesBySection,
498
522
  buildNoteMessageMap,
499
- collectNoteLineNumbers,
500
523
  } from './sequence/renderer';
501
524
  export type {
502
525
  RenderStep,
@@ -765,7 +765,7 @@ export function parseInfra(content: string): ParsedInfra {
765
765
  }
766
766
  }
767
767
 
768
- validateTagGroupNames(result.tagGroups, warn);
768
+ validateTagGroupNames(result.tagGroups, warn, setError);
769
769
 
770
770
  return result;
771
771
  }
package/src/internal.ts CHANGED
@@ -10,7 +10,11 @@ export {
10
10
  isArchiveColumn,
11
11
  } from './kanban/mutations';
12
12
  export {
13
- groupMessagesBySection,
13
+ applyGroupOrdering,
14
+ applyPositionOverrides,
14
15
  buildNoteMessageMap,
15
- collectNoteLineNumbers,
16
+ buildRenderSequence,
17
+ computeActivations,
18
+ groupMessagesBySection,
16
19
  } from './sequence/renderer';
20
+ export { orderArcNodes } from './d3';
@@ -27,7 +27,7 @@ export interface StepLayout {
27
27
  color: string;
28
28
  }
29
29
 
30
- export interface PhaseLayout {
30
+ interface PhaseLayout {
31
31
  x: number;
32
32
  y: number;
33
33
  width: number;
@@ -88,8 +88,6 @@ export function scoreToColor(score: number, palette: PaletteColors): string {
88
88
  // Layout Engine
89
89
  // ============================================================
90
90
 
91
- export const COLLAPSED_PHASE_WIDTH = 60;
92
-
93
91
  export function layoutJourneyMap(
94
92
  parsed: ParsedJourneyMap,
95
93
  palette: PaletteColors,
@@ -121,14 +119,18 @@ export function layoutJourneyMap(
121
119
  ? parsed.phases.flatMap((p) => p.steps)
122
120
  : parsed.steps;
123
121
 
124
- // Compute step card heights based on content (matches kanban card sizing)
122
+ // Compute step card heights based on content (matches kanban card sizing).
123
+ // Char-width constants MUST match the renderer's wrapText() in renderer.ts
124
+ // (`fontSize * 0.6`) and the title wrap (`TITLE_CHAR_WIDTH`) — otherwise the
125
+ // layout reserves too little vertical space and rendered text overflows.
125
126
  const annoIconIndent = ANNO_ICON_SIZE + ANNO_ICON_GAP;
126
127
  const annoTextW = STEP_CARD_WIDTH - CARD_PADDING_X * 2 - annoIconIndent;
127
128
  const descTextWidth = STEP_CARD_WIDTH - CARD_PADDING_X * 2;
128
- const charWidth = 4.8; // average char width at FONT_SIZE_META (10px)
129
+ const FONT_SIZE_META = 10;
130
+ const charWidth = FONT_SIZE_META * 0.6; // matches renderer wrapText()
129
131
 
130
132
  const titleTextWidth = STEP_CARD_WIDTH - CARD_PADDING_X * 2;
131
- const titleCharWidth = 6.5; // average char width at FONT_SIZE_STEP (12px)
133
+ const titleCharWidth = 6.5; // matches renderer TITLE_CHAR_WIDTH (FONT_SIZE_STEP 12px)
132
134
  const TITLE_LINE_HEIGHT = 16;
133
135
 
134
136
  const stepHeights = allSteps.map((step) => {
@@ -408,7 +408,11 @@ export function parseJourneyMap(
408
408
  return fail(1, 'No phases or steps found');
409
409
  }
410
410
 
411
- validateTagGroupNames(result.tagGroups, warn);
411
+ validateTagGroupNames(result.tagGroups, warn, (line, msg) => {
412
+ const diag = makeDgmoError(line, msg);
413
+ result.diagnostics.push(diag);
414
+ if (!result.error) result.error = formatDgmoError(diag);
415
+ });
412
416
 
413
417
  return result;
414
418
  }
@@ -373,7 +373,11 @@ export function parseKanban(
373
373
  return fail(1, 'No columns found. Use [Column Name] to define columns');
374
374
  }
375
375
 
376
- validateTagGroupNames(result.tagGroups, warn);
376
+ validateTagGroupNames(result.tagGroups, warn, (line, msg) => {
377
+ const diag = makeDgmoError(line, msg);
378
+ result.diagnostics.push(diag);
379
+ if (!result.error) result.error = formatDgmoError(diag);
380
+ });
377
381
 
378
382
  return result;
379
383
  }
@@ -72,10 +72,7 @@ function computeHiddenCounts(
72
72
  }
73
73
 
74
74
  /** Remove children of collapsed nodes on the cloned tree. */
75
- function pruneCollapsed(
76
- node: OrgNode,
77
- collapsedIds: Set<string>
78
- ): void {
75
+ function pruneCollapsed(node: OrgNode, collapsedIds: Set<string>): void {
79
76
  for (const child of node.children) {
80
77
  pruneCollapsed(child, collapsedIds);
81
78
  }
package/src/org/parser.ts CHANGED
@@ -344,7 +344,7 @@ export function parseOrg(content: string, palette?: PaletteColors): ParsedOrg {
344
344
  collectAll(result.roots);
345
345
 
346
346
  validateTagValues(allNodes, result.tagGroups, pushWarning, suggest);
347
- validateTagGroupNames(result.tagGroups, pushWarning);
347
+ validateTagGroupNames(result.tagGroups, pushWarning, pushError);
348
348
  }
349
349
 
350
350
  if (
@@ -138,14 +138,16 @@ export function renderOrg(
138
138
  const titleReserve = fixedTitle ? TITLE_HEIGHT : 0;
139
139
 
140
140
  // Ancestor breadcrumb trail (focus mode) — rendered inside the scaled group
141
- const hasAncestorTrail = !exportDims && ancestorPath && ancestorPath.length > 0;
141
+ const hasAncestorTrail =
142
+ !exportDims && ancestorPath && ancestorPath.length > 0;
142
143
  const ancestorTrailHeight = hasAncestorTrail
143
144
  ? ancestorPath.length * ANCESTOR_ROW_HEIGHT + ANCESTOR_TRAIL_BOTTOM_GAP
144
145
  : 0;
145
146
 
146
147
  // Compute scale to fit diagram in viewport
147
148
  const diagramW = layout.width;
148
- let diagramH = layout.height + (fixedTitle ? 0 : titleOffset) + ancestorTrailHeight;
149
+ let diagramH =
150
+ layout.height + (fixedTitle ? 0 : titleOffset) + ancestorTrailHeight;
149
151
  if (fixedLegend) {
150
152
  // Remove the legend space from diagram height — legend is rendered separately
151
153
  diagramH -= layoutLegendShift;
@@ -594,15 +596,17 @@ export function renderOrg(
594
596
  : rootContainer
595
597
  ? rootContainer.x + rootContainer.width / 2
596
598
  : null;
597
- const rootTopY = rootNode ? rootNode.y : rootContainer ? rootContainer.y : null;
599
+ const rootTopY = rootNode
600
+ ? rootNode.y
601
+ : rootContainer
602
+ ? rootContainer.y
603
+ : null;
598
604
  if (rootCenterX !== null && rootTopY !== null) {
599
605
  // Trail connects directly to the top edge of the root node.
600
606
  // The last ancestor dot sits ANCESTOR_TRAIL_BOTTOM_GAP above the root.
601
607
  const trailBottomY = rootTopY - ANCESTOR_TRAIL_BOTTOM_GAP;
602
608
 
603
- const trailG = contentG
604
- .append('g')
605
- .attr('class', 'org-ancestor-trail');
609
+ const trailG = contentG.append('g').attr('class', 'org-ancestor-trail');
606
610
 
607
611
  const count = ancestorPath!.length;
608
612
 
@@ -631,13 +635,14 @@ export function renderOrg(
631
635
  const dotY = dotPositions[i];
632
636
 
633
637
  // Resolve color from tag groups (same logic as node cards)
634
- const resolvedColor = ancestor.color
635
- ?? resolveTagColor(
636
- ancestor.metadata,
637
- parsed.tagGroups,
638
- activeTagGroup ?? null,
639
- ancestor.isContainer
640
- );
638
+ const resolvedColor =
639
+ ancestor.color ??
640
+ resolveTagColor(
641
+ ancestor.metadata,
642
+ parsed.tagGroups,
643
+ activeTagGroup ?? null,
644
+ ancestor.isContainer
645
+ );
641
646
  const dotColor = resolvedColor ?? palette.textMuted;
642
647
 
643
648
  const rowG = trailG
@@ -676,14 +681,18 @@ export function renderOrg(
676
681
  // Hover effect
677
682
  rowG
678
683
  .on('mouseenter', function () {
679
- d3Selection.select(this).select('circle')
684
+ d3Selection
685
+ .select(this)
686
+ .select('circle')
680
687
  .attr('r', ANCESTOR_DOT_R + 1);
681
688
  d3Selection.select(this).select('text').attr('fill', palette.text);
682
689
  })
683
690
  .on('mouseleave', function () {
684
- d3Selection.select(this).select('circle')
685
- .attr('r', ANCESTOR_DOT_R);
686
- d3Selection.select(this).select('text').attr('fill', palette.textMuted);
691
+ d3Selection.select(this).select('circle').attr('r', ANCESTOR_DOT_R);
692
+ d3Selection
693
+ .select(this)
694
+ .select('text')
695
+ .attr('fill', palette.textMuted);
687
696
  });
688
697
  }
689
698
  }
@@ -26,7 +26,7 @@ import {
26
26
  const KNOWN_SEQ_OPTIONS = new Set(['active-tag']);
27
27
 
28
28
  /** Known sequence-diagram boolean options (bare keyword or `no-` prefix). */
29
- const KNOWN_SEQ_BOOLEANS = new Set(['activations', 'collapse-notes']);
29
+ const KNOWN_SEQ_BOOLEANS = new Set(['activations']);
30
30
 
31
31
  /**
32
32
  * Participant types that can be declared via "Name is a type" syntax.
@@ -1345,7 +1345,7 @@ export function parseSequenceDgmo(content: string): ParsedSequenceDgmo {
1345
1345
  entities.push({ metadata: g.metadata, lineNumber: g.lineNumber });
1346
1346
  }
1347
1347
  validateTagValues(entities, result.tagGroups, pushWarning, suggest);
1348
- validateTagGroupNames(result.tagGroups, pushWarning);
1348
+ validateTagGroupNames(result.tagGroups, pushWarning, pushError);
1349
1349
  }
1350
1350
 
1351
1351
  return result;
@@ -185,7 +185,6 @@ const PARTICIPANT_RULES: readonly InferenceRule[] = [
185
185
  { pattern: /^Admin$/i, type: 'actor' },
186
186
  { pattern: /^User$/i, type: 'actor' },
187
187
  { pattern: /^Customer$/i, type: 'actor' },
188
- { pattern: /^Client$/i, type: 'actor' },
189
188
  { pattern: /^Agent$/i, type: 'actor' },
190
189
  { pattern: /^Person$/i, type: 'actor' },
191
190
  { pattern: /^Buyer$/i, type: 'actor' },