@diagrammo/dgmo 0.8.20 → 0.8.22
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/AGENTS.md +2 -1
- package/README.md +1 -0
- package/dist/cli.cjs +142 -90
- package/dist/editor.cjs +30 -4
- package/dist/editor.cjs.map +1 -1
- package/dist/editor.js +30 -4
- package/dist/editor.js.map +1 -1
- package/dist/highlight.cjs +25 -3
- package/dist/highlight.cjs.map +1 -1
- package/dist/highlight.js +25 -3
- package/dist/highlight.js.map +1 -1
- package/dist/index.cjs +21201 -12886
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +646 -89
- package/dist/index.d.ts +646 -89
- package/dist/index.js +21178 -12889
- package/dist/index.js.map +1 -1
- package/docs/guide/chart-mindmap.md +198 -0
- package/docs/guide/chart-sequence.md +23 -1
- package/docs/guide/chart-sitemap.md +18 -1
- package/docs/guide/chart-tech-radar.md +219 -0
- package/docs/guide/chart-wireframe.md +100 -0
- package/docs/guide/index.md +8 -0
- package/docs/guide/registry.json +1 -0
- package/docs/language-reference.md +249 -4
- package/gallery/fixtures/boxes-and-lines.dgmo +10 -3
- package/gallery/fixtures/c4-full.dgmo +2 -2
- package/gallery/fixtures/cycle/ooda-loop.dgmo +25 -0
- package/gallery/fixtures/cycle/pdca-circle-nodes.dgmo +12 -0
- package/gallery/fixtures/cycle/pdca-minimal.dgmo +6 -0
- package/gallery/fixtures/cycle/sprint-cycle-span.dgmo +17 -0
- package/gallery/fixtures/gantt-full.dgmo +2 -2
- package/gallery/fixtures/gantt.dgmo +2 -2
- package/gallery/fixtures/infra-full.dgmo +2 -2
- package/gallery/fixtures/infra.dgmo +1 -1
- package/gallery/fixtures/sequence-tags-protocols.dgmo +2 -2
- package/gallery/fixtures/sequence-tags.dgmo +2 -2
- package/gallery/fixtures/tech-radar-dense.dgmo +77 -0
- package/gallery/fixtures/tech-radar.dgmo +36 -0
- package/gallery/fixtures/timeline.dgmo +1 -1
- package/package.json +1 -1
- package/src/boxes-and-lines/collapse.ts +21 -3
- package/src/boxes-and-lines/layout.ts +360 -42
- package/src/boxes-and-lines/parser.ts +94 -11
- package/src/boxes-and-lines/renderer.ts +371 -114
- package/src/boxes-and-lines/types.ts +2 -1
- package/src/c4/layout.ts +8 -8
- package/src/c4/parser.ts +35 -2
- package/src/c4/renderer.ts +19 -3
- package/src/c4/types.ts +1 -0
- package/src/chart.ts +14 -7
- package/src/completion.ts +253 -0
- package/src/cycle/layout.ts +732 -0
- package/src/cycle/parser.ts +352 -0
- package/src/cycle/renderer.ts +539 -0
- package/src/cycle/types.ts +77 -0
- package/src/d3.ts +240 -40
- package/src/dgmo-router.ts +15 -0
- package/src/echarts.ts +7 -4
- package/src/editor/dgmo.grammar +5 -1
- package/src/editor/dgmo.grammar.js +1 -1
- package/src/editor/keywords.ts +26 -0
- package/src/gantt/parser.ts +2 -8
- package/src/graph/flowchart-parser.ts +15 -21
- package/src/graph/layout.ts +73 -9
- package/src/graph/state-collapse.ts +78 -0
- package/src/graph/state-parser.ts +5 -10
- package/src/graph/state-renderer.ts +139 -34
- package/src/index.ts +78 -0
- package/src/infra/layout.ts +218 -74
- package/src/infra/parser.ts +30 -6
- package/src/infra/renderer.ts +14 -8
- package/src/infra/types.ts +10 -3
- package/src/journey-map/layout.ts +386 -0
- package/src/journey-map/parser.ts +540 -0
- package/src/journey-map/renderer.ts +1456 -0
- package/src/journey-map/types.ts +47 -0
- package/src/kanban/parser.ts +3 -10
- package/src/kanban/renderer.ts +325 -63
- package/src/mindmap/collapse.ts +88 -0
- package/src/mindmap/layout.ts +605 -0
- package/src/mindmap/parser.ts +373 -0
- package/src/mindmap/renderer.ts +544 -0
- package/src/mindmap/text-wrap.ts +217 -0
- package/src/mindmap/types.ts +55 -0
- package/src/org/parser.ts +2 -6
- package/src/render.ts +18 -21
- package/src/sequence/renderer.ts +273 -56
- package/src/sharing.ts +3 -0
- package/src/sitemap/layout.ts +56 -18
- package/src/sitemap/parser.ts +26 -17
- package/src/sitemap/renderer.ts +34 -0
- package/src/sitemap/types.ts +1 -0
- package/src/tech-radar/index.ts +14 -0
- package/src/tech-radar/interactive.ts +1058 -0
- package/src/tech-radar/layout.ts +190 -0
- package/src/tech-radar/parser.ts +385 -0
- package/src/tech-radar/renderer.ts +1159 -0
- package/src/tech-radar/shared.ts +187 -0
- package/src/tech-radar/types.ts +81 -0
- package/src/utils/description-helpers.ts +33 -0
- package/src/utils/export-container.ts +3 -2
- package/src/utils/legend-d3.ts +1 -0
- package/src/utils/legend-layout.ts +5 -3
- package/src/utils/parsing.ts +48 -7
- package/src/utils/tag-groups.ts +46 -60
- package/src/wireframe/layout.ts +460 -0
- package/src/wireframe/parser.ts +956 -0
- package/src/wireframe/renderer.ts +1293 -0
- package/src/wireframe/types.ts +110 -0
package/src/d3.ts
CHANGED
|
@@ -19,7 +19,9 @@ export type VisualizationType =
|
|
|
19
19
|
| 'timeline'
|
|
20
20
|
| 'venn'
|
|
21
21
|
| 'quadrant'
|
|
22
|
-
| 'sequence'
|
|
22
|
+
| 'sequence'
|
|
23
|
+
| 'tech-radar'
|
|
24
|
+
| 'cycle';
|
|
23
25
|
|
|
24
26
|
interface D3DataItem {
|
|
25
27
|
label: string;
|
|
@@ -184,6 +186,7 @@ import { makeDgmoError, formatDgmoError, suggest } from './diagnostics';
|
|
|
184
186
|
import {
|
|
185
187
|
collectIndentedValues,
|
|
186
188
|
extractColor,
|
|
189
|
+
normalizeNumericToken,
|
|
187
190
|
parseFirstLine,
|
|
188
191
|
parsePipeMetadata,
|
|
189
192
|
MULTIPLE_PIPE_ERROR,
|
|
@@ -632,7 +635,7 @@ export function parseVisualization(
|
|
|
632
635
|
// Arc link line: source -> target(color) weight
|
|
633
636
|
if (result.type === 'arc') {
|
|
634
637
|
const linkMatch = line.match(
|
|
635
|
-
/^(.+?)\s*->\s*(.+?)(?:\(([^)]+)\))?\s*(?:\s+(\d+(
|
|
638
|
+
/^(.+?)\s*->\s*(.+?)(?:\(([^)]+)\))?\s*(?:\s+(-?[\d,_]+(?:\.[\d]+)?))?$/
|
|
636
639
|
);
|
|
637
640
|
if (linkMatch) {
|
|
638
641
|
const source = linkMatch[1].trim();
|
|
@@ -648,7 +651,9 @@ export function parseVisualization(
|
|
|
648
651
|
result.links.push({
|
|
649
652
|
source,
|
|
650
653
|
target,
|
|
651
|
-
value: linkMatch[4]
|
|
654
|
+
value: linkMatch[4]
|
|
655
|
+
? parseFloat(normalizeNumericToken(linkMatch[4]) ?? linkMatch[4])
|
|
656
|
+
: 1,
|
|
652
657
|
color: linkColor,
|
|
653
658
|
lineNumber,
|
|
654
659
|
});
|
|
@@ -1028,7 +1033,7 @@ export function parseVisualization(
|
|
|
1028
1033
|
|
|
1029
1034
|
// Data points: Label x, y OR Label x y
|
|
1030
1035
|
const pointMatch = line.match(
|
|
1031
|
-
/^(.+?)\s+([0-9]
|
|
1036
|
+
/^(.+?)\s+(-?[0-9][0-9,_]*(?:\.[0-9]+)?)\s*[,\s]\s*(-?[0-9][0-9,_]*(?:\.[0-9]+)?)\s*$/
|
|
1032
1037
|
);
|
|
1033
1038
|
if (pointMatch) {
|
|
1034
1039
|
const label = pointMatch[1].trim();
|
|
@@ -1042,8 +1047,12 @@ export function parseVisualization(
|
|
|
1042
1047
|
) {
|
|
1043
1048
|
result.quadrantPoints.push({
|
|
1044
1049
|
label,
|
|
1045
|
-
x: parseFloat(
|
|
1046
|
-
|
|
1050
|
+
x: parseFloat(
|
|
1051
|
+
normalizeNumericToken(pointMatch[2]) ?? pointMatch[2]
|
|
1052
|
+
),
|
|
1053
|
+
y: parseFloat(
|
|
1054
|
+
normalizeNumericToken(pointMatch[3]) ?? pointMatch[3]
|
|
1055
|
+
),
|
|
1047
1056
|
lineNumber,
|
|
1048
1057
|
});
|
|
1049
1058
|
}
|
|
@@ -1201,7 +1210,8 @@ export function parseVisualization(
|
|
|
1201
1210
|
// Scan from right, capped at P values
|
|
1202
1211
|
let rightIdx = tokens.length - 1;
|
|
1203
1212
|
while (rightIdx >= 0 && values.length < P) {
|
|
1204
|
-
const raw =
|
|
1213
|
+
const raw =
|
|
1214
|
+
normalizeNumericToken(tokens[rightIdx]) ?? tokens[rightIdx];
|
|
1205
1215
|
const num = parseFloat(raw);
|
|
1206
1216
|
if (!isNaN(num) && /^-?\d/.test(raw)) {
|
|
1207
1217
|
values.unshift(num);
|
|
@@ -1385,8 +1395,11 @@ export function parseVisualization(
|
|
|
1385
1395
|
} else if (colonIndex === -1) {
|
|
1386
1396
|
// Try "word weight" or "multi-word-label weight" space-separated format
|
|
1387
1397
|
const lastSpace = line.lastIndexOf(' ');
|
|
1398
|
+
const rawWeight = lastSpace >= 0 ? line.substring(lastSpace + 1) : '';
|
|
1388
1399
|
const maybeWeight =
|
|
1389
|
-
lastSpace >= 0
|
|
1400
|
+
lastSpace >= 0
|
|
1401
|
+
? parseFloat(normalizeNumericToken(rawWeight) ?? rawWeight)
|
|
1402
|
+
: NaN;
|
|
1390
1403
|
if (lastSpace >= 0 && !isNaN(maybeWeight) && maybeWeight > 0) {
|
|
1391
1404
|
result.words.push({
|
|
1392
1405
|
text: line.substring(0, lastSpace).trim(),
|
|
@@ -6492,12 +6505,7 @@ export async function renderForExport(
|
|
|
6492
6505
|
content: string,
|
|
6493
6506
|
theme: 'light' | 'dark' | 'transparent',
|
|
6494
6507
|
palette?: PaletteColors,
|
|
6495
|
-
|
|
6496
|
-
collapsedNodes?: Set<string>;
|
|
6497
|
-
activeTagGroup?: string | null;
|
|
6498
|
-
hiddenAttributes?: Set<string>;
|
|
6499
|
-
swimlaneTagGroup?: string | null;
|
|
6500
|
-
},
|
|
6508
|
+
viewState?: import('./sharing').CompactViewState,
|
|
6501
6509
|
options?: {
|
|
6502
6510
|
c4Level?: 'context' | 'containers' | 'components' | 'deployment';
|
|
6503
6511
|
c4System?: string;
|
|
@@ -6521,14 +6529,14 @@ export async function renderForExport(
|
|
|
6521
6529
|
const orgParsed = parseOrg(content, effectivePalette);
|
|
6522
6530
|
if (orgParsed.error) return '';
|
|
6523
6531
|
|
|
6524
|
-
// Apply interactive collapse state when provided
|
|
6525
|
-
const collapsedNodes =
|
|
6532
|
+
// Apply interactive collapse state when provided (read from unified viewState)
|
|
6533
|
+
const collapsedNodes = viewState?.cg ? new Set(viewState.cg) : undefined;
|
|
6526
6534
|
const activeTagGroup = resolveActiveTagGroup(
|
|
6527
6535
|
orgParsed.tagGroups,
|
|
6528
6536
|
orgParsed.options['active-tag'],
|
|
6529
|
-
|
|
6537
|
+
viewState?.tag ?? options?.tagGroup
|
|
6530
6538
|
);
|
|
6531
|
-
const hiddenAttributes =
|
|
6539
|
+
const hiddenAttributes = viewState?.ha ? new Set(viewState.ha) : undefined;
|
|
6532
6540
|
|
|
6533
6541
|
const { parsed: effectiveParsed, hiddenCounts } =
|
|
6534
6542
|
collapsedNodes && collapsedNodes.size > 0
|
|
@@ -6575,14 +6583,14 @@ export async function renderForExport(
|
|
|
6575
6583
|
const sitemapParsed = parseSitemap(content, effectivePalette);
|
|
6576
6584
|
if (sitemapParsed.error || sitemapParsed.roots.length === 0) return '';
|
|
6577
6585
|
|
|
6578
|
-
// Apply interactive collapse state when provided
|
|
6579
|
-
const collapsedNodes =
|
|
6586
|
+
// Apply interactive collapse state when provided (read from unified viewState)
|
|
6587
|
+
const collapsedNodes = viewState?.cg ? new Set(viewState.cg) : undefined;
|
|
6580
6588
|
const activeTagGroup = resolveActiveTagGroup(
|
|
6581
6589
|
sitemapParsed.tagGroups,
|
|
6582
6590
|
sitemapParsed.options['active-tag'],
|
|
6583
|
-
|
|
6591
|
+
viewState?.tag ?? options?.tagGroup
|
|
6584
6592
|
);
|
|
6585
|
-
const hiddenAttributes =
|
|
6593
|
+
const hiddenAttributes = viewState?.ha ? new Set(viewState.ha) : undefined;
|
|
6586
6594
|
|
|
6587
6595
|
const { parsed: effectiveParsed, hiddenCounts } =
|
|
6588
6596
|
collapsedNodes && collapsedNodes.size > 0
|
|
@@ -6635,8 +6643,12 @@ export async function renderForExport(
|
|
|
6635
6643
|
activeTagGroup: resolveActiveTagGroup(
|
|
6636
6644
|
kanbanParsed.tagGroups,
|
|
6637
6645
|
kanbanParsed.options['active-tag'],
|
|
6638
|
-
options?.tagGroup
|
|
6646
|
+
viewState?.tag ?? options?.tagGroup
|
|
6639
6647
|
),
|
|
6648
|
+
currentSwimlaneGroup: viewState?.swim ?? null,
|
|
6649
|
+
collapsedLanes: viewState?.cl ? new Set(viewState.cl) : undefined,
|
|
6650
|
+
collapsedColumns: viewState?.cc ? new Set(viewState.cc) : undefined,
|
|
6651
|
+
compactMeta: viewState?.cm,
|
|
6640
6652
|
});
|
|
6641
6653
|
return finalizeSvgExport(container, theme, effectivePalette);
|
|
6642
6654
|
}
|
|
@@ -6696,22 +6708,32 @@ export async function renderForExport(
|
|
|
6696
6708
|
resolveActiveTagGroup(
|
|
6697
6709
|
erParsed.tagGroups,
|
|
6698
6710
|
erParsed.options['active-tag'],
|
|
6699
|
-
options?.tagGroup
|
|
6700
|
-
)
|
|
6711
|
+
viewState?.tag ?? options?.tagGroup
|
|
6712
|
+
),
|
|
6713
|
+
viewState?.sem
|
|
6701
6714
|
);
|
|
6702
6715
|
return finalizeSvgExport(container, theme, effectivePalette);
|
|
6703
6716
|
}
|
|
6704
6717
|
|
|
6705
6718
|
if (detectedType === 'boxes-and-lines') {
|
|
6706
6719
|
const { parseBoxesAndLines } = await import('./boxes-and-lines/parser');
|
|
6707
|
-
const { layoutBoxesAndLines } = await import('./boxes-and-lines/layout');
|
|
6708
|
-
const { renderBoxesAndLinesForExport } =
|
|
6709
|
-
await import('./boxes-and-lines/renderer');
|
|
6710
|
-
|
|
6711
6720
|
const effectivePalette = await resolveExportPalette(theme, palette);
|
|
6712
6721
|
const blParsed = parseBoxesAndLines(content);
|
|
6713
6722
|
if (blParsed.error || blParsed.nodes.length === 0) return '';
|
|
6714
6723
|
|
|
6724
|
+
// Convert viewState.htv (Record<string, string[]>) to Map<string, Set<string>>
|
|
6725
|
+
let blHiddenTagValues: Map<string, Set<string>> | undefined;
|
|
6726
|
+
if (viewState?.htv) {
|
|
6727
|
+
blHiddenTagValues = new Map();
|
|
6728
|
+
for (const [k, v] of Object.entries(viewState.htv)) {
|
|
6729
|
+
blHiddenTagValues.set(k, new Set(v));
|
|
6730
|
+
}
|
|
6731
|
+
}
|
|
6732
|
+
|
|
6733
|
+
const { layoutBoxesAndLines } = await import('./boxes-and-lines/layout');
|
|
6734
|
+
const { renderBoxesAndLinesForExport } =
|
|
6735
|
+
await import('./boxes-and-lines/renderer');
|
|
6736
|
+
|
|
6715
6737
|
const blLayout = layoutBoxesAndLines(blParsed);
|
|
6716
6738
|
const PADDING = 20;
|
|
6717
6739
|
const titleOffset = blParsed.title ? 40 : 0;
|
|
@@ -6727,12 +6749,106 @@ export async function renderForExport(
|
|
|
6727
6749
|
theme === 'dark',
|
|
6728
6750
|
{
|
|
6729
6751
|
exportDims: { width: exportWidth, height: exportHeight },
|
|
6730
|
-
activeTagGroup: options?.tagGroup,
|
|
6752
|
+
activeTagGroup: viewState?.tag ?? options?.tagGroup,
|
|
6753
|
+
hiddenTagValues: blHiddenTagValues,
|
|
6731
6754
|
}
|
|
6732
6755
|
);
|
|
6733
6756
|
return finalizeSvgExport(container, theme, effectivePalette);
|
|
6734
6757
|
}
|
|
6735
6758
|
|
|
6759
|
+
if (detectedType === 'mindmap') {
|
|
6760
|
+
const { parseMindmap } = await import('./mindmap/parser');
|
|
6761
|
+
const { layoutMindmap } = await import('./mindmap/layout');
|
|
6762
|
+
const { collapseMindmapTree } = await import('./mindmap/collapse');
|
|
6763
|
+
const { renderMindmap } = await import('./mindmap/renderer');
|
|
6764
|
+
|
|
6765
|
+
const isDark = theme === 'dark';
|
|
6766
|
+
const effectivePalette = await resolveExportPalette(theme, palette);
|
|
6767
|
+
|
|
6768
|
+
const mmParsed = parseMindmap(content, effectivePalette);
|
|
6769
|
+
if (mmParsed.error) return '';
|
|
6770
|
+
|
|
6771
|
+
const collapsedNodes = viewState?.cg ? new Set(viewState.cg) : undefined;
|
|
6772
|
+
const activeTagGroup = resolveActiveTagGroup(
|
|
6773
|
+
mmParsed.tagGroups,
|
|
6774
|
+
mmParsed.options['active-tag'],
|
|
6775
|
+
viewState?.tag ?? options?.tagGroup
|
|
6776
|
+
);
|
|
6777
|
+
const hideDescriptions =
|
|
6778
|
+
mmParsed.options['hide-descriptions'] === 'true' ||
|
|
6779
|
+
viewState?.hd === true;
|
|
6780
|
+
|
|
6781
|
+
const { roots: effectiveRoots, hiddenCounts } =
|
|
6782
|
+
collapsedNodes && collapsedNodes.size > 0
|
|
6783
|
+
? collapseMindmapTree(mmParsed.roots, collapsedNodes)
|
|
6784
|
+
: { roots: mmParsed.roots, hiddenCounts: new Map<string, number>() };
|
|
6785
|
+
|
|
6786
|
+
const effectiveParsed = { ...mmParsed, roots: effectiveRoots };
|
|
6787
|
+
|
|
6788
|
+
const mmLayout = layoutMindmap(effectiveParsed, effectivePalette, {
|
|
6789
|
+
interactive: false,
|
|
6790
|
+
hiddenCounts: hiddenCounts.size > 0 ? hiddenCounts : undefined,
|
|
6791
|
+
activeTagGroup,
|
|
6792
|
+
hideDescriptions,
|
|
6793
|
+
});
|
|
6794
|
+
|
|
6795
|
+
const PADDING = 20;
|
|
6796
|
+
const titleOffset = effectiveParsed.title ? 30 : 0;
|
|
6797
|
+
const exportWidth = mmLayout.width + PADDING * 2;
|
|
6798
|
+
const exportHeight = mmLayout.height + PADDING * 2 + titleOffset;
|
|
6799
|
+
const container = createExportContainer(exportWidth, exportHeight);
|
|
6800
|
+
|
|
6801
|
+
const colorByDepth = viewState?.cbd === true;
|
|
6802
|
+
|
|
6803
|
+
renderMindmap(
|
|
6804
|
+
container,
|
|
6805
|
+
effectiveParsed,
|
|
6806
|
+
mmLayout,
|
|
6807
|
+
effectivePalette,
|
|
6808
|
+
isDark,
|
|
6809
|
+
undefined,
|
|
6810
|
+
{ width: exportWidth, height: exportHeight },
|
|
6811
|
+
undefined,
|
|
6812
|
+
hideDescriptions,
|
|
6813
|
+
colorByDepth ? null : activeTagGroup,
|
|
6814
|
+
colorByDepth ? { colorByDepth: true } : undefined
|
|
6815
|
+
);
|
|
6816
|
+
return finalizeSvgExport(container, theme, effectivePalette);
|
|
6817
|
+
}
|
|
6818
|
+
|
|
6819
|
+
if (detectedType === 'wireframe') {
|
|
6820
|
+
const { parseWireframe } = await import('./wireframe/parser');
|
|
6821
|
+
const { layoutWireframe } = await import('./wireframe/layout');
|
|
6822
|
+
const { renderWireframe } = await import('./wireframe/renderer');
|
|
6823
|
+
|
|
6824
|
+
const effectivePalette = await resolveExportPalette(theme, palette);
|
|
6825
|
+
const wireframeParsed = parseWireframe(content);
|
|
6826
|
+
if (
|
|
6827
|
+
wireframeParsed.error ||
|
|
6828
|
+
(wireframeParsed.roots.length === 0 &&
|
|
6829
|
+
wireframeParsed.modals.length === 0)
|
|
6830
|
+
)
|
|
6831
|
+
return '';
|
|
6832
|
+
|
|
6833
|
+
const wireframeLayout = layoutWireframe(wireframeParsed);
|
|
6834
|
+
|
|
6835
|
+
const exportWidth = wireframeLayout.width;
|
|
6836
|
+
const exportHeight = wireframeLayout.height;
|
|
6837
|
+
const container = createExportContainer(exportWidth, exportHeight);
|
|
6838
|
+
|
|
6839
|
+
renderWireframe(
|
|
6840
|
+
container,
|
|
6841
|
+
wireframeParsed,
|
|
6842
|
+
wireframeLayout,
|
|
6843
|
+
effectivePalette,
|
|
6844
|
+
theme === 'dark',
|
|
6845
|
+
undefined,
|
|
6846
|
+
{ width: exportWidth, height: exportHeight },
|
|
6847
|
+
theme
|
|
6848
|
+
);
|
|
6849
|
+
return finalizeSvgExport(container, theme, effectivePalette);
|
|
6850
|
+
}
|
|
6851
|
+
|
|
6736
6852
|
if (detectedType === 'c4') {
|
|
6737
6853
|
const { parseC4 } = await import('./c4/parser');
|
|
6738
6854
|
const {
|
|
@@ -6748,10 +6864,18 @@ export async function renderForExport(
|
|
|
6748
6864
|
const c4Parsed = parseC4(content, effectivePalette);
|
|
6749
6865
|
if (c4Parsed.error || c4Parsed.elements.length === 0) return '';
|
|
6750
6866
|
|
|
6751
|
-
// Container/component-level rendering
|
|
6752
|
-
const c4Level =
|
|
6753
|
-
|
|
6754
|
-
|
|
6867
|
+
// Container/component-level rendering (viewState fallback for share links)
|
|
6868
|
+
const c4Level =
|
|
6869
|
+
options?.c4Level ??
|
|
6870
|
+
(viewState?.c4l as
|
|
6871
|
+
| 'context'
|
|
6872
|
+
| 'containers'
|
|
6873
|
+
| 'components'
|
|
6874
|
+
| 'deployment'
|
|
6875
|
+
| undefined) ??
|
|
6876
|
+
'context';
|
|
6877
|
+
const c4System = options?.c4System ?? viewState?.c4s;
|
|
6878
|
+
const c4Container = options?.c4Container ?? viewState?.c4c;
|
|
6755
6879
|
|
|
6756
6880
|
const c4Layout =
|
|
6757
6881
|
c4Level === 'deployment'
|
|
@@ -6788,7 +6912,7 @@ export async function renderForExport(
|
|
|
6788
6912
|
resolveActiveTagGroup(
|
|
6789
6913
|
c4Parsed.tagGroups,
|
|
6790
6914
|
c4Parsed.options['active-tag'],
|
|
6791
|
-
options?.tagGroup
|
|
6915
|
+
viewState?.tag ?? options?.tagGroup
|
|
6792
6916
|
)
|
|
6793
6917
|
);
|
|
6794
6918
|
return finalizeSvgExport(container, theme, effectivePalette);
|
|
@@ -6834,7 +6958,7 @@ export async function renderForExport(
|
|
|
6834
6958
|
const activeTagGroup = resolveActiveTagGroup(
|
|
6835
6959
|
infraParsed.tagGroups,
|
|
6836
6960
|
infraParsed.options['active-tag'],
|
|
6837
|
-
options?.tagGroup
|
|
6961
|
+
viewState?.tag ?? options?.tagGroup
|
|
6838
6962
|
);
|
|
6839
6963
|
|
|
6840
6964
|
const titleOffset = infraParsed.title ? 40 : 0;
|
|
@@ -6860,7 +6984,8 @@ export async function renderForExport(
|
|
|
6860
6984
|
false,
|
|
6861
6985
|
null,
|
|
6862
6986
|
null,
|
|
6863
|
-
true
|
|
6987
|
+
true,
|
|
6988
|
+
viewState?.cg ? new Set(viewState.cg) : null
|
|
6864
6989
|
);
|
|
6865
6990
|
// Restore explicit pixel dimensions for resvg (renderer uses 100%/viewBox for app scaling)
|
|
6866
6991
|
const infraSvg = container.querySelector('svg');
|
|
@@ -6890,7 +7015,16 @@ export async function renderForExport(
|
|
|
6890
7015
|
resolved,
|
|
6891
7016
|
effectivePalette,
|
|
6892
7017
|
theme === 'dark',
|
|
6893
|
-
|
|
7018
|
+
{
|
|
7019
|
+
collapsedGroups: viewState?.cg ? new Set(viewState.cg) : undefined,
|
|
7020
|
+
currentSwimlaneGroup: viewState?.swim ?? undefined,
|
|
7021
|
+
collapsedLanes: viewState?.cl ? new Set(viewState.cl) : undefined,
|
|
7022
|
+
currentActiveGroup: resolveActiveTagGroup(
|
|
7023
|
+
resolved.tagGroups,
|
|
7024
|
+
resolved.options.activeTag ?? undefined,
|
|
7025
|
+
viewState?.tag ?? options?.tagGroup
|
|
7026
|
+
),
|
|
7027
|
+
},
|
|
6894
7028
|
{ width: EXPORT_W, height: EXPORT_H }
|
|
6895
7029
|
);
|
|
6896
7030
|
return finalizeSvgExport(container, theme, effectivePalette);
|
|
@@ -6920,6 +7054,72 @@ export async function renderForExport(
|
|
|
6920
7054
|
return finalizeSvgExport(container, theme, effectivePalette);
|
|
6921
7055
|
}
|
|
6922
7056
|
|
|
7057
|
+
if (detectedType === 'tech-radar') {
|
|
7058
|
+
const { parseTechRadar } = await import('./tech-radar/parser');
|
|
7059
|
+
const { renderTechRadarForExport } = await import('./tech-radar/renderer');
|
|
7060
|
+
|
|
7061
|
+
const effectivePalette = await resolveExportPalette(theme, palette);
|
|
7062
|
+
const radarParsed = parseTechRadar(content);
|
|
7063
|
+
if (radarParsed.error || radarParsed.quadrants.length === 0) return '';
|
|
7064
|
+
|
|
7065
|
+
const RADAR_EXPORT_W = 1600;
|
|
7066
|
+
const RADAR_EXPORT_H = 1200;
|
|
7067
|
+
const container = createExportContainer(RADAR_EXPORT_W, RADAR_EXPORT_H);
|
|
7068
|
+
renderTechRadarForExport(
|
|
7069
|
+
container,
|
|
7070
|
+
radarParsed,
|
|
7071
|
+
effectivePalette,
|
|
7072
|
+
theme === 'dark',
|
|
7073
|
+
{ width: RADAR_EXPORT_W, height: RADAR_EXPORT_H },
|
|
7074
|
+
viewState
|
|
7075
|
+
);
|
|
7076
|
+
return finalizeSvgExport(container, theme, effectivePalette);
|
|
7077
|
+
}
|
|
7078
|
+
|
|
7079
|
+
if (detectedType === 'journey-map') {
|
|
7080
|
+
const { parseJourneyMap } = await import('./journey-map/parser');
|
|
7081
|
+
const { renderJourneyMap } = await import('./journey-map/renderer');
|
|
7082
|
+
const { layoutJourneyMap } = await import('./journey-map/layout');
|
|
7083
|
+
|
|
7084
|
+
const effectivePalette = await resolveExportPalette(theme, palette);
|
|
7085
|
+
const jmParsed = parseJourneyMap(content, effectivePalette);
|
|
7086
|
+
if (
|
|
7087
|
+
jmParsed.error ||
|
|
7088
|
+
(jmParsed.phases.length === 0 && jmParsed.steps.length === 0)
|
|
7089
|
+
)
|
|
7090
|
+
return '';
|
|
7091
|
+
|
|
7092
|
+
const jmLayout = layoutJourneyMap(jmParsed, effectivePalette);
|
|
7093
|
+
const container = createExportContainer(
|
|
7094
|
+
jmLayout.totalWidth,
|
|
7095
|
+
jmLayout.totalHeight
|
|
7096
|
+
);
|
|
7097
|
+
renderJourneyMap(container, jmParsed, effectivePalette, theme === 'dark', {
|
|
7098
|
+
exportDims: { width: jmLayout.totalWidth, height: jmLayout.totalHeight },
|
|
7099
|
+
});
|
|
7100
|
+
return finalizeSvgExport(container, theme, effectivePalette);
|
|
7101
|
+
}
|
|
7102
|
+
|
|
7103
|
+
if (detectedType === 'cycle') {
|
|
7104
|
+
const { parseCycle } = await import('./cycle/parser');
|
|
7105
|
+
const { renderCycleForExport } = await import('./cycle/renderer');
|
|
7106
|
+
|
|
7107
|
+
const effectivePalette = await resolveExportPalette(theme, palette);
|
|
7108
|
+
const cycleParsed = parseCycle(content);
|
|
7109
|
+
if (cycleParsed.error || cycleParsed.nodes.length === 0) return '';
|
|
7110
|
+
|
|
7111
|
+
const container = createExportContainer(EXPORT_WIDTH, EXPORT_HEIGHT);
|
|
7112
|
+
renderCycleForExport(
|
|
7113
|
+
container,
|
|
7114
|
+
cycleParsed,
|
|
7115
|
+
effectivePalette,
|
|
7116
|
+
theme === 'dark',
|
|
7117
|
+
{ width: EXPORT_WIDTH, height: EXPORT_HEIGHT },
|
|
7118
|
+
viewState
|
|
7119
|
+
);
|
|
7120
|
+
return finalizeSvgExport(container, theme, effectivePalette);
|
|
7121
|
+
}
|
|
7122
|
+
|
|
6923
7123
|
const parsed = parseVisualization(content, palette);
|
|
6924
7124
|
// Allow sequence diagrams through even if parseVisualization errors —
|
|
6925
7125
|
// sequence is parsed by its own dedicated parser (parseSequenceDgmo)
|
|
@@ -6991,9 +7191,9 @@ export async function renderForExport(
|
|
|
6991
7191
|
resolveActiveTagGroup(
|
|
6992
7192
|
parsed.timelineTagGroups,
|
|
6993
7193
|
undefined,
|
|
6994
|
-
|
|
7194
|
+
viewState?.tag ?? options?.tagGroup
|
|
6995
7195
|
),
|
|
6996
|
-
|
|
7196
|
+
viewState?.swim
|
|
6997
7197
|
);
|
|
6998
7198
|
} else if (parsed.type === 'venn') {
|
|
6999
7199
|
renderVenn(container, parsed, effectivePalette, isDark, undefined, dims);
|
package/src/dgmo-router.ts
CHANGED
|
@@ -17,6 +17,11 @@ import { looksLikeSitemap, parseSitemap } from './sitemap/parser';
|
|
|
17
17
|
import { parseInfra } from './infra/parser';
|
|
18
18
|
import { parseGantt } from './gantt/parser';
|
|
19
19
|
import { parseBoxesAndLines } from './boxes-and-lines/parser';
|
|
20
|
+
import { parseMindmap } from './mindmap/parser';
|
|
21
|
+
import { parseWireframe } from './wireframe/parser';
|
|
22
|
+
import { parseTechRadar } from './tech-radar/parser';
|
|
23
|
+
import { parseCycle } from './cycle/parser';
|
|
24
|
+
import { parseJourneyMap } from './journey-map/parser';
|
|
20
25
|
import { parseFirstLine } from './utils/parsing';
|
|
21
26
|
import { makeDgmoError, suggest } from './diagnostics';
|
|
22
27
|
import type { DgmoError } from './diagnostics';
|
|
@@ -135,6 +140,8 @@ const VISUALIZATION_TYPES = new Set([
|
|
|
135
140
|
'timeline',
|
|
136
141
|
'venn',
|
|
137
142
|
'quadrant',
|
|
143
|
+
'tech-radar',
|
|
144
|
+
'cycle',
|
|
138
145
|
]);
|
|
139
146
|
const DIAGRAM_TYPES = new Set([
|
|
140
147
|
'sequence',
|
|
@@ -149,6 +156,9 @@ const DIAGRAM_TYPES = new Set([
|
|
|
149
156
|
'infra',
|
|
150
157
|
'gantt',
|
|
151
158
|
'boxes-and-lines',
|
|
159
|
+
'mindmap',
|
|
160
|
+
'wireframe',
|
|
161
|
+
'journey-map',
|
|
152
162
|
]);
|
|
153
163
|
const EXTENDED_CHART_TYPES = new Set([
|
|
154
164
|
'scatter',
|
|
@@ -228,6 +238,11 @@ const PARSE_DISPATCH = new Map<
|
|
|
228
238
|
['infra', (c) => parseInfra(c)],
|
|
229
239
|
['gantt', (c) => parseGantt(c)],
|
|
230
240
|
['boxes-and-lines', (c) => parseBoxesAndLines(c)],
|
|
241
|
+
['mindmap', (c) => parseMindmap(c)],
|
|
242
|
+
['wireframe', (c) => parseWireframe(c)],
|
|
243
|
+
['tech-radar', (c) => parseTechRadar(c)],
|
|
244
|
+
['cycle', (c) => parseCycle(c)],
|
|
245
|
+
['journey-map', (c) => parseJourneyMap(c)],
|
|
231
246
|
]);
|
|
232
247
|
|
|
233
248
|
/**
|
package/src/echarts.ts
CHANGED
|
@@ -150,6 +150,7 @@ import {
|
|
|
150
150
|
collectIndentedValues,
|
|
151
151
|
extractColor,
|
|
152
152
|
measureIndent,
|
|
153
|
+
normalizeNumericToken,
|
|
153
154
|
parseFirstLine,
|
|
154
155
|
parseSeriesNames,
|
|
155
156
|
} from './utils/parsing';
|
|
@@ -359,10 +360,11 @@ export function parseExtendedChart(
|
|
|
359
360
|
|
|
360
361
|
// Sankey/chord link syntax: Source -> Target Value (directed) or Source -- Target Value (undirected)
|
|
361
362
|
const arrowMatch = trimmed.match(
|
|
362
|
-
/^(.+?)\s*(->|--)\s*(.+?)\s+(\d+(
|
|
363
|
+
/^(.+?)\s*(->|--)\s*(.+?)\s+(-?[\d,_]+(?:\.[\d]+)?)\s*(?:\(([^)]+)\))?\s*$/
|
|
363
364
|
);
|
|
364
365
|
if (arrowMatch) {
|
|
365
|
-
const [, rawSource, arrow, rawTarget,
|
|
366
|
+
const [, rawSource, arrow, rawTarget, rawVal, rawLinkColor] = arrowMatch;
|
|
367
|
+
const val = normalizeNumericToken(rawVal) ?? rawVal;
|
|
366
368
|
const { label: source, color: sourceColor } = extractColor(
|
|
367
369
|
rawSource.trim(),
|
|
368
370
|
palette
|
|
@@ -409,7 +411,7 @@ export function parseExtendedChart(
|
|
|
409
411
|
// Parse "TargetName value (linkColor)" or "TargetName(nodeColor) value (linkColor)"
|
|
410
412
|
// Strip trailing (color) annotation before parseDataRowValues — it can't handle it
|
|
411
413
|
const valColorMatch = trimmed.match(
|
|
412
|
-
/(\d+(
|
|
414
|
+
/(-?[\d,_]+(?:\.[\d]+)?)\s*\(([^)]+)\)\s*$/
|
|
413
415
|
);
|
|
414
416
|
const strippedLine = valColorMatch
|
|
415
417
|
? trimmed.replace(/\s*\([^)]+\)\s*$/, '')
|
|
@@ -449,9 +451,10 @@ export function parseExtendedChart(
|
|
|
449
451
|
|
|
450
452
|
// Bare label at indent 0 (or any indent without a value) = new source node
|
|
451
453
|
const spaceIdx = trimmed.indexOf(' ');
|
|
454
|
+
const lastTok = trimmed.substring(trimmed.lastIndexOf(' ') + 1);
|
|
452
455
|
const hasNumericSuffix =
|
|
453
456
|
spaceIdx >= 0 &&
|
|
454
|
-
!isNaN(parseFloat(
|
|
457
|
+
!isNaN(parseFloat(normalizeNumericToken(lastTok) ?? lastTok));
|
|
455
458
|
if (!hasNumericSuffix) {
|
|
456
459
|
while (sankeyStack.length && sankeyStack.at(-1)!.indent >= indent) {
|
|
457
460
|
sankeyStack.pop();
|
package/src/editor/dgmo.grammar
CHANGED
|
@@ -30,7 +30,11 @@ contentPart {
|
|
|
30
30
|
Duration { $[0-9]+ ("." $[0-9]+)? ("min" | "bd" | "h" | "d" | "w" | "m" | "q" | "y" | "s") "?"? }
|
|
31
31
|
DateLiteral { $[0-9] $[0-9] $[0-9] $[0-9] "-" $[0-9] $[0-9] ("-" $[0-9] $[0-9])? }
|
|
32
32
|
Percentage { $[0-9]+ ("." $[0-9]+)? "%" }
|
|
33
|
-
Number {
|
|
33
|
+
Number {
|
|
34
|
+
$[0-9] $[0-9]? $[0-9]? ("," $[0-9] $[0-9] $[0-9])+ ("." $[0-9]+)? |
|
|
35
|
+
$[0-9]+ ("_" $[0-9]+)+ ("." $[0-9]+)? |
|
|
36
|
+
$[0-9]+ ("." $[0-9]+)?
|
|
37
|
+
}
|
|
34
38
|
|
|
35
39
|
SectionMarker { "==" }
|
|
36
40
|
Url { "http" "s"? "://" ![ \t\n|,)\]>]+ }
|
|
@@ -10,7 +10,7 @@ export const parser = LRParser.deserialize({
|
|
|
10
10
|
maxTerm: 40,
|
|
11
11
|
skippedNodes: [0],
|
|
12
12
|
repeatNodeCount: 2,
|
|
13
|
-
tokenData: "
|
|
13
|
+
tokenData: "<O~RxOX#oXY#tYZ$PZp#opq#tqt#oux#oxy$Uyz$tz{${{|%S|}%Z}!O%b!O!P#o!P!Q%q!Q![&b![!]/T!]!^#o!^!_/[!_!`/c!`!a/p!a!b/w!b!c#o!c!}0O!}#O3U#O#P#o#P#Q3Z#Q#R#o#R#S0O#S#T#o#T#[0O#[#]3b#]#o0O#o#p#o#p#q;b#q#r#o#r#s;i#s;'S#o;'S;=`;x<%lO#o~#tOq~~#yQv~XY#tpq#t~$UOw~~$]Qc~q~}!O$c#T#o$c~$fRyz$o}!O$c#T#o$c~$tOg~~${Od~q~~%SOn~q~~%ZOk~q~~%bOj~q~~%iPl~q~!`!a%l~%qOX~~%vPq~!P!Q%y~&OSV~OY%yZ;'S%y;'S;=`&[<%lO%y~&_P;=`<%l%y~&i]^~q~uv'b|}'g!O!P(d!Q![*T#R#S.o#U#V)_#W#X)e#[#])e#a#b)r#e#f)e#g#h)e#k#l)e#m#n)e~'gO]~~'jP!Q!['m~'pP!Q!['s~'vP!Q!['y~(OQ^~|}'g!O!P(U~(XP!Q![([~(aP^~!Q![([~(gP!Q![(j~(oY^~uv'b!Q![(j#U#V)_#W#X)e#[#])e#a#b)r#e#f)e#g#h)e#k#l)e#m#n)e~)bP#W#X)e~)jPZ~!a!b)m~)rOZ~~)wQZ~!a!b)m#]#^)}~*QP#b#c)e~*Y]^~uv'b|}'g!O!P(d!Q![+R#R#S.o#U#V)_#W#X)e#[#])e#a#b)r#e#f)e#g#h)e#k#l)e#m#n)e~+W]^~uv'b|}'g!O!P(d!Q![,P#R#S.o#U#V)_#W#X)e#[#])e#a#b)r#e#f)e#g#h)e#k#l)e#m#n)e~,U]^~uv'b}!O,}!O!P(d!Q![-t#R#S.o#U#V)_#W#X)e#[#])e#a#b)r#e#f)e#g#h)e#k#l)e#m#n)e~-QP!Q![-T~-WP!Q![-Z~-`P[~}!O-c~-fP!Q![-i~-lP!Q![-o~-tO[~~-y[^~uv'b!O!P(d!Q![-t#R#S.o#U#V)_#W#X)e#[#])e#a#b)r#e#f)e#g#h)e#k#l)e#m#n)e~.rP!Q![.u~.zR^~!O!P(U!Q![.u#R#S.o~/[Oi~q~~/cOe~q~~/hPq~!_!`/k~/pO_~~/wOf~q~~0OOo~q~~0V_p~q~qr1Ust1Uvw1Uwx1U{|1U}!O2Y!O!P1U!P!Q1U!Q![1U!_!`1U!a!b1U!b!c1U!c!}1U#R#S1U#T#o1U~1Z_p~qr1Ust1Uvw1Uwx1U{|1U}!O2Y!O!P1U!P!Q1U!Q![1U!_!`1U!a!b1U!b!c1U!c!}1U#R#S1U#T#o1U~2]]qr1Ust1Uvw1Uwx1U{|1U!O!P1U!P!Q1U!_!`1U!a!b1U!b!c1U!c!}1U#R#S1U#T#o1U~3ZOa~~3bOb~q~~3iap~q~qr1Ust1Uvw1Uwx1U{|1U}!O2Y!O!P1U!P!Q1U!Q![1U!_!`1U!a!b1U!b!c1U!c!}1U#R#S1U#T#h1U#h#i4n#i#o1U~4sap~qr1Ust1Uvw1Uwx1U{|1U}!O2Y!O!P1U!P!Q1U!Q![1U!_!`1U!a!b1U!b!c1U!c!}1U#R#S1U#T#h1U#h#i5x#i#o1U~5}ap~qr1Ust1Uvw1Uwx1U{|1U}!O2Y!O!P1U!P!Q1U!Q![1U!_!`1U!a!b1U!b!c1U!c!}1U#R#S1U#T#d1U#d#e7S#e#o1U~7Xbp~qr1Ust1Uvw1Uwx1U{|1U}!O2Y!O!P1U!P!Q1U!Q![1U![!]8a!_!`1U!a!b1U!b!c1U!c!}1U#R#S1U#T#g1U#g#h:Z#h#o1U~8dP!P!Q8g~8jP!P!Q8m~8pYOX9`Zp9`qy9`z|9`}!`9`!a#P9`#Q#p9`#q;'S9`;'S;=`:T<%lO9`~9eY`~OX9`Zp9`qy9`z|9`}!`9`!a#P9`#Q#p9`#q;'S9`;'S;=`:T<%lO9`~:WP;=`<%l9`~:``p~qr1Ust1Uvw1Uwx1U{|1U}!O2Y!O!P1U!P!Q1U!Q![1U![!]8a!_!`1U!a!b1U!b!c1U!c!}1U#R#S1U#T#o1U~;iOh~q~~;pPm~q~!`!a;s~;xOY~~;{P;=`<%l#o",
|
|
14
14
|
tokenizers: [0],
|
|
15
15
|
topRules: {"Document":[0,6]},
|
|
16
16
|
specialized: [{term: 32, get: (value, stack) => (specializeKeyword(value, stack) << 1), external: specializeKeyword}],
|
package/src/editor/keywords.ts
CHANGED
|
@@ -13,6 +13,10 @@ export const CHART_TYPES = new Set([
|
|
|
13
13
|
'infra',
|
|
14
14
|
'gantt',
|
|
15
15
|
'boxes-and-lines',
|
|
16
|
+
'wireframe',
|
|
17
|
+
'tech-radar',
|
|
18
|
+
'mindmap',
|
|
19
|
+
'journey-map',
|
|
16
20
|
// Data chart types
|
|
17
21
|
'bar',
|
|
18
22
|
'line',
|
|
@@ -64,6 +68,10 @@ export const METADATA_KEYS = new Set([
|
|
|
64
68
|
'top-left',
|
|
65
69
|
'bottom-right',
|
|
66
70
|
'bottom-left',
|
|
71
|
+
// Tech-radar pipe metadata
|
|
72
|
+
'quadrant',
|
|
73
|
+
'ring',
|
|
74
|
+
'trend',
|
|
67
75
|
]);
|
|
68
76
|
|
|
69
77
|
/** Tag declaration keyword. */
|
|
@@ -81,6 +89,8 @@ export const DIRECTIVE_KEYWORDS = new Set([
|
|
|
81
89
|
'critical-path',
|
|
82
90
|
'no-dependencies',
|
|
83
91
|
'sort',
|
|
92
|
+
// Tech-radar
|
|
93
|
+
'rings',
|
|
84
94
|
// Tags
|
|
85
95
|
'tags',
|
|
86
96
|
'import',
|
|
@@ -170,6 +180,17 @@ export const CONTROL_KEYWORDS = new Set([
|
|
|
170
180
|
'loop',
|
|
171
181
|
'parallel',
|
|
172
182
|
'note',
|
|
183
|
+
// Wireframe elements
|
|
184
|
+
'nav',
|
|
185
|
+
'tabs',
|
|
186
|
+
'table',
|
|
187
|
+
'image',
|
|
188
|
+
'modal',
|
|
189
|
+
'skeleton',
|
|
190
|
+
'alert',
|
|
191
|
+
'progress',
|
|
192
|
+
'chart',
|
|
193
|
+
'mobile',
|
|
173
194
|
]);
|
|
174
195
|
|
|
175
196
|
/** Status keywords — kanban. */
|
|
@@ -182,6 +203,11 @@ export const STATUS_KEYWORDS = new Set([
|
|
|
182
203
|
'in-progress',
|
|
183
204
|
'backlog',
|
|
184
205
|
'ready',
|
|
206
|
+
// Tech-radar trend values
|
|
207
|
+
'new',
|
|
208
|
+
'up',
|
|
209
|
+
'down',
|
|
210
|
+
'stable',
|
|
185
211
|
]);
|
|
186
212
|
|
|
187
213
|
/** Modifier keywords — adjust declarations. */
|
package/src/gantt/parser.ts
CHANGED
|
@@ -744,7 +744,7 @@ export function parseGantt(
|
|
|
744
744
|
|
|
745
745
|
// First segment could be empty (just `[Group]`) or have metadata
|
|
746
746
|
let metadata: Record<string, string> = {};
|
|
747
|
-
|
|
747
|
+
const color: string | null = null;
|
|
748
748
|
|
|
749
749
|
const pipeWarn = () => warn(lineNumber, MULTIPLE_PIPE_ERROR);
|
|
750
750
|
if (segments.length > 0 && segments[0].trim()) {
|
|
@@ -758,14 +758,8 @@ export function parseGantt(
|
|
|
758
758
|
);
|
|
759
759
|
}
|
|
760
760
|
|
|
761
|
-
// Extract color from group name if present
|
|
762
|
-
const nameExtracted = extractColor(groupMatch[1], palette);
|
|
763
|
-
if (nameExtracted.color) {
|
|
764
|
-
color = nameExtracted.color;
|
|
765
|
-
}
|
|
766
|
-
|
|
767
761
|
const group: GanttGroup = {
|
|
768
|
-
name:
|
|
762
|
+
name: groupMatch[1],
|
|
769
763
|
color,
|
|
770
764
|
metadata,
|
|
771
765
|
lineNumber,
|