@diagrammo/dgmo 0.30.0 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/.cursorrules +4 -1
  2. package/.github/copilot-instructions.md +4 -1
  3. package/.windsurfrules +4 -1
  4. package/README.md +21 -3
  5. package/SKILL.md +4 -1
  6. package/dist/advanced.cjs +1853 -623
  7. package/dist/advanced.d.cts +143 -16
  8. package/dist/advanced.d.ts +143 -16
  9. package/dist/advanced.js +1846 -623
  10. package/dist/auto.cjs +1640 -581
  11. package/dist/auto.js +99 -99
  12. package/dist/auto.mjs +1640 -581
  13. package/dist/cli.cjs +148 -147
  14. package/dist/index.cjs +1643 -662
  15. package/dist/index.js +1643 -662
  16. package/docs/ai-integration.md +4 -1
  17. package/docs/language-reference.md +282 -27
  18. package/gallery/fixtures/boxes-and-lines.dgmo +2 -2
  19. package/gallery/fixtures/c4-full.dgmo +4 -5
  20. package/gallery/fixtures/c4.dgmo +2 -3
  21. package/package.json +7 -1
  22. package/src/advanced.ts +10 -0
  23. package/src/boxes-and-lines/focus.ts +257 -0
  24. package/src/boxes-and-lines/layout-search.ts +345 -65
  25. package/src/boxes-and-lines/layout.ts +11 -1
  26. package/src/boxes-and-lines/parser.ts +97 -4
  27. package/src/boxes-and-lines/renderer.ts +111 -8
  28. package/src/boxes-and-lines/types.ts +9 -0
  29. package/src/c4/parser.ts +8 -7
  30. package/src/c4/renderer.ts +7 -5
  31. package/src/chart-type-registry.ts +129 -4
  32. package/src/chart-types.ts +3 -3
  33. package/src/chart.ts +18 -1
  34. package/src/class/renderer.ts +4 -2
  35. package/src/cli-banner.ts +107 -0
  36. package/src/cli.ts +13 -0
  37. package/src/colors.ts +247 -2
  38. package/src/cycle/parser.ts +2 -7
  39. package/src/d3.ts +67 -54
  40. package/src/diagnostics.ts +17 -0
  41. package/src/dimensions.ts +9 -13
  42. package/src/echarts.ts +42 -14
  43. package/src/er/parser.ts +6 -1
  44. package/src/er/renderer.ts +4 -2
  45. package/src/gantt/parser.ts +44 -7
  46. package/src/graph/flowchart-parser.ts +77 -3
  47. package/src/graph/flowchart-renderer.ts +4 -2
  48. package/src/graph/state-renderer.ts +6 -4
  49. package/src/infra/parser.ts +80 -0
  50. package/src/infra/renderer.ts +8 -4
  51. package/src/journey-map/parser.ts +23 -8
  52. package/src/journey-map/renderer.ts +1 -1
  53. package/src/kanban/parser.ts +8 -7
  54. package/src/kanban/renderer.ts +1 -1
  55. package/src/map/context-labels.ts +134 -27
  56. package/src/map/geo.ts +10 -2
  57. package/src/map/layout.ts +259 -4
  58. package/src/map/parser.ts +2 -0
  59. package/src/map/renderer.ts +49 -25
  60. package/src/map/resolver.ts +68 -19
  61. package/src/mindmap/parser.ts +15 -7
  62. package/src/mindmap/renderer.ts +55 -15
  63. package/src/org/parser.ts +8 -7
  64. package/src/org/renderer.ts +89 -127
  65. package/src/palettes/color-utils.ts +19 -4
  66. package/src/palettes/index.ts +1 -0
  67. package/src/pert/renderer.ts +15 -10
  68. package/src/pyramid/parser.ts +2 -7
  69. package/src/quadrant/renderer.ts +2 -2
  70. package/src/raci/parser.ts +2 -7
  71. package/src/raci/renderer.ts +5 -5
  72. package/src/ring/parser.ts +2 -7
  73. package/src/sequence/parser.ts +18 -7
  74. package/src/sequence/renderer.ts +4 -4
  75. package/src/sitemap/parser.ts +8 -7
  76. package/src/sitemap/renderer.ts +37 -39
  77. package/src/tech-radar/parser.ts +2 -7
  78. package/src/timeline/renderer.ts +15 -5
  79. package/src/utils/card.ts +183 -0
  80. package/src/utils/parsing.ts +13 -1
  81. package/src/utils/scaling.ts +38 -81
  82. package/src/utils/tag-groups.ts +48 -10
  83. package/src/utils/visual-conventions.ts +61 -0
  84. package/src/visualizations/parse.ts +6 -1
  85. package/src/wireframe/parser.ts +6 -1
@@ -9,7 +9,11 @@ import {
9
9
  tagShorthandRemovedMessage,
10
10
  type DgmoError,
11
11
  } from '../diagnostics';
12
- import { RECOGNIZED_COLOR_NAMES, resolveColor } from '../colors';
12
+ import {
13
+ CATEGORICAL_COLOR_ORDER,
14
+ RECOGNIZED_COLOR_NAMES,
15
+ resolveColor,
16
+ } from '../colors';
13
17
  import type { PaletteColors } from '../palettes/types';
14
18
  import type { Writable } from './brand';
15
19
 
@@ -91,16 +95,12 @@ export const AUTO_TAG_COLOR_SENTINEL = '';
91
95
 
92
96
  /**
93
97
  * The categorical name cycle used to auto-assign colors to bare tag values,
94
- * in deterministic order. Drawn from `RECOGNIZED_COLOR_NAMES` but excludes
95
- * the non-categorical neutrals (`gray`/`black`/`white`) so auto-picked
96
- * colors are visually distinct legend swatches. If a group has more
97
- * colorless entries than free categorical names, the cycle wraps.
98
+ * in deterministic order. Aliased to the shared {@link CATEGORICAL_COLOR_ORDER}
99
+ * (RGB-seeded, max-contrast, neutrals excluded) so tag swatches and data-chart
100
+ * series colors share one canonical rotation. If a group has more colorless
101
+ * entries than free categorical names, the cycle wraps.
98
102
  */
99
- export const autoTagColorCycle: readonly string[] = Object.freeze(
100
- RECOGNIZED_COLOR_NAMES.filter(
101
- (n) => n !== 'gray' && n !== 'black' && n !== 'white'
102
- )
103
- );
103
+ export const autoTagColorCycle: readonly string[] = CATEGORICAL_COLOR_ORDER;
104
104
 
105
105
  /**
106
106
  * Finalize a tag group's auto-color assignment.
@@ -572,6 +572,44 @@ export function validateTagGroupNames(
572
572
  }
573
573
  }
574
574
 
575
+ // ── Parent → Child Tag Cascade ────────────────────────────
576
+
577
+ /**
578
+ * Cascade explicit tag values down a node tree: a child that has no value of
579
+ * its own for a given tag group inherits the value of its nearest ancestor
580
+ * that does. A child's own explicit value always wins and becomes the new
581
+ * inherited value for its subtree.
582
+ *
583
+ * Run this on the parsed tree BEFORE {@link injectDefaultTagMetadata} so that
584
+ * an inherited ancestor value takes precedence over the group's global
585
+ * default — only nodes with no tagged ancestor fall through to the default.
586
+ * Idempotent and mutates `metadata` in place.
587
+ *
588
+ * @param roots Root nodes of the tree (each with mutable `metadata` + `children`)
589
+ * @param tagGroups Declared tag groups (only `.name` is used)
590
+ */
591
+ export function cascadeTagMetadata<
592
+ T extends { metadata: Record<string, string>; children: readonly T[] },
593
+ >(roots: readonly T[], tagGroups: ReadonlyArray<{ name: string }>): void {
594
+ const keys = tagGroups.map((g) => g.name.toLowerCase());
595
+ if (keys.length === 0) return;
596
+
597
+ const walk = (node: T, inherited: Record<string, string>): void => {
598
+ const childInherited = { ...inherited };
599
+ for (const key of keys) {
600
+ const own = node.metadata[key];
601
+ if (own) {
602
+ childInherited[key] = own; // own explicit value propagates downward
603
+ } else if (inherited[key]) {
604
+ node.metadata[key] = inherited[key]; // inherit from nearest ancestor
605
+ }
606
+ }
607
+ for (const child of node.children) walk(child, childInherited);
608
+ };
609
+
610
+ for (const root of roots) walk(root, {});
611
+ }
612
+
575
613
  // ── Default Metadata Injection ────────────────────────────
576
614
 
577
615
  /**
@@ -0,0 +1,61 @@
1
+ // ============================================================
2
+ // Visual conventions — shared card/group/collapse constants (Story 111.1)
3
+ // ============================================================
4
+ //
5
+ // Single source of truth for the structured-diagram visual constants described
6
+ // in docs/architecture/diagram-visual-conventions.md. Before this module these
7
+ // values were re-declared in every renderer (NODE_STROKE_WIDTH in 13 files,
8
+ // HEADER_HEIGHT in 12, ...), so a convention change meant editing N files and
9
+ // hoping the snapshots agreed.
10
+ //
11
+ // Two tiers, because the renderers do NOT all agree:
12
+ //
13
+ // 1. UNIVERSAL — identical at every call site. Import these everywhere; never
14
+ // re-declare. Changing one of these is a deliberate cross-chart change.
15
+ //
16
+ // 2. CONVENTION DEFAULTS — the org/sitemap baseline from the convention. Most
17
+ // card-shaped renderers match these and should import them. A few have a
18
+ // DOCUMENTED intentional deviation and keep a local override (with a
19
+ // comment saying why):
20
+ // - infra: META_FONT_SIZE 10 / META_LINE_HEIGHT 14 (denser meta rows)
21
+ // - boxes-and-lines: COLLAPSE_BAR_HEIGHT 4 / SEPARATOR_GAP 4
22
+ // - cycle, raci: HEADER_HEIGHT 36 (not label+meta cards)
23
+ // Those overrides are the exception that proves the rule — they stay local
24
+ // and visible, not hidden inside a re-declared full constant set.
25
+
26
+ // ── Universal (same value at every site) ──
27
+
28
+ /** Node card + group border stroke width. */
29
+ export const NODE_STROKE_WIDTH = 1.5;
30
+ /** Edge / connector stroke width. */
31
+ export const EDGE_STROKE_WIDTH = 1.5;
32
+ /** Node card corner radius. */
33
+ export const CARD_RADIUS = 6;
34
+ /** Group / container corner radius. */
35
+ export const CONTAINER_RADIUS = 8;
36
+ /** Collapse accent bar horizontal inset from the card edges. */
37
+ export const COLLAPSE_BAR_INSET = 0;
38
+
39
+ // ── Convention defaults (org/sitemap baseline; see deviations above) ──
40
+
41
+ /** Node card header band height. */
42
+ export const HEADER_HEIGHT = 28;
43
+ /** Node card label font size. */
44
+ export const LABEL_FONT_SIZE = 13;
45
+ /** Node card metadata-row font size. */
46
+ export const META_FONT_SIZE = 11;
47
+ /** Node card metadata-row line height. */
48
+ export const META_LINE_HEIGHT = 16;
49
+ /** Gap between the header separator and the first metadata row. */
50
+ export const SEPARATOR_GAP = 6;
51
+ /** Collapse accent bar height. */
52
+ export const COLLAPSE_BAR_HEIGHT = 6;
53
+
54
+ /** Group / container reserved header band height. */
55
+ export const CONTAINER_HEADER_HEIGHT = 28;
56
+ /** Group / container label font size. */
57
+ export const CONTAINER_LABEL_FONT_SIZE = 13;
58
+ /** Group / container metadata-row font size. */
59
+ export const CONTAINER_META_FONT_SIZE = 11;
60
+ /** Group / container metadata-row line height. */
61
+ export const CONTAINER_META_LINE_HEIGHT = 16;
@@ -215,7 +215,12 @@ function parseVisualizationFull(
215
215
  // Timeline tag group entries (indented under tag heading)
216
216
  if (currentTimelineTagGroup && indent > 0) {
217
217
  const { text: entryText, isDefault } = stripDefaultModifier(line);
218
- const { label, color } = extractColor(entryText, palette);
218
+ const { label, color } = extractColor(
219
+ entryText,
220
+ palette,
221
+ result.diagnostics,
222
+ lineNumber
223
+ );
219
224
  if (color) {
220
225
  if (isDefault) {
221
226
  currentTimelineTagGroup.defaultValue = label;
@@ -895,7 +895,12 @@ export function parseWireframe(content: string): ParsedWireframe {
895
895
  // Indented tag entry: `Value color` or `Value color default`
896
896
  if (indent > 0 && currentTagGroup) {
897
897
  const { text: cleanEntry, isDefault } = stripDefaultModifier(trimmed);
898
- const { label, color } = extractColor(cleanEntry);
898
+ const { label, color } = extractColor(
899
+ cleanEntry,
900
+ undefined,
901
+ diagnostics,
902
+ lineNumber
903
+ );
899
904
  // Bare value (no explicit color) → keep it; finalized below.
900
905
  currentTagGroup.entries.push({
901
906
  value: label,