@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
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { PaletteColors } from '../palettes';
|
|
2
|
+
import { resolveColorWithDiagnostic } from '../colors';
|
|
2
3
|
import { makeDgmoError, formatDgmoError, suggest } from '../diagnostics';
|
|
3
4
|
import {
|
|
4
5
|
matchTagBlockHeading,
|
|
@@ -138,8 +139,14 @@ export function parseJourneyMap(
|
|
|
138
139
|
const key = part.substring(0, colonIdx).trim().toLowerCase();
|
|
139
140
|
const value = part.substring(colonIdx + 1).trim();
|
|
140
141
|
if (key === 'color') {
|
|
141
|
-
|
|
142
|
-
personaColor =
|
|
142
|
+
// Resolve the color name directly (no synthetic parens wrap).
|
|
143
|
+
personaColor =
|
|
144
|
+
resolveColorWithDiagnostic(
|
|
145
|
+
value,
|
|
146
|
+
lineNumber,
|
|
147
|
+
result.diagnostics,
|
|
148
|
+
palette
|
|
149
|
+
) ?? undefined;
|
|
143
150
|
}
|
|
144
151
|
}
|
|
145
152
|
}
|
|
@@ -209,7 +216,7 @@ export function parseJourneyMap(
|
|
|
209
216
|
if (!color) {
|
|
210
217
|
warn(
|
|
211
218
|
lineNumber,
|
|
212
|
-
`Expected 'Value
|
|
219
|
+
`Expected 'Value color' in tag group '${currentTagGroup.name}'`
|
|
213
220
|
);
|
|
214
221
|
continue;
|
|
215
222
|
}
|
|
@@ -36,6 +36,7 @@ export interface JourneyMapInteractiveOptions {
|
|
|
36
36
|
collapsedPhases?: Set<string>;
|
|
37
37
|
/** Called when a phase is toggled */
|
|
38
38
|
onPhaseToggle?: (phaseName: string) => void;
|
|
39
|
+
exportMode?: boolean;
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
// ============================================================
|
|
@@ -313,7 +314,7 @@ export function renderJourneyMap(
|
|
|
313
314
|
titleRelation: 'inline-with-title',
|
|
314
315
|
},
|
|
315
316
|
titleWidth: 0,
|
|
316
|
-
mode:
|
|
317
|
+
mode: options?.exportMode ? 'export' : 'preview',
|
|
317
318
|
};
|
|
318
319
|
|
|
319
320
|
const legendState: LegendState = { activeGroup: effectiveActiveGroup };
|
|
@@ -1559,6 +1560,7 @@ export function renderJourneyMapForExport(
|
|
|
1559
1560
|
const container = document.createElement('div');
|
|
1560
1561
|
renderJourneyMap(container, parsed, palette, isDark, {
|
|
1561
1562
|
exportDims: { width: layout.totalWidth, height: layout.totalHeight },
|
|
1563
|
+
exportMode: true,
|
|
1562
1564
|
});
|
|
1563
1565
|
|
|
1564
1566
|
const svgEl = container.querySelector('svg');
|
package/src/kanban/parser.ts
CHANGED
|
@@ -26,10 +26,11 @@ import type {
|
|
|
26
26
|
// Regex patterns
|
|
27
27
|
// ============================================================
|
|
28
28
|
|
|
29
|
-
// [Column Name], [Column Name]
|
|
29
|
+
// [Column Name], [Column Name] color, [Column Name] as <alias>, [Column Name] | wip: 3, etc.
|
|
30
|
+
// Universal §1.5 trailing-token: color is a bare token after `]`.
|
|
30
31
|
// Captures: [1]=label [2]=color [3]=alias (TD-18) [4]=pipe meta
|
|
31
32
|
const COLUMN_RE =
|
|
32
|
-
/^\[(.+?)\](?:\s
|
|
33
|
+
/^\[(.+?)\](?:\s+(\S+))?(?:\s+as\s+([A-Za-z][A-Za-z0-9_]{0,11}))?\s*(?:\|\s*(.+))?$/;
|
|
33
34
|
// Legacy delimiter
|
|
34
35
|
const LEGACY_COLUMN_RE = /^==\s+(.+?)\s*(?:\[wip:\s*(\d+)\])?\s*==$/;
|
|
35
36
|
|
|
@@ -180,7 +181,7 @@ export function parseKanban(
|
|
|
180
181
|
}
|
|
181
182
|
}
|
|
182
183
|
|
|
183
|
-
// Tag group entries (indented Value
|
|
184
|
+
// Tag group entries (indented Value color under tag heading)
|
|
184
185
|
// First entry is the default unless another is marked `default`
|
|
185
186
|
if (currentTagGroup && !contentStarted) {
|
|
186
187
|
const indent = measureIndent(line);
|
|
@@ -190,7 +191,7 @@ export function parseKanban(
|
|
|
190
191
|
if (!color) {
|
|
191
192
|
warn(
|
|
192
193
|
lineNumber,
|
|
193
|
-
`Expected 'Value
|
|
194
|
+
`Expected 'Value color' in tag group '${currentTagGroup.name}'`
|
|
194
195
|
);
|
|
195
196
|
continue;
|
|
196
197
|
}
|
|
@@ -247,9 +248,12 @@ export function parseKanban(
|
|
|
247
248
|
|
|
248
249
|
columnCounter++;
|
|
249
250
|
const colName = columnMatch[1].trim();
|
|
250
|
-
|
|
251
|
+
// Trailing token after `]` must be a recognized color word (§1.5).
|
|
252
|
+
// If it isn't, the line is malformed — emit the standard diagnostic.
|
|
253
|
+
const rawTrailing = columnMatch[2]?.trim();
|
|
254
|
+
const colColor = rawTrailing
|
|
251
255
|
? resolveColorWithDiagnostic(
|
|
252
|
-
|
|
256
|
+
rawTrailing,
|
|
253
257
|
lineNumber,
|
|
254
258
|
result.diagnostics,
|
|
255
259
|
palette
|
|
@@ -270,8 +274,8 @@ export function parseKanban(
|
|
|
270
274
|
parsePipeMetadata(pipeSegments, metaAliasMap)
|
|
271
275
|
);
|
|
272
276
|
// Extract wip from metadata
|
|
273
|
-
if (columnMetadata
|
|
274
|
-
const wipVal = parseInt(columnMetadata
|
|
277
|
+
if (columnMetadata['wip']) {
|
|
278
|
+
const wipVal = parseInt(columnMetadata['wip'], 10);
|
|
275
279
|
if (!isNaN(wipVal)) {
|
|
276
280
|
wipLimit = wipVal;
|
|
277
281
|
}
|
package/src/kanban/renderer.ts
CHANGED
|
@@ -37,6 +37,7 @@ interface KanbanInteractiveOptions {
|
|
|
37
37
|
collapsedLanes?: Set<string>;
|
|
38
38
|
collapsedColumns?: Set<string>;
|
|
39
39
|
compactMeta?: boolean;
|
|
40
|
+
exportMode?: boolean;
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
// ============================================================
|
|
@@ -330,7 +331,7 @@ export function renderKanban(
|
|
|
330
331
|
const legendConfig: LegendConfig = {
|
|
331
332
|
groups: parsed.tagGroups,
|
|
332
333
|
position: { placement: 'top-center', titleRelation: 'inline-with-title' },
|
|
333
|
-
mode:
|
|
334
|
+
mode: options?.exportMode ? 'export' : 'preview',
|
|
334
335
|
};
|
|
335
336
|
const legendState: LegendState = { activeGroup: activeTagGroup ?? null };
|
|
336
337
|
const legendG = svg
|
|
@@ -682,6 +683,7 @@ export function renderKanbanForExport(
|
|
|
682
683
|
const container = document.createElement('div');
|
|
683
684
|
renderKanban(container, parsed, palette, isDark, {
|
|
684
685
|
exportDims: { width: layout.totalWidth, height: layout.totalHeight },
|
|
686
|
+
exportMode: true,
|
|
685
687
|
});
|
|
686
688
|
|
|
687
689
|
const svgEl = container.querySelector('svg');
|
package/src/mindmap/layout.ts
CHANGED
package/src/mindmap/parser.ts
CHANGED
|
@@ -179,7 +179,7 @@ export function parseMindmap(
|
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
-
// Tag group entries (indented Value
|
|
182
|
+
// Tag group entries (indented Value color under tag heading)
|
|
183
183
|
if (currentTagGroup && !contentStarted) {
|
|
184
184
|
const indent = measureIndent(line);
|
|
185
185
|
if (indent > 0) {
|
|
@@ -188,7 +188,7 @@ export function parseMindmap(
|
|
|
188
188
|
if (!color) {
|
|
189
189
|
pushError(
|
|
190
190
|
lineNumber,
|
|
191
|
-
`Expected 'Value
|
|
191
|
+
`Expected 'Value color' in tag group '${currentTagGroup.name}'`
|
|
192
192
|
);
|
|
193
193
|
continue;
|
|
194
194
|
}
|
|
@@ -297,7 +297,7 @@ export function parseMindmap(
|
|
|
297
297
|
function parseNodeLine(
|
|
298
298
|
trimmed: string,
|
|
299
299
|
lineNumber: number,
|
|
300
|
-
|
|
300
|
+
_palette: PaletteColors | undefined,
|
|
301
301
|
counter: number,
|
|
302
302
|
aliasMap: Map<string, string>,
|
|
303
303
|
warnFn: (line: number, msg: string) => void
|
package/src/mindmap/renderer.ts
CHANGED
|
@@ -95,6 +95,7 @@ export function renderMindmap(
|
|
|
95
95
|
onToggleDescriptions?: (active: boolean) => void;
|
|
96
96
|
controlsExpanded?: boolean;
|
|
97
97
|
onToggleControlsExpand?: () => void;
|
|
98
|
+
exportMode?: boolean;
|
|
98
99
|
}
|
|
99
100
|
): void {
|
|
100
101
|
const isExport = !!exportDims;
|
|
@@ -234,7 +235,7 @@ export function renderMindmap(
|
|
|
234
235
|
};
|
|
235
236
|
}),
|
|
236
237
|
position: { placement: 'top-center', titleRelation: 'below-title' },
|
|
237
|
-
mode: '
|
|
238
|
+
mode: options?.exportMode ? 'export' : 'preview',
|
|
238
239
|
controlsGroup: controlsToggles,
|
|
239
240
|
};
|
|
240
241
|
const legendState: LegendState = {
|
package/src/org/parser.ts
CHANGED
|
@@ -235,7 +235,7 @@ export function parseOrg(content: string, palette?: PaletteColors): ParsedOrg {
|
|
|
235
235
|
}
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
-
// Tag group entries (indented Value
|
|
238
|
+
// Tag group entries (indented Value color under tag heading)
|
|
239
239
|
// First entry is the default unless another is marked `default`
|
|
240
240
|
if (currentTagGroup && !contentStarted) {
|
|
241
241
|
const indent = measureIndent(line);
|
|
@@ -245,7 +245,7 @@ export function parseOrg(content: string, palette?: PaletteColors): ParsedOrg {
|
|
|
245
245
|
if (!color) {
|
|
246
246
|
pushError(
|
|
247
247
|
lineNumber,
|
|
248
|
-
`Expected 'Value
|
|
248
|
+
`Expected 'Value color' in tag group '${currentTagGroup.name}'`
|
|
249
249
|
);
|
|
250
250
|
continue;
|
|
251
251
|
}
|
|
@@ -389,7 +389,7 @@ function parseNodeLabel(
|
|
|
389
389
|
trimmed: string,
|
|
390
390
|
_indent: number,
|
|
391
391
|
lineNumber: number,
|
|
392
|
-
|
|
392
|
+
_palette: PaletteColors | undefined,
|
|
393
393
|
counter: number,
|
|
394
394
|
metaAliasMap: Map<string, string> = new Map(),
|
|
395
395
|
warnFn?: (line: number, msg: string) => void,
|
package/src/org/renderer.ts
CHANGED
|
@@ -110,7 +110,8 @@ export function renderOrg(
|
|
|
110
110
|
exportDims?: { width?: number; height?: number },
|
|
111
111
|
activeTagGroup?: string | null,
|
|
112
112
|
hiddenAttributes?: Set<string>,
|
|
113
|
-
ancestorPath?: AncestorInfo[]
|
|
113
|
+
ancestorPath?: AncestorInfo[],
|
|
114
|
+
exportMode?: boolean
|
|
114
115
|
): void {
|
|
115
116
|
// Clear existing content
|
|
116
117
|
d3Selection.select(container).selectAll(':not([data-d3-tooltip])').remove();
|
|
@@ -235,7 +236,7 @@ export function renderOrg(
|
|
|
235
236
|
const rootNodeIds = new Set(parsed.roots.map((r) => r.id));
|
|
236
237
|
|
|
237
238
|
// Render container backgrounds (bottom layer)
|
|
238
|
-
const colorOff = parsed.options?.color === 'off';
|
|
239
|
+
const colorOff = parsed.options?.['color'] === 'off';
|
|
239
240
|
for (const c of layout.containers) {
|
|
240
241
|
const cG = contentG
|
|
241
242
|
.append('g')
|
|
@@ -759,7 +760,7 @@ export function renderOrg(
|
|
|
759
760
|
},
|
|
760
761
|
],
|
|
761
762
|
position: { placement: 'top-center', titleRelation: 'below-title' },
|
|
762
|
-
mode: '
|
|
763
|
+
mode: exportMode ? 'export' : 'preview',
|
|
763
764
|
};
|
|
764
765
|
const singleState: LegendState = { activeGroup: lg.name };
|
|
765
766
|
const groupG = legendParentBase
|
|
@@ -783,7 +784,7 @@ export function renderOrg(
|
|
|
783
784
|
const legendConfig: LegendConfig = {
|
|
784
785
|
groups,
|
|
785
786
|
position: { placement: 'top-center', titleRelation: 'below-title' },
|
|
786
|
-
mode: '
|
|
787
|
+
mode: exportMode ? 'export' : 'preview',
|
|
787
788
|
capsulePillAddonWidth: eyeAddonWidth,
|
|
788
789
|
};
|
|
789
790
|
const legendState: LegendState = { activeGroup: activeTagGroup ?? null };
|
package/src/pert/layout.ts
CHANGED
|
@@ -488,7 +488,7 @@ export function relayoutPert(
|
|
|
488
488
|
function applySwimLanes(
|
|
489
489
|
g: any,
|
|
490
490
|
resolved: ResolvedPert,
|
|
491
|
-
|
|
491
|
+
_memberToGroup: Map<string, string>,
|
|
492
492
|
collapsedGroupIds: ReadonlySet<string>
|
|
493
493
|
): boolean {
|
|
494
494
|
const expanded = resolved.groups.filter(
|
package/src/pert/monte-carlo.ts
CHANGED
|
@@ -134,8 +134,8 @@ interface SimulationOptions {
|
|
|
134
134
|
function simulate(
|
|
135
135
|
resolved: ResolvedPert,
|
|
136
136
|
expanded: ExpandedActivity[],
|
|
137
|
-
|
|
138
|
-
|
|
137
|
+
_predecessors: Map<string, string[]>,
|
|
138
|
+
_successors: Map<string, string[]>,
|
|
139
139
|
topo: string[],
|
|
140
140
|
terminals: string[],
|
|
141
141
|
poisoned: Set<string>,
|
package/src/pert/parser.ts
CHANGED
|
@@ -42,7 +42,7 @@ import type {
|
|
|
42
42
|
DeclarationSite,
|
|
43
43
|
ReferenceSite,
|
|
44
44
|
} from './internal';
|
|
45
|
-
import type { DiagramSymbols } from '../completion';
|
|
45
|
+
import type { DiagramSymbols } from '../completion-types';
|
|
46
46
|
|
|
47
47
|
// ============================================================
|
|
48
48
|
// Regexes / constants
|
|
@@ -448,7 +448,7 @@ export interface ParsePertOptions {
|
|
|
448
448
|
now?: Date;
|
|
449
449
|
/**
|
|
450
450
|
* Active palette — used when resolving color names on `tag` entries
|
|
451
|
-
* (e.g. `High
|
|
451
|
+
* (e.g. `High red` → palette.colors.red). Optional; when omitted the
|
|
452
452
|
* universal default color map is used.
|
|
453
453
|
*/
|
|
454
454
|
palette?: PaletteColors;
|
|
@@ -503,7 +503,7 @@ export function parsePert(
|
|
|
503
503
|
|
|
504
504
|
/**
|
|
505
505
|
* Tag groups declared at the top of the diagram. A `tag …` heading
|
|
506
|
-
* opens a block; entries (indented `Value
|
|
506
|
+
* opens a block; entries (indented `Value color` lines) accumulate
|
|
507
507
|
* until the first non-tag content line closes it.
|
|
508
508
|
*/
|
|
509
509
|
const tagGroups: TagGroup[] = [];
|
|
@@ -576,7 +576,7 @@ export function parsePert(
|
|
|
576
576
|
// layer is responsible for routing.
|
|
577
577
|
}
|
|
578
578
|
|
|
579
|
-
// ── Tag-block phase. `tag Priority as p\n High
|
|
579
|
+
// ── Tag-block phase. `tag Priority as p\n High red\n Low green`
|
|
580
580
|
// lives BEFORE diagram content; once any group / activity / arrow
|
|
581
581
|
// is seen, `contentStarted` flips and further `tag …` headings
|
|
582
582
|
// emit an error.
|
|
@@ -599,7 +599,7 @@ export function parsePert(
|
|
|
599
599
|
);
|
|
600
600
|
}
|
|
601
601
|
tagGroups.push(currentTagGroup);
|
|
602
|
-
// Inline values (e.g. `tag Priority as p Low
|
|
602
|
+
// Inline values (e.g. `tag Priority as p Low green, High red`).
|
|
603
603
|
if (tagBlockMatch.inlineValues) {
|
|
604
604
|
for (const raw of tagBlockMatch.inlineValues) {
|
|
605
605
|
const { text, isDefault } = stripDefaultModifier(raw);
|
|
@@ -612,7 +612,7 @@ export function parsePert(
|
|
|
612
612
|
if (!color) {
|
|
613
613
|
warn(
|
|
614
614
|
lineNumber,
|
|
615
|
-
`Expected 'Value
|
|
615
|
+
`Expected 'Value color' in tag group '${currentTagGroup.name}'`
|
|
616
616
|
);
|
|
617
617
|
continue;
|
|
618
618
|
}
|
|
@@ -624,7 +624,7 @@ export function parsePert(
|
|
|
624
624
|
}
|
|
625
625
|
continue;
|
|
626
626
|
}
|
|
627
|
-
// Indented `Value
|
|
627
|
+
// Indented `Value color` entry under an open tag block.
|
|
628
628
|
if (currentTagGroup && indent > 0) {
|
|
629
629
|
const { text, isDefault } = stripDefaultModifier(trimmed);
|
|
630
630
|
const { label, color } = extractColor(
|
|
@@ -636,7 +636,7 @@ export function parsePert(
|
|
|
636
636
|
if (!color) {
|
|
637
637
|
warn(
|
|
638
638
|
lineNumber,
|
|
639
|
-
`Expected 'Value
|
|
639
|
+
`Expected 'Value color' in tag group '${currentTagGroup.name}'`
|
|
640
640
|
);
|
|
641
641
|
continue;
|
|
642
642
|
}
|
|
@@ -675,7 +675,7 @@ export function parsePert(
|
|
|
675
675
|
id,
|
|
676
676
|
name,
|
|
677
677
|
activityIds: [],
|
|
678
|
-
collapsed: meta
|
|
678
|
+
collapsed: meta['collapsed'] === 'true',
|
|
679
679
|
lineNumber,
|
|
680
680
|
...(Object.keys(tags).length > 0 && { tags }),
|
|
681
681
|
});
|
|
@@ -1027,7 +1027,7 @@ export function parsePert(
|
|
|
1027
1027
|
name: decl.name,
|
|
1028
1028
|
...(decl.alias !== undefined && { alias: decl.alias }),
|
|
1029
1029
|
duration: estimate,
|
|
1030
|
-
...(meta
|
|
1030
|
+
...(meta['confidence'] && { confidence: meta['confidence'] }),
|
|
1031
1031
|
...(decl.groupHint !== undefined && { groupId: decl.groupHint }),
|
|
1032
1032
|
lineNumber: decl.lineNumber,
|
|
1033
1033
|
isMilestone,
|
package/src/pert/renderer.ts
CHANGED
|
@@ -388,6 +388,8 @@ export interface PertRenderOptions {
|
|
|
388
388
|
* through to the parsed `active-tag` directive.
|
|
389
389
|
*/
|
|
390
390
|
activeTagOverride?: string | null;
|
|
391
|
+
/** True when rendering for export — strips collapsed pills and cog from legend. */
|
|
392
|
+
exportMode?: boolean;
|
|
391
393
|
}
|
|
392
394
|
|
|
393
395
|
export function renderPert(
|
|
@@ -568,6 +570,7 @@ export function renderPert(
|
|
|
568
570
|
y: tagLegendY,
|
|
569
571
|
width: exportWidth,
|
|
570
572
|
activeGroup: tagLegendActive,
|
|
573
|
+
exportMode: options.exportMode,
|
|
571
574
|
});
|
|
572
575
|
}
|
|
573
576
|
|
|
@@ -681,6 +684,7 @@ export function renderPertForExport(
|
|
|
681
684
|
title: hasTitle ? parsed.title : null,
|
|
682
685
|
subtitle: resolved.projectSubtitle,
|
|
683
686
|
exportDims: { width: exportWidth, height: exportHeight },
|
|
687
|
+
exportMode: true,
|
|
684
688
|
});
|
|
685
689
|
const svgEl = container.querySelector('svg');
|
|
686
690
|
if (!svgEl) return '';
|
|
@@ -2990,6 +2994,7 @@ interface TagLegendArgs {
|
|
|
2990
2994
|
y: number;
|
|
2991
2995
|
width: number;
|
|
2992
2996
|
activeGroup: string | null;
|
|
2997
|
+
exportMode?: boolean;
|
|
2993
2998
|
}
|
|
2994
2999
|
|
|
2995
3000
|
/**
|
|
@@ -3008,7 +3013,7 @@ function renderTagLegendRow(
|
|
|
3008
3013
|
): void {
|
|
3009
3014
|
if (resolved.tagGroups.length === 0) return;
|
|
3010
3015
|
|
|
3011
|
-
const { x, y, width, activeGroup } = args;
|
|
3016
|
+
const { x, y, width, activeGroup, exportMode } = args;
|
|
3012
3017
|
const groups = resolved.tagGroups.map((g) => ({
|
|
3013
3018
|
name: g.name,
|
|
3014
3019
|
entries: g.entries.map((e) => ({ value: e.value, color: e.color })),
|
|
@@ -3024,7 +3029,7 @@ function renderTagLegendRow(
|
|
|
3024
3029
|
{
|
|
3025
3030
|
groups,
|
|
3026
3031
|
position: { placement: 'top-center', titleRelation: 'below-title' },
|
|
3027
|
-
mode: '
|
|
3032
|
+
mode: exportMode ? 'export' : 'preview',
|
|
3028
3033
|
},
|
|
3029
3034
|
{ activeGroup },
|
|
3030
3035
|
palette,
|
package/src/pert/types.ts
CHANGED
|
@@ -215,7 +215,7 @@ export interface ParsedPert {
|
|
|
215
215
|
groups: PertGroup[];
|
|
216
216
|
/**
|
|
217
217
|
* Tag groups declared at the top of the diagram (`tag Priority as p
|
|
218
|
-
* High
|
|
218
|
+
* High red, Low green`). Drive node fill via `resolveTagColor()`.
|
|
219
219
|
* Empty when no `tag` blocks are declared.
|
|
220
220
|
*/
|
|
221
221
|
tagGroups: TagGroup[];
|
package/src/pyramid/parser.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
measureIndent,
|
|
8
8
|
parseFirstLine,
|
|
9
9
|
parsePipeMetadata,
|
|
10
|
+
peelTrailingColorName,
|
|
10
11
|
tryParseSharedOption,
|
|
11
12
|
} from '../utils/parsing';
|
|
12
13
|
import type { ParsedPyramid, PyramidLayer } from './types';
|
|
@@ -146,6 +147,17 @@ export function parsePyramid(content: string): ParsedPyramid {
|
|
|
146
147
|
continue;
|
|
147
148
|
}
|
|
148
149
|
|
|
150
|
+
// Universal trailing-token shortcut: `Label color` is equivalent to
|
|
151
|
+
// `Label | color: <name>` when color is the only metadata key (§1.5).
|
|
152
|
+
if (!color) {
|
|
153
|
+
const { label: stripped, colorName: shortcutColor } =
|
|
154
|
+
peelTrailingColorName(label);
|
|
155
|
+
if (shortcutColor) {
|
|
156
|
+
color = shortcutColor;
|
|
157
|
+
label = stripped;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
149
161
|
currentLayer = {
|
|
150
162
|
label,
|
|
151
163
|
lineNumber: lineNum,
|
package/src/raci/parser.ts
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
measureIndent,
|
|
25
25
|
parseFirstLine,
|
|
26
26
|
parsePipeMetadata,
|
|
27
|
+
peelTrailingColorName,
|
|
27
28
|
OPTION_NOCOLON_RE,
|
|
28
29
|
tryParseSharedOption,
|
|
29
30
|
} from '../utils/parsing';
|
|
@@ -82,10 +83,10 @@ const KNOWN_BOOLEANS = new Set<string>([
|
|
|
82
83
|
...Object.keys(VARIANT_LOCK_DIRECTIVES),
|
|
83
84
|
]);
|
|
84
85
|
|
|
85
|
-
// Allow optional trailing
|
|
86
|
-
//
|
|
87
|
-
//
|
|
88
|
-
const PHASE_RE = /^\[(.+?)\]
|
|
86
|
+
// Allow optional trailing color shortcut and/or pipe metadata after the
|
|
87
|
+
// bracket: `[Voyage] blue | desc: …` (per §1.5 universal trailing-token
|
|
88
|
+
// rule + the modern cycle/pyramid/ring/journey-map/b&l idiom).
|
|
89
|
+
const PHASE_RE = /^\[(.+?)\](?:\s+(\S+))?(?:\s*\|\s*(.+))?\s*$/;
|
|
89
90
|
const ROLE_ASSIGNMENT_RE = /^([^:]+):\s*(.*)$/;
|
|
90
91
|
|
|
91
92
|
/**
|
|
@@ -382,22 +383,36 @@ export function parseRaci(
|
|
|
382
383
|
// Strip a possible trailing comma (user habit tolerance,
|
|
383
384
|
// matches `collectIndentedValues`).
|
|
384
385
|
const stripped = nextTrim.replace(/,\s*$/, '');
|
|
385
|
-
// Optional pipe metadata: `Cap | color: blue` —
|
|
386
|
-
//
|
|
386
|
+
// Optional pipe metadata: `Cap | color: blue` — long form.
|
|
387
|
+
// Optional trailing-token shortcut: `Cap blue` — short form (§1.5).
|
|
387
388
|
const segments = stripped.split('|').map((s) => s.trim());
|
|
388
|
-
|
|
389
|
+
let roleLabel = segments[0] ?? '';
|
|
389
390
|
let roleColor: string | undefined;
|
|
390
391
|
if (segments.length > 1) {
|
|
391
392
|
const meta = parsePipeMetadata(segments);
|
|
392
|
-
if (meta
|
|
393
|
+
if (meta['color']) {
|
|
393
394
|
roleColor = resolveColorWithDiagnostic(
|
|
394
|
-
meta
|
|
395
|
+
meta['color'],
|
|
395
396
|
j + 1,
|
|
396
397
|
result.diagnostics,
|
|
397
398
|
palette
|
|
398
399
|
);
|
|
399
400
|
}
|
|
400
401
|
}
|
|
402
|
+
// Apply shortcut only when pipe metadata didn't already set color.
|
|
403
|
+
if (!roleColor) {
|
|
404
|
+
const { label: stripLabel, colorName: shortcutColor } =
|
|
405
|
+
peelTrailingColorName(roleLabel);
|
|
406
|
+
if (shortcutColor) {
|
|
407
|
+
roleColor = resolveColorWithDiagnostic(
|
|
408
|
+
shortcutColor,
|
|
409
|
+
j + 1,
|
|
410
|
+
result.diagnostics,
|
|
411
|
+
palette
|
|
412
|
+
);
|
|
413
|
+
roleLabel = stripLabel;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
401
416
|
if (roleLabel) getOrAddRole(roleLabel, j + 1, roleColor);
|
|
402
417
|
}
|
|
403
418
|
i = j - 1; // outer loop's i++ lands on the first non-block line
|
|
@@ -469,13 +484,28 @@ export function parseRaci(
|
|
|
469
484
|
errorAt(lineNumber, 'Phase label is empty.');
|
|
470
485
|
continue;
|
|
471
486
|
}
|
|
472
|
-
//
|
|
487
|
+
// PHASE_RE captures: 1=label, 2=optional trailing-token color, 3=pipe meta.
|
|
488
|
+
// Long pipe form (`[Voyage] | color: blue`) wins over the shortcut.
|
|
473
489
|
let phaseColor: string | undefined;
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
490
|
+
const trailingToken = phaseMatch[2];
|
|
491
|
+
const pipeMeta = phaseMatch[3];
|
|
492
|
+
if (pipeMeta) {
|
|
493
|
+
const meta = parsePipeMetadata(['', pipeMeta]);
|
|
494
|
+
if (meta['color']) {
|
|
495
|
+
phaseColor = resolveColorWithDiagnostic(
|
|
496
|
+
meta['color'],
|
|
497
|
+
lineNumber,
|
|
498
|
+
result.diagnostics,
|
|
499
|
+
palette
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
if (!phaseColor && trailingToken) {
|
|
504
|
+
// Trailing token must be a recognized color word, or it's a parse error.
|
|
505
|
+
const { colorName } = peelTrailingColorName(`x ${trailingToken}`);
|
|
506
|
+
if (colorName) {
|
|
477
507
|
phaseColor = resolveColorWithDiagnostic(
|
|
478
|
-
|
|
508
|
+
colorName,
|
|
479
509
|
lineNumber,
|
|
480
510
|
result.diagnostics,
|
|
481
511
|
palette
|
package/src/raci/renderer.ts
CHANGED
|
@@ -602,7 +602,8 @@ export function renderRaci(
|
|
|
602
602
|
parsed.roles.forEach((roleId, i) => {
|
|
603
603
|
const cx = roleX(i) + COLUMN_INSET;
|
|
604
604
|
const cw = roleColW - 2 * COLUMN_INSET;
|
|
605
|
-
// Per-role color from `Cap
|
|
605
|
+
// Per-role color from `Cap blue` trailing-token (or `Cap | color: blue`)
|
|
606
|
+
// syntax. When the user provides
|
|
606
607
|
// one, it wins; otherwise rotate through marker-safe accents so
|
|
607
608
|
// each column has a subtle visual identity instead of every column
|
|
608
609
|
// reading as the same neutral gray.
|
|
@@ -1150,7 +1151,7 @@ function renderTaskRow(
|
|
|
1150
1151
|
surfaceBg: string,
|
|
1151
1152
|
solid: boolean,
|
|
1152
1153
|
taskDiagnostics: Map<string, TaskDiagnosticBucket> | null,
|
|
1153
|
-
|
|
1154
|
+
_hasAnyDiagnostic: boolean,
|
|
1154
1155
|
rowContent: RowContent | undefined,
|
|
1155
1156
|
onClickLine?: (lineNumber: number) => void,
|
|
1156
1157
|
_onMarkerDragStart?: (source: RaciDragSource, e: PointerEvent) => void
|
package/src/raci/types.ts
CHANGED
|
@@ -67,9 +67,10 @@ export interface ParsedRaci {
|
|
|
67
67
|
/** Display name for each role (parallel to `roles`). */
|
|
68
68
|
roleDisplayNames: string[];
|
|
69
69
|
/**
|
|
70
|
-
* Optional per-role palette color from `Cap
|
|
71
|
-
* roles block
|
|
72
|
-
*
|
|
70
|
+
* Optional per-role palette color from the `Cap blue` trailing-token
|
|
71
|
+
* suffix in the roles block (or the long pipe form `Cap | color: blue`).
|
|
72
|
+
* Parallel to `roles`; entries default to `undefined` (renderer falls
|
|
73
|
+
* back to the neutral column tint).
|
|
73
74
|
*/
|
|
74
75
|
roleColors: Array<string | undefined>;
|
|
75
76
|
phases: RaciPhase[];
|
package/src/ring/parser.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
measureIndent,
|
|
9
9
|
parseFirstLine,
|
|
10
10
|
parsePipeMetadata,
|
|
11
|
+
peelTrailingColorName,
|
|
11
12
|
tryParseSharedOption,
|
|
12
13
|
PIPE_KEY_VALUE_PREFIX_RE,
|
|
13
14
|
PIPE_LIKELY_STRUCTURED_TAIL_RE,
|
|
@@ -175,6 +176,17 @@ export function parseRing(content: string): ParsedRing {
|
|
|
175
176
|
continue;
|
|
176
177
|
}
|
|
177
178
|
|
|
179
|
+
// Universal trailing-token shortcut: `Label color` equivalent to
|
|
180
|
+
// `Label | color: <name>` when color is not already set (§1.5).
|
|
181
|
+
if (!color) {
|
|
182
|
+
const { label: stripped, colorName: shortcutColor } =
|
|
183
|
+
peelTrailingColorName(label);
|
|
184
|
+
if (shortcutColor) {
|
|
185
|
+
color = shortcutColor;
|
|
186
|
+
label = stripped;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
178
190
|
currentLayer = {
|
|
179
191
|
label,
|
|
180
192
|
lineNumber: lineNum,
|