@diagrammo/dgmo 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -10
- package/dist/advanced.cjs +53094 -0
- package/dist/advanced.d.cts +4690 -0
- package/dist/advanced.d.ts +4690 -0
- package/dist/advanced.js +52849 -0
- package/dist/auto.cjs +2298 -2069
- package/dist/auto.js +132 -109
- package/dist/auto.mjs +2294 -2065
- package/dist/cli.cjs +175 -152
- package/dist/editor.cjs +8 -9
- package/dist/editor.js +8 -9
- package/dist/highlight.cjs +8 -9
- package/dist/highlight.js +8 -9
- package/dist/index.cjs +2281 -2048
- package/dist/index.d.cts +45 -1
- package/dist/index.d.ts +45 -1
- package/dist/index.js +2276 -2044
- package/dist/internal.cjs +2064 -1831
- package/dist/internal.d.cts +113 -113
- package/dist/internal.d.ts +113 -113
- package/dist/internal.js +2059 -1826
- package/dist/pert.cjs +325 -0
- package/dist/pert.d.cts +542 -0
- package/dist/pert.d.ts +542 -0
- package/dist/pert.js +294 -0
- package/docs/language-reference.md +83 -66
- package/gallery/fixtures/area.dgmo +3 -3
- package/gallery/fixtures/bar-stacked.dgmo +5 -5
- package/gallery/fixtures/boxes-and-lines.dgmo +2 -2
- package/gallery/fixtures/c4-full.dgmo +8 -8
- package/gallery/fixtures/class-full.dgmo +2 -2
- package/gallery/fixtures/doughnut.dgmo +6 -6
- package/gallery/fixtures/flowchart-colors.dgmo +3 -3
- package/gallery/fixtures/function.dgmo +3 -3
- package/gallery/fixtures/gantt-full.dgmo +9 -9
- package/gallery/fixtures/gantt.dgmo +7 -7
- package/gallery/fixtures/infra-full.dgmo +6 -6
- package/gallery/fixtures/infra.dgmo +2 -2
- package/gallery/fixtures/kanban.dgmo +9 -9
- package/gallery/fixtures/line.dgmo +2 -2
- package/gallery/fixtures/multi-line.dgmo +3 -3
- package/gallery/fixtures/org-full.dgmo +6 -6
- package/gallery/fixtures/quadrant.dgmo +2 -2
- package/gallery/fixtures/sankey.dgmo +9 -9
- package/gallery/fixtures/scatter.dgmo +3 -3
- package/gallery/fixtures/sequence-tags-protocols.dgmo +8 -8
- package/gallery/fixtures/sequence-tags.dgmo +7 -7
- package/gallery/fixtures/sitemap-full.dgmo +7 -7
- package/gallery/fixtures/slope.dgmo +5 -5
- package/gallery/fixtures/spr-eras.dgmo +9 -9
- package/gallery/fixtures/timeline.dgmo +3 -3
- package/gallery/fixtures/venn.dgmo +3 -3
- package/package.json +28 -3
- package/src/advanced.ts +730 -0
- package/src/auto/index.ts +14 -13
- package/src/boxes-and-lines/layout.ts +481 -445
- package/src/boxes-and-lines/renderer.ts +5 -1
- package/src/c4/parser.ts +8 -8
- package/src/c4/renderer.ts +15 -8
- package/src/chart-types.ts +0 -5
- package/src/chart.ts +18 -9
- package/src/class/parser.ts +8 -15
- package/src/class/renderer.ts +17 -6
- package/src/cli.ts +15 -13
- package/src/completion-types.ts +28 -0
- package/src/completion.ts +28 -21
- package/src/cycle/layout.ts +2 -2
- package/src/cycle/parser.ts +14 -0
- package/src/cycle/renderer.ts +6 -3
- package/src/d3.ts +1537 -1164
- package/src/echarts.ts +37 -20
- package/src/editor/dgmo.grammar +1 -3
- package/src/editor/dgmo.grammar.js +8 -8
- package/src/editor/dgmo.grammar.terms.js +11 -12
- package/src/editor/highlight-api.ts +0 -1
- package/src/editor/highlight.ts +0 -1
- package/src/er/parser.ts +19 -20
- package/src/er/renderer.ts +20 -8
- package/src/gantt/calculator.ts +1 -11
- package/src/gantt/parser.ts +17 -17
- package/src/gantt/renderer.ts +9 -6
- package/src/graph/flowchart-parser.ts +19 -85
- package/src/graph/flowchart-renderer.ts +4 -9
- package/src/graph/layout.ts +0 -2
- package/src/graph/state-parser.ts +17 -62
- package/src/graph/state-renderer.ts +4 -9
- package/src/index.ts +17 -1
- package/src/infra/parser.ts +40 -30
- package/src/infra/renderer.ts +9 -6
- package/src/internal.ts +9 -721
- package/src/journey-map/parser.ts +10 -3
- package/src/journey-map/renderer.ts +3 -1
- package/src/kanban/parser.ts +12 -8
- package/src/kanban/renderer.ts +3 -1
- package/src/mindmap/layout.ts +1 -1
- package/src/mindmap/parser.ts +3 -3
- package/src/mindmap/renderer.ts +2 -1
- package/src/org/parser.ts +3 -3
- package/src/org/renderer.ts +5 -4
- package/src/pert/layout.ts +1 -1
- package/src/pert/monte-carlo.ts +2 -2
- package/src/pert/parser.ts +10 -10
- package/src/pert/renderer.ts +7 -2
- package/src/pert/types.ts +1 -1
- package/src/pyramid/parser.ts +12 -0
- package/src/raci/parser.ts +44 -14
- package/src/raci/renderer.ts +3 -2
- package/src/raci/types.ts +4 -3
- package/src/ring/parser.ts +12 -0
- package/src/sequence/parser.ts +15 -9
- package/src/sequence/renderer.ts +2 -5
- package/src/sitemap/layout.ts +0 -2
- package/src/sitemap/parser.ts +12 -38
- package/src/sitemap/renderer.ts +13 -13
- package/src/sitemap/types.ts +0 -1
- package/src/tech-radar/interactive.ts +1 -1
- package/src/tech-radar/renderer.ts +6 -4
- package/src/tech-radar/types.ts +2 -0
- package/src/utils/arrows.ts +3 -28
- package/src/utils/legend-d3.ts +12 -6
- package/src/utils/legend-layout.ts +1 -1
- package/src/utils/legend-types.ts +1 -1
- package/src/utils/parsing.ts +64 -35
- package/src/utils/tag-groups.ts +109 -30
- package/src/wireframe/layout.ts +11 -7
- package/src/wireframe/parser.ts +4 -4
- package/src/wireframe/renderer.ts +5 -2
package/src/sequence/parser.ts
CHANGED
|
@@ -215,7 +215,10 @@ const IS_A_PATTERN = /^([^:]+?)\s+is\s+an?\s+(\w+)(?:\s+(.+))?$/i;
|
|
|
215
215
|
const POSITION_ONLY_PATTERN = /^([^:]+?)\s+position\s+(-?\d+)$/i;
|
|
216
216
|
|
|
217
217
|
// Colored participant declaration — e.g. "Tapin2(green)", "API(blue)"
|
|
218
|
-
|
|
218
|
+
// Scoped to recognized 11-name palette colors only (§1.5) so legitimate
|
|
219
|
+
// `funcCall(arg)` lines don't trigger the legacy-color diagnostic.
|
|
220
|
+
const COLORED_PARTICIPANT_PATTERN =
|
|
221
|
+
/^(\S+?)\((red|orange|yellow|green|blue|purple|teal|cyan|gray|black|white)\)\s*$/;
|
|
219
222
|
|
|
220
223
|
// Group heading pattern — "[Backend]", "[Backend] | t: Product"
|
|
221
224
|
// Group 1: name (no ] or | inside brackets), Group 2: color in parens, Group 3: after-bracket text
|
|
@@ -678,7 +681,7 @@ export function parseSequenceDgmo(content: string): ParsedSequenceDgmo {
|
|
|
678
681
|
if (groupColor) {
|
|
679
682
|
pushWarning(
|
|
680
683
|
lineNumber,
|
|
681
|
-
`(${groupColor}) color syntax removed from sequence diagrams — use 'tag:' groups for coloring`
|
|
684
|
+
`'(${groupColor})' parens-color syntax removed from sequence diagrams — use 'tag:' groups for coloring`
|
|
682
685
|
);
|
|
683
686
|
}
|
|
684
687
|
contentStarted = true;
|
|
@@ -765,7 +768,7 @@ export function parseSequenceDgmo(content: string): ParsedSequenceDgmo {
|
|
|
765
768
|
continue;
|
|
766
769
|
}
|
|
767
770
|
|
|
768
|
-
// Tag group entries (indented Value
|
|
771
|
+
// Tag group entries (indented Value color under tag heading)
|
|
769
772
|
// First entry is the default unless another is marked `default`
|
|
770
773
|
if (currentTagGroup && !contentStarted && measureIndent(raw) > 0) {
|
|
771
774
|
const { text: cleanEntry, isDefault } = stripDefaultModifier(trimmed);
|
|
@@ -778,7 +781,7 @@ export function parseSequenceDgmo(content: string): ParsedSequenceDgmo {
|
|
|
778
781
|
if (!color) {
|
|
779
782
|
pushError(
|
|
780
783
|
lineNumber,
|
|
781
|
-
`Expected 'Value
|
|
784
|
+
`Expected 'Value color' in tag group '${currentTagGroup.name}'`
|
|
782
785
|
);
|
|
783
786
|
continue;
|
|
784
787
|
}
|
|
@@ -807,11 +810,14 @@ export function parseSequenceDgmo(content: string): ParsedSequenceDgmo {
|
|
|
807
810
|
blockStack.pop();
|
|
808
811
|
}
|
|
809
812
|
const labelRaw = sectionMatch[1].trim();
|
|
810
|
-
|
|
813
|
+
// Scoped to recognized 11-name palette colors only (§1.5).
|
|
814
|
+
const colorMatch = labelRaw.match(
|
|
815
|
+
/^(.+?)\((red|orange|yellow|green|blue|purple|teal|cyan|gray|black|white)\)$/
|
|
816
|
+
);
|
|
811
817
|
if (colorMatch) {
|
|
812
818
|
pushWarning(
|
|
813
819
|
lineNumber,
|
|
814
|
-
`(${colorMatch[2]
|
|
820
|
+
`'(${colorMatch[2]})' parens-color syntax removed from sequence diagrams — use 'tag:' groups for coloring`
|
|
815
821
|
);
|
|
816
822
|
}
|
|
817
823
|
contentStarted = true;
|
|
@@ -1016,8 +1022,8 @@ export function parseSequenceDgmo(content: string): ParsedSequenceDgmo {
|
|
|
1016
1022
|
continue;
|
|
1017
1023
|
}
|
|
1018
1024
|
|
|
1019
|
-
//
|
|
1020
|
-
//
|
|
1025
|
+
// Legacy `Name(color)` participant declaration at any level (§1.5 hard
|
|
1026
|
+
// break). Scoped to the 11-name palette so `funcCall(arg)` doesn't trip.
|
|
1021
1027
|
const { core: colorCore, meta: colorMeta } = splitPipe(trimmed, lineNumber);
|
|
1022
1028
|
const coloredMatch = colorCore.match(COLORED_PARTICIPANT_PATTERN);
|
|
1023
1029
|
if (coloredMatch && !ARROW_PATTERN.test(colorCore)) {
|
|
@@ -1025,7 +1031,7 @@ export function parseSequenceDgmo(content: string): ParsedSequenceDgmo {
|
|
|
1025
1031
|
const color = coloredMatch[2].trim();
|
|
1026
1032
|
pushError(
|
|
1027
1033
|
lineNumber,
|
|
1028
|
-
`'${id}(${color})' syntax is no longer supported — use 'tag:' groups for coloring`
|
|
1034
|
+
`'${id}(${color})' parens-color syntax is no longer supported — use 'tag:' groups for coloring`
|
|
1029
1035
|
);
|
|
1030
1036
|
contentStarted = true;
|
|
1031
1037
|
const key = addParticipant(id, lineNumber, { metadata: colorMeta });
|
package/src/sequence/renderer.ts
CHANGED
|
@@ -949,9 +949,6 @@ export function renderSequenceDiagram(
|
|
|
949
949
|
const messages = collapsed ? collapsed.messages : parsed.messages;
|
|
950
950
|
const elements = collapsed ? collapsed.elements : parsed.elements;
|
|
951
951
|
const groups = collapsed ? collapsed.groups : parsed.groups;
|
|
952
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
953
|
-
const collapsedGroupIds = collapsed?.collapsedGroupIds ?? new Map();
|
|
954
|
-
|
|
955
952
|
const collapsedSections = options?.collapsedSections;
|
|
956
953
|
|
|
957
954
|
const sourceParticipants = collapsed
|
|
@@ -1006,7 +1003,7 @@ export function renderSequenceDiagram(
|
|
|
1006
1003
|
const charsForWidth = (maxW: number): number =>
|
|
1007
1004
|
Math.floor((maxW - NOTE_PAD_H * 2 - NOTE_FOLD) / NOTE_CHAR_W);
|
|
1008
1005
|
|
|
1009
|
-
const activationsOff = parsedOptions
|
|
1006
|
+
const activationsOff = parsedOptions['activations']?.toLowerCase() === 'off';
|
|
1010
1007
|
|
|
1011
1008
|
// Tag resolution — shared utility handles priority chain:
|
|
1012
1009
|
// programmatic override → diagram-level active-tag → auto-activate first group
|
|
@@ -2765,7 +2762,7 @@ export function renderSequenceDiagram(
|
|
|
2765
2762
|
const legendConfig: LegendConfig = {
|
|
2766
2763
|
groups: resolvedGroups,
|
|
2767
2764
|
position: { placement: 'top-center', titleRelation: 'below-title' },
|
|
2768
|
-
mode: '
|
|
2765
|
+
mode: 'preview',
|
|
2769
2766
|
};
|
|
2770
2767
|
const legendState: LegendState = {
|
|
2771
2768
|
activeGroup: activeTagGroup ?? null,
|
package/src/sitemap/layout.ts
CHANGED
|
@@ -41,7 +41,6 @@ export interface SitemapLayoutEdge {
|
|
|
41
41
|
targetId: string;
|
|
42
42
|
points: { x: number; y: number }[];
|
|
43
43
|
label?: string;
|
|
44
|
-
color?: string;
|
|
45
44
|
lineNumber: number;
|
|
46
45
|
/** True for edges deferred from dagre (container endpoints) — use linear curve */
|
|
47
46
|
deferred?: boolean;
|
|
@@ -652,7 +651,6 @@ export function layoutSitemap(
|
|
|
652
651
|
targetId: edge.targetId,
|
|
653
652
|
points,
|
|
654
653
|
label: edge.label,
|
|
655
|
-
color: edge.color,
|
|
656
654
|
lineNumber: edge.lineNumber,
|
|
657
655
|
deferred: deferredSet.has(i) || undefined,
|
|
658
656
|
});
|
package/src/sitemap/parser.ts
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
// ============================================================
|
|
4
4
|
|
|
5
5
|
import type { PaletteColors } from '../palettes';
|
|
6
|
-
import { resolveColorWithDiagnostic } from '../colors';
|
|
7
6
|
import type { DgmoError } from '../diagnostics';
|
|
8
7
|
import { makeDgmoError, formatDgmoError, suggest } from '../diagnostics';
|
|
9
8
|
import { normalizeName } from '../utils/name-normalize';
|
|
@@ -20,7 +19,6 @@ import {
|
|
|
20
19
|
measureIndent,
|
|
21
20
|
extractColor,
|
|
22
21
|
parsePipeMetadata,
|
|
23
|
-
inferArrowColor,
|
|
24
22
|
MULTIPLE_PIPE_ERROR,
|
|
25
23
|
parseFirstLine,
|
|
26
24
|
OPTION_NOCOLON_RE,
|
|
@@ -39,10 +37,11 @@ const CONTAINER_RE = /^\[([^\]]+)\]\s*(?:\|\s*(.+))?$/;
|
|
|
39
37
|
const METADATA_RE = /^([^:]+):\s*(.+)$/;
|
|
40
38
|
|
|
41
39
|
/**
|
|
42
|
-
* Arrow line: `-label
|
|
43
|
-
*
|
|
40
|
+
* Arrow line: `-label->` or `->` followed by target label.
|
|
41
|
+
* Edges have no color slot (spec §1.7).
|
|
42
|
+
* Captures: [1] label, [2] target
|
|
44
43
|
*/
|
|
45
|
-
const ARROW_RE = /^-([
|
|
44
|
+
const ARROW_RE = /^-([^>][^>]*?)?\s*->\s*(.+)$/;
|
|
46
45
|
const BARE_ARROW_RE = /^->\s*(.+)$/;
|
|
47
46
|
|
|
48
47
|
// ============================================================
|
|
@@ -51,12 +50,11 @@ const BARE_ARROW_RE = /^->\s*(.+)$/;
|
|
|
51
50
|
|
|
52
51
|
function parseArrowLine(
|
|
53
52
|
trimmed: string,
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
_palette: PaletteColors | undefined,
|
|
54
|
+
_lineNumber: number,
|
|
55
|
+
_diagnostics: DgmoError[]
|
|
57
56
|
): {
|
|
58
57
|
label?: string;
|
|
59
|
-
color?: string;
|
|
60
58
|
target: string;
|
|
61
59
|
targetIsGroup: boolean;
|
|
62
60
|
} | null {
|
|
@@ -71,33 +69,14 @@ function parseArrowLine(
|
|
|
71
69
|
};
|
|
72
70
|
}
|
|
73
71
|
|
|
74
|
-
// Labeled
|
|
72
|
+
// Labeled arrow: -label-> Target
|
|
75
73
|
const arrowMatch = trimmed.match(ARROW_RE);
|
|
76
74
|
if (arrowMatch) {
|
|
77
75
|
const label = arrowMatch[1]?.trim() || undefined;
|
|
78
|
-
|
|
79
|
-
? resolveColorWithDiagnostic(
|
|
80
|
-
arrowMatch[2].trim(),
|
|
81
|
-
lineNumber,
|
|
82
|
-
diagnostics,
|
|
83
|
-
palette
|
|
84
|
-
)
|
|
85
|
-
: undefined;
|
|
86
|
-
if (label && !color) {
|
|
87
|
-
const inferred = inferArrowColor(label);
|
|
88
|
-
if (inferred)
|
|
89
|
-
color = resolveColorWithDiagnostic(
|
|
90
|
-
inferred,
|
|
91
|
-
lineNumber,
|
|
92
|
-
diagnostics,
|
|
93
|
-
palette
|
|
94
|
-
);
|
|
95
|
-
}
|
|
96
|
-
const rawTarget = arrowMatch[3].trim();
|
|
76
|
+
const rawTarget = arrowMatch[2].trim();
|
|
97
77
|
const groupMatch = rawTarget.match(/^\[(.+)\]$/);
|
|
98
78
|
return {
|
|
99
79
|
label,
|
|
100
|
-
color,
|
|
101
80
|
target: groupMatch ? groupMatch[1].trim() : rawTarget,
|
|
102
81
|
targetIsGroup: !!groupMatch,
|
|
103
82
|
};
|
|
@@ -216,7 +195,6 @@ export function parseSitemap(
|
|
|
216
195
|
targetLabel: string;
|
|
217
196
|
targetIsGroup: boolean;
|
|
218
197
|
label?: string;
|
|
219
|
-
color?: string;
|
|
220
198
|
lineNumber: number;
|
|
221
199
|
}[] = [];
|
|
222
200
|
|
|
@@ -309,7 +287,7 @@ export function parseSitemap(
|
|
|
309
287
|
}
|
|
310
288
|
}
|
|
311
289
|
|
|
312
|
-
// Tag group entries (indented Value
|
|
290
|
+
// Tag group entries (indented `Value color` under tag heading; §1.5)
|
|
313
291
|
// First entry is the default unless another is marked `default`
|
|
314
292
|
if (currentTagGroup && !contentStarted) {
|
|
315
293
|
const indent = measureIndent(line);
|
|
@@ -319,7 +297,7 @@ export function parseSitemap(
|
|
|
319
297
|
if (!color) {
|
|
320
298
|
pushError(
|
|
321
299
|
lineNumber,
|
|
322
|
-
`Expected 'Value
|
|
300
|
+
`Expected 'Value color' in tag group '${currentTagGroup.name}'`
|
|
323
301
|
);
|
|
324
302
|
continue;
|
|
325
303
|
}
|
|
@@ -365,7 +343,6 @@ export function parseSitemap(
|
|
|
365
343
|
targetLabel: arrowInfo.target,
|
|
366
344
|
targetIsGroup: arrowInfo.targetIsGroup,
|
|
367
345
|
label: arrowInfo.label,
|
|
368
|
-
color: arrowInfo.color,
|
|
369
346
|
lineNumber,
|
|
370
347
|
});
|
|
371
348
|
}
|
|
@@ -486,7 +463,6 @@ export function parseSitemap(
|
|
|
486
463
|
sourceId: arrow.sourceNode.id,
|
|
487
464
|
targetId: aliasHit,
|
|
488
465
|
label: arrow.label,
|
|
489
|
-
color: arrow.color,
|
|
490
466
|
lineNumber: arrow.lineNumber,
|
|
491
467
|
});
|
|
492
468
|
continue;
|
|
@@ -508,7 +484,6 @@ export function parseSitemap(
|
|
|
508
484
|
sourceId: arrow.sourceNode.id,
|
|
509
485
|
targetId: targetContainer.id,
|
|
510
486
|
label: arrow.label,
|
|
511
|
-
color: arrow.color,
|
|
512
487
|
lineNumber: arrow.lineNumber,
|
|
513
488
|
});
|
|
514
489
|
} else {
|
|
@@ -526,7 +501,6 @@ export function parseSitemap(
|
|
|
526
501
|
sourceId: arrow.sourceNode.id,
|
|
527
502
|
targetId: targetNode.id,
|
|
528
503
|
label: arrow.label,
|
|
529
|
-
color: arrow.color,
|
|
530
504
|
lineNumber: arrow.lineNumber,
|
|
531
505
|
});
|
|
532
506
|
}
|
|
@@ -566,7 +540,7 @@ export function parseSitemap(
|
|
|
566
540
|
function parseNodeLabel(
|
|
567
541
|
trimmed: string,
|
|
568
542
|
lineNumber: number,
|
|
569
|
-
|
|
543
|
+
_palette: PaletteColors | undefined,
|
|
570
544
|
counter: number,
|
|
571
545
|
metaAliasMap: Map<string, string> = new Map(),
|
|
572
546
|
warnFn?: (line: number, msg: string) => void,
|
package/src/sitemap/renderer.ts
CHANGED
|
@@ -116,7 +116,8 @@ export function renderSitemap(
|
|
|
116
116
|
onClickItem?: (lineNumber: number) => void,
|
|
117
117
|
exportDims?: { width?: number; height?: number },
|
|
118
118
|
activeTagGroup?: string | null,
|
|
119
|
-
hiddenAttributes?: Set<string
|
|
119
|
+
hiddenAttributes?: Set<string>,
|
|
120
|
+
exportMode?: boolean
|
|
120
121
|
): void {
|
|
121
122
|
// Clear existing content
|
|
122
123
|
d3Selection.select(container).selectAll(':not([data-d3-tooltip])').remove();
|
|
@@ -184,11 +185,9 @@ export function renderSitemap(
|
|
|
184
185
|
.attr('points', `0,0 ${ARROWHEAD_W},${ARROWHEAD_H / 2} 0,${ARROWHEAD_H}`)
|
|
185
186
|
.attr('fill', palette.textMuted);
|
|
186
187
|
|
|
187
|
-
//
|
|
188
|
+
// Edges have no color slot (spec §1.7); keep empty set so the marker-setup
|
|
189
|
+
// loop is a no-op but the symbol stays available for future color sources.
|
|
188
190
|
const edgeColors = new Set<string>();
|
|
189
|
-
for (const edge of layout.edges) {
|
|
190
|
-
if (edge.color) edgeColors.add(edge.color);
|
|
191
|
-
}
|
|
192
191
|
for (const color of edgeColors) {
|
|
193
192
|
const id = `sm-arrow-${color.replace('#', '')}`;
|
|
194
193
|
defs
|
|
@@ -379,10 +378,8 @@ export function renderSitemap(
|
|
|
379
378
|
.attr('class', 'sitemap-edge-group')
|
|
380
379
|
.attr('data-line-number', String(edge.lineNumber));
|
|
381
380
|
|
|
382
|
-
const edgeColor =
|
|
383
|
-
const markerId =
|
|
384
|
-
? `sm-arrow-${edge.color.replace('#', '')}`
|
|
385
|
-
: 'sm-arrow';
|
|
381
|
+
const edgeColor = palette.textMuted;
|
|
382
|
+
const markerId = 'sm-arrow';
|
|
386
383
|
|
|
387
384
|
const gen = edge.deferred ? lineGeneratorLinear : lineGenerator;
|
|
388
385
|
const pathD = gen(edge.points);
|
|
@@ -602,7 +599,8 @@ export function renderSitemap(
|
|
|
602
599
|
isDark,
|
|
603
600
|
activeTagGroup,
|
|
604
601
|
undefined,
|
|
605
|
-
hiddenAttributes
|
|
602
|
+
hiddenAttributes,
|
|
603
|
+
exportMode
|
|
606
604
|
);
|
|
607
605
|
}
|
|
608
606
|
|
|
@@ -647,7 +645,8 @@ export function renderSitemap(
|
|
|
647
645
|
isDark,
|
|
648
646
|
activeTagGroup,
|
|
649
647
|
width,
|
|
650
|
-
hiddenAttributes
|
|
648
|
+
hiddenAttributes,
|
|
649
|
+
exportMode
|
|
651
650
|
);
|
|
652
651
|
}
|
|
653
652
|
}
|
|
@@ -663,7 +662,8 @@ function renderLegend(
|
|
|
663
662
|
isDark: boolean,
|
|
664
663
|
activeTagGroup?: string | null,
|
|
665
664
|
fixedWidth?: number,
|
|
666
|
-
hiddenAttributes?: Set<string
|
|
665
|
+
hiddenAttributes?: Set<string>,
|
|
666
|
+
exportMode?: boolean
|
|
667
667
|
): void {
|
|
668
668
|
if (legendGroups.length === 0) return;
|
|
669
669
|
|
|
@@ -678,7 +678,7 @@ function renderLegend(
|
|
|
678
678
|
const legendConfig: LegendConfig = {
|
|
679
679
|
groups,
|
|
680
680
|
position: { placement: 'top-center', titleRelation: 'below-title' },
|
|
681
|
-
mode: '
|
|
681
|
+
mode: exportMode ? 'export' : 'preview',
|
|
682
682
|
capsulePillAddonWidth: eyeAddonWidth,
|
|
683
683
|
};
|
|
684
684
|
const legendState: LegendState = { activeGroup: activeTagGroup ?? null };
|
package/src/sitemap/types.ts
CHANGED
|
@@ -163,7 +163,7 @@ export function renderTechRadar(
|
|
|
163
163
|
},
|
|
164
164
|
],
|
|
165
165
|
position: { placement: 'top-center', titleRelation: 'below-title' },
|
|
166
|
-
mode: '
|
|
166
|
+
mode: options?.exportMode ? 'export' : 'preview',
|
|
167
167
|
controlsGroup: {
|
|
168
168
|
toggles: [
|
|
169
169
|
{
|
|
@@ -920,7 +920,7 @@ import type { TechRadarBlip } from './types';
|
|
|
920
920
|
|
|
921
921
|
function createBlipPopover(
|
|
922
922
|
container: HTMLElement,
|
|
923
|
-
|
|
923
|
+
_palette: PaletteColors,
|
|
924
924
|
isDark: boolean
|
|
925
925
|
): HTMLDivElement {
|
|
926
926
|
container.style.position = 'relative';
|
|
@@ -1195,7 +1195,8 @@ export function renderTechRadarForExport(
|
|
|
1195
1195
|
palette: PaletteColors,
|
|
1196
1196
|
isDark: boolean,
|
|
1197
1197
|
exportDims?: D3ExportDimensions,
|
|
1198
|
-
viewState?: CompactViewState
|
|
1198
|
+
viewState?: CompactViewState,
|
|
1199
|
+
exportMode?: boolean
|
|
1199
1200
|
): void {
|
|
1200
1201
|
renderTechRadar(
|
|
1201
1202
|
container,
|
|
@@ -1204,6 +1205,7 @@ export function renderTechRadarForExport(
|
|
|
1204
1205
|
isDark,
|
|
1205
1206
|
undefined,
|
|
1206
1207
|
exportDims,
|
|
1207
|
-
viewState
|
|
1208
|
+
viewState,
|
|
1209
|
+
{ exportMode }
|
|
1208
1210
|
);
|
|
1209
1211
|
}
|
package/src/tech-radar/types.ts
CHANGED
|
@@ -78,4 +78,6 @@ export interface TechRadarRenderOptions {
|
|
|
78
78
|
onLegendGroupToggle?: (groupName: string) => void;
|
|
79
79
|
/** Active line from the editor cursor — triggers popover/expansion for that blip. */
|
|
80
80
|
activeLine?: number | null;
|
|
81
|
+
/** True when rendering for export (PNG/SVG/PDF) — controls whether collapsed legend pills and cog are stripped. */
|
|
82
|
+
exportMode?: boolean;
|
|
81
83
|
}
|
package/src/utils/arrows.ts
CHANGED
|
@@ -22,7 +22,6 @@
|
|
|
22
22
|
|
|
23
23
|
import type { DgmoError } from '../diagnostics';
|
|
24
24
|
import { makeDgmoError } from '../diagnostics';
|
|
25
|
-
import { RECOGNIZED_COLOR_NAMES } from '../colors';
|
|
26
25
|
|
|
27
26
|
interface ParsedArrow {
|
|
28
27
|
from: string;
|
|
@@ -140,10 +139,9 @@ export interface ParseInArrowLabelResult {
|
|
|
140
139
|
*
|
|
141
140
|
* This helper is intentionally chart-agnostic: it operates on an already
|
|
142
141
|
* extracted label string, leaving each chart's existing arrow-finding
|
|
143
|
-
* tokenization in place.
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
* `matchColorParens()` from this module for the shared lookup.
|
|
142
|
+
* tokenization in place. Edges no longer have a color slot on any chart
|
|
143
|
+
* type (see spec §1.7 "Edge color is not a feature"); arrow content is
|
|
144
|
+
* pure label text.
|
|
147
145
|
*/
|
|
148
146
|
export function parseInArrowLabel(
|
|
149
147
|
rawLabel: string,
|
|
@@ -162,29 +160,6 @@ export function parseInArrowLabel(
|
|
|
162
160
|
return { label: trimmed, diagnostics };
|
|
163
161
|
}
|
|
164
162
|
|
|
165
|
-
// ============================================================
|
|
166
|
-
// matchColorParens — shared TD-11 helper for flowchart and state
|
|
167
|
-
// ============================================================
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Test whether a string matches the TD-11 color-parens form `(colorName)`
|
|
171
|
-
* where `colorName` is one of the 11 recognized palette color names from
|
|
172
|
-
* `src/colors.ts:RECOGNIZED_COLOR_NAMES`. Returns the lowercase color name
|
|
173
|
-
* on a match, or `null` on fall-through (whole string becomes a label).
|
|
174
|
-
*
|
|
175
|
-
* Used by flowchart and state parsers to keep the color-parens recognition
|
|
176
|
-
* rule in one place — do NOT re-implement the regex in chart parsers.
|
|
177
|
-
*/
|
|
178
|
-
export function matchColorParens(content: string): string | null {
|
|
179
|
-
const m = content.match(/^\(([A-Za-z]+)\)$/);
|
|
180
|
-
if (!m) return null;
|
|
181
|
-
const candidate = m[1].toLowerCase();
|
|
182
|
-
if ((RECOGNIZED_COLOR_NAMES as readonly string[]).includes(candidate)) {
|
|
183
|
-
return candidate;
|
|
184
|
-
}
|
|
185
|
-
return null;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
163
|
// Forward (call) patterns — participant names may contain spaces, so use non-greedy (.+?)
|
|
189
164
|
const SYNC_LABELED_RE = /^(.+?)\s*-(.+)->\s*(.+)$/;
|
|
190
165
|
const ASYNC_LABELED_RE = /^(.+?)\s*~(.+)~>\s*(.+)$/;
|
package/src/utils/legend-d3.ts
CHANGED
|
@@ -46,7 +46,14 @@ export function renderLegendD3(
|
|
|
46
46
|
let currentState = { ...state };
|
|
47
47
|
let currentLayout: LegendLayout;
|
|
48
48
|
|
|
49
|
-
const legendG = container
|
|
49
|
+
const legendG = container
|
|
50
|
+
.append('g')
|
|
51
|
+
.attr('class', 'dgmo-legend')
|
|
52
|
+
.attr('data-legend-title-relation', config.position.titleRelation)
|
|
53
|
+
.attr(
|
|
54
|
+
'data-legend-capsule-addon-width',
|
|
55
|
+
String(config.capsulePillAddonWidth ?? 0)
|
|
56
|
+
);
|
|
50
57
|
|
|
51
58
|
function render() {
|
|
52
59
|
currentLayout = computeLegendLayout(config, currentState, width);
|
|
@@ -270,11 +277,10 @@ function renderPill(
|
|
|
270
277
|
groupBg: string,
|
|
271
278
|
callbacks?: LegendCallbacks
|
|
272
279
|
): void {
|
|
273
|
-
// Collapsed tag-group pills
|
|
274
|
-
//
|
|
275
|
-
//
|
|
276
|
-
// pills
|
|
277
|
-
// `data-export-ignore` separately.
|
|
280
|
+
// Collapsed tag-group pills are hidden in export mode
|
|
281
|
+
// (`LegendConfig.mode === 'export'`) — the layout engine filters them
|
|
282
|
+
// in `computeLegendLayout`. See
|
|
283
|
+
// tech-spec-hide-inactive-tag-pills-in-exports.md.
|
|
278
284
|
const g = parent
|
|
279
285
|
.append('g')
|
|
280
286
|
.attr('transform', `translate(${pill.x},${pill.y})`)
|
|
@@ -235,7 +235,7 @@ export function computeLegendLayout(
|
|
|
235
235
|
containerWidth: number
|
|
236
236
|
): LegendLayout {
|
|
237
237
|
const { groups, controls: configControls, mode } = config;
|
|
238
|
-
const isExport = mode === '
|
|
238
|
+
const isExport = mode === 'export';
|
|
239
239
|
|
|
240
240
|
// Filter groups for export: only active group shown
|
|
241
241
|
const activeGroupName = state.activeGroup?.toLowerCase() ?? null;
|
|
@@ -37,7 +37,7 @@ export interface LegendPosition {
|
|
|
37
37
|
titleRelation: 'below-title' | 'inline-with-title';
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
export type LegendMode = '
|
|
40
|
+
export type LegendMode = 'preview' | 'export';
|
|
41
41
|
|
|
42
42
|
export type LegendControlExportBehavior = 'include' | 'strip' | 'static';
|
|
43
43
|
|
package/src/utils/parsing.ts
CHANGED
|
@@ -4,10 +4,18 @@
|
|
|
4
4
|
* pipe-metadata parsing.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
RECOGNIZED_COLOR_NAMES,
|
|
9
|
+
resolveColor,
|
|
10
|
+
resolveColorWithDiagnostic,
|
|
11
|
+
} from '../colors';
|
|
8
12
|
import type { DgmoError } from '../diagnostics';
|
|
9
13
|
import type { PaletteColors } from '../palettes';
|
|
10
14
|
|
|
15
|
+
const RECOGNIZED_COLOR_SET: ReadonlySet<string> = new Set(
|
|
16
|
+
RECOGNIZED_COLOR_NAMES
|
|
17
|
+
);
|
|
18
|
+
|
|
11
19
|
// ── All known chart types ────────────────────────────────────
|
|
12
20
|
/** Complete set of recognized chart type identifiers. */
|
|
13
21
|
export const ALL_CHART_TYPES = new Set([
|
|
@@ -87,27 +95,47 @@ export function measureIndent(line: string): number {
|
|
|
87
95
|
return indent;
|
|
88
96
|
}
|
|
89
97
|
|
|
90
|
-
/**
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
98
|
+
/**
|
|
99
|
+
* Trailing-token color rule (see docs/dgmo-language-spec.md §1.5).
|
|
100
|
+
*
|
|
101
|
+
* Caller contract: `label` must be a pre-split LABEL REGION — the parser is
|
|
102
|
+
* responsible for stripping structural terminators (`as <alias>`, `| pipe
|
|
103
|
+
* metadata`, numeric values, date ranges, brackets, arrow constructs) BEFORE
|
|
104
|
+
* invoking this function. The color rule operates only on what remains.
|
|
105
|
+
*
|
|
106
|
+
* Algorithm: split the label on whitespace; if the final token is exactly one
|
|
107
|
+
* of `RECOGNIZED_COLOR_NAMES` (case-sensitive, lowercase only), peel it off
|
|
108
|
+
* as color and return the rest as the label. Otherwise the entire input
|
|
109
|
+
* stays as the label, no color.
|
|
110
|
+
*
|
|
111
|
+
* Case-sensitivity is deliberate: it provides the escape hatch (`Red`,
|
|
112
|
+
* `Yellow`, `Green` stay as labels — useful for traffic-light tag groups).
|
|
113
|
+
*
|
|
114
|
+
* Returns `{ label, color? }` where `color` is the palette-resolved hex string
|
|
115
|
+
* (or undefined if no color word matched).
|
|
116
|
+
*/
|
|
94
117
|
export function extractColor(
|
|
95
118
|
label: string,
|
|
96
119
|
palette?: PaletteColors,
|
|
97
120
|
diagnostics?: DgmoError[],
|
|
98
121
|
line?: number
|
|
99
122
|
): { label: string; color?: string } {
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
123
|
+
const lastSpaceIdx = Math.max(
|
|
124
|
+
label.lastIndexOf(' '),
|
|
125
|
+
label.lastIndexOf('\t')
|
|
126
|
+
);
|
|
127
|
+
if (lastSpaceIdx < 0) return { label };
|
|
128
|
+
const trailing = label.substring(lastSpaceIdx + 1);
|
|
129
|
+
// Case-sensitive lowercase match against the closed 11-name palette.
|
|
130
|
+
if (!RECOGNIZED_COLOR_SET.has(trailing)) return { label };
|
|
103
131
|
let color: string | undefined;
|
|
104
132
|
if (diagnostics && line !== undefined) {
|
|
105
|
-
color = resolveColorWithDiagnostic(
|
|
133
|
+
color = resolveColorWithDiagnostic(trailing, line, diagnostics, palette);
|
|
106
134
|
} else {
|
|
107
|
-
color = resolveColor(
|
|
135
|
+
color = resolveColor(trailing, palette) ?? undefined;
|
|
108
136
|
}
|
|
109
137
|
return {
|
|
110
|
-
label: label.substring(0,
|
|
138
|
+
label: label.substring(0, lastSpaceIdx).trimEnd(),
|
|
111
139
|
color,
|
|
112
140
|
};
|
|
113
141
|
}
|
|
@@ -457,31 +485,32 @@ export function parseSeriesNames(
|
|
|
457
485
|
}
|
|
458
486
|
|
|
459
487
|
/**
|
|
460
|
-
*
|
|
461
|
-
*
|
|
462
|
-
*
|
|
488
|
+
* Peel a trailing recognized color name from a label region, returning the
|
|
489
|
+
* raw color name (not a resolved hex). Used by chart types that pair the
|
|
490
|
+
* universal trailing-token shortcut with their own pipe-metadata `color: …`
|
|
491
|
+
* long form (cycle, pyramid, ring, raci, boxes-and-lines).
|
|
492
|
+
*
|
|
493
|
+
* Caller contract: `label` must already have pipe metadata stripped — this
|
|
494
|
+
* function operates only on the label region.
|
|
495
|
+
*
|
|
496
|
+
* Returns `{ label, colorName? }`. If the trailing token is not a recognized
|
|
497
|
+
* lowercase color, returns the original label and `colorName: undefined`.
|
|
463
498
|
*/
|
|
464
|
-
export function
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
)
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
lower === 'false'
|
|
480
|
-
)
|
|
481
|
-
return 'red';
|
|
482
|
-
// Orange: uncertain/warning
|
|
483
|
-
if (lower === 'maybe' || lower === 'warning') return 'orange';
|
|
484
|
-
return undefined;
|
|
499
|
+
export function peelTrailingColorName(label: string): {
|
|
500
|
+
label: string;
|
|
501
|
+
colorName?: string;
|
|
502
|
+
} {
|
|
503
|
+
const lastSpaceIdx = Math.max(
|
|
504
|
+
label.lastIndexOf(' '),
|
|
505
|
+
label.lastIndexOf('\t')
|
|
506
|
+
);
|
|
507
|
+
if (lastSpaceIdx < 0) return { label };
|
|
508
|
+
const trailing = label.substring(lastSpaceIdx + 1);
|
|
509
|
+
if (!RECOGNIZED_COLOR_SET.has(trailing)) return { label };
|
|
510
|
+
return {
|
|
511
|
+
label: label.substring(0, lastSpaceIdx).trimEnd(),
|
|
512
|
+
colorName: trailing,
|
|
513
|
+
};
|
|
485
514
|
}
|
|
486
515
|
|
|
487
516
|
/** Error message for multiple pipes on a single line. */
|