@diagrammo/dgmo 0.14.1 → 0.15.1
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 +14 -1
- package/dist/advanced.cjs +53069 -0
- package/dist/advanced.d.cts +4691 -0
- package/dist/advanced.d.ts +4691 -0
- package/dist/advanced.js +52823 -0
- package/dist/auto.cjs +1557 -1295
- package/dist/auto.js +132 -713
- package/dist/auto.mjs +1553 -1291
- package/dist/cli.cjs +173 -150
- package/dist/editor.cjs +1 -0
- package/dist/editor.js +1 -0
- package/dist/highlight.cjs +1 -0
- package/dist/highlight.js +1 -0
- package/dist/index.cjs +2031 -4722
- package/dist/index.d.cts +96 -4464
- package/dist/index.d.ts +96 -4464
- package/dist/index.js +2024 -4475
- package/dist/internal.cjs +51930 -553
- package/dist/internal.d.cts +4526 -102
- package/dist/internal.d.ts +4526 -102
- package/dist/internal.js +51721 -548
- package/dist/pert.cjs +1 -1
- package/dist/pert.js +1 -1
- package/docs/language-reference.md +67 -17
- package/package.json +18 -3
- package/src/advanced.ts +731 -0
- package/src/auto/index.ts +14 -13
- package/src/boxes-and-lines/layout.ts +481 -445
- package/src/c4/parser.ts +7 -7
- package/src/chart-types.ts +0 -5
- package/src/class/parser.ts +1 -9
- package/src/cli.ts +9 -7
- package/src/completion-types.ts +28 -0
- package/src/completion.ts +15 -18
- package/src/cycle/layout.ts +2 -2
- package/src/d3.ts +1455 -1122
- package/src/echarts.ts +11 -11
- package/src/editor/keywords.ts +1 -0
- package/src/er/parser.ts +1 -9
- package/src/er/renderer.ts +1 -1
- package/src/gantt/calculator.ts +1 -11
- package/src/gantt/parser.ts +16 -16
- package/src/gantt/renderer.ts +2 -2
- package/src/graph/flowchart-parser.ts +1 -1
- package/src/graph/flowchart-renderer.ts +1 -1
- package/src/graph/state-renderer.ts +1 -1
- package/src/index.ts +213 -690
- package/src/infra/parser.ts +57 -25
- package/src/infra/renderer.ts +2 -2
- package/src/internal.ts +11 -17
- package/src/kanban/parser.ts +2 -2
- package/src/mindmap/layout.ts +1 -1
- package/src/mindmap/parser.ts +1 -1
- package/src/org/parser.ts +1 -1
- package/src/org/renderer.ts +1 -1
- package/src/palettes/index.ts +39 -0
- package/src/pert/layout.ts +1 -1
- package/src/pert/monte-carlo.ts +2 -2
- package/src/pert/parser.ts +3 -3
- package/src/raci/parser.ts +4 -4
- package/src/raci/renderer.ts +1 -1
- package/src/render.ts +17 -1
- package/src/sequence/renderer.ts +1 -4
- package/src/sitemap/parser.ts +1 -1
- package/src/tech-radar/interactive.ts +1 -1
- package/src/tech-radar/renderer.ts +1 -1
- package/src/themes.ts +22 -0
- package/src/utils/tag-groups.ts +11 -12
- package/src/wireframe/layout.ts +11 -7
- package/src/wireframe/parser.ts +2 -2
- package/src/wireframe/renderer.ts +5 -2
package/src/infra/parser.ts
CHANGED
|
@@ -194,6 +194,24 @@ export function parseInfra(content: string): ParsedInfra {
|
|
|
194
194
|
if (!m) return { label: trimmed };
|
|
195
195
|
return { label: m[1].trim(), alias: m[2] };
|
|
196
196
|
}
|
|
197
|
+
|
|
198
|
+
// Infra nodes have no "is a <type>" declaration — capability comes from
|
|
199
|
+
// properties (cache-hit, buffer, drain-rate, …). Strip the suffix if a
|
|
200
|
+
// user wrote it (likely copying from sequence/c4 syntax) and warn.
|
|
201
|
+
const IS_A_SUFFIX = /^(.*?)\s+is\s+an?\s+[A-Za-z][\w-]*\s*$/i;
|
|
202
|
+
function peelInfraDecorations(
|
|
203
|
+
rawName: string,
|
|
204
|
+
lineNumber: number
|
|
205
|
+
): { label: string; alias?: string } {
|
|
206
|
+
const peeled = peelAlias(rawName);
|
|
207
|
+
const m = peeled.label.match(IS_A_SUFFIX);
|
|
208
|
+
if (!m) return peeled;
|
|
209
|
+
warn(
|
|
210
|
+
lineNumber,
|
|
211
|
+
`Infra nodes don't use 'is a <type>' — types are inferred from properties (cache-hit, buffer, drain-rate, …). Drop the 'is a' suffix.`
|
|
212
|
+
);
|
|
213
|
+
return { label: m[1].trim(), alias: peeled.alias };
|
|
214
|
+
}
|
|
197
215
|
/**
|
|
198
216
|
* Resolve a connection-target token. If the token exactly matches a
|
|
199
217
|
* declared alias, return the bound canonical id. Otherwise fall
|
|
@@ -333,11 +351,11 @@ export function parseInfra(content: string): ParsedInfra {
|
|
|
333
351
|
|
|
334
352
|
// animate (default ON) / no-animate
|
|
335
353
|
if (trimmed === 'animate') {
|
|
336
|
-
result.options
|
|
354
|
+
result.options['animate'] = 'on';
|
|
337
355
|
continue;
|
|
338
356
|
}
|
|
339
357
|
if (trimmed === 'no-animate') {
|
|
340
|
-
result.options
|
|
358
|
+
result.options['animate'] = 'off';
|
|
341
359
|
continue;
|
|
342
360
|
}
|
|
343
361
|
|
|
@@ -399,7 +417,7 @@ export function parseInfra(content: string): ParsedInfra {
|
|
|
399
417
|
finishCurrentTagGroup();
|
|
400
418
|
|
|
401
419
|
const rawName = (compMatch[1] ?? compMatch[2] ?? '').trim();
|
|
402
|
-
const peeled =
|
|
420
|
+
const peeled = peelInfraDecorations(rawName, lineNumber);
|
|
403
421
|
const name = peeled.label;
|
|
404
422
|
const rest = compMatch[3] || '';
|
|
405
423
|
const { tags } = extractPipeMetadata(rest);
|
|
@@ -482,7 +500,7 @@ export function parseInfra(content: string): ParsedInfra {
|
|
|
482
500
|
if (compMatch) {
|
|
483
501
|
finishCurrentTagGroup();
|
|
484
502
|
const rawName = (compMatch[1] ?? compMatch[2] ?? '').trim();
|
|
485
|
-
const peeled =
|
|
503
|
+
const peeled = peelInfraDecorations(rawName, lineNumber);
|
|
486
504
|
const name = peeled.label;
|
|
487
505
|
const rest = compMatch[3] || '';
|
|
488
506
|
const { tags: nodeTags } = extractPipeMetadata(rest);
|
|
@@ -532,11 +550,11 @@ export function parseInfra(content: string): ParsedInfra {
|
|
|
532
550
|
const pipeMeta = extractPipeMetadata(targetRaw);
|
|
533
551
|
const targetName = pipeMeta.clean || targetRaw;
|
|
534
552
|
warnUnparsedPipeMeta(targetName, lineNumber, warn);
|
|
535
|
-
const split = pipeMeta.tags
|
|
536
|
-
? parseFloat(pipeMeta.tags
|
|
553
|
+
const split = pipeMeta.tags['split']
|
|
554
|
+
? parseFloat(pipeMeta.tags['split'])
|
|
537
555
|
: null;
|
|
538
|
-
const fanoutRaw = pipeMeta.tags
|
|
539
|
-
? parseInt(pipeMeta.tags
|
|
556
|
+
const fanoutRaw = pipeMeta.tags['fanout']
|
|
557
|
+
? parseInt(pipeMeta.tags['fanout'], 10)
|
|
540
558
|
: null;
|
|
541
559
|
if (fanoutRaw !== null && fanoutRaw < 1) {
|
|
542
560
|
warn(
|
|
@@ -570,11 +588,11 @@ export function parseInfra(content: string): ParsedInfra {
|
|
|
570
588
|
const pipeMeta = extractPipeMetadata(targetRaw);
|
|
571
589
|
const targetName = pipeMeta.clean || targetRaw;
|
|
572
590
|
warnUnparsedPipeMeta(targetName, lineNumber, warn);
|
|
573
|
-
const split = pipeMeta.tags
|
|
574
|
-
? parseFloat(pipeMeta.tags
|
|
591
|
+
const split = pipeMeta.tags['split']
|
|
592
|
+
? parseFloat(pipeMeta.tags['split'])
|
|
575
593
|
: null;
|
|
576
|
-
const fanoutRaw = pipeMeta.tags
|
|
577
|
-
? parseInt(pipeMeta.tags
|
|
594
|
+
const fanoutRaw = pipeMeta.tags['fanout']
|
|
595
|
+
? parseInt(pipeMeta.tags['fanout'], 10)
|
|
578
596
|
: null;
|
|
579
597
|
if (fanoutRaw !== null && fanoutRaw < 1) {
|
|
580
598
|
warn(
|
|
@@ -613,11 +631,11 @@ export function parseInfra(content: string): ParsedInfra {
|
|
|
613
631
|
const pipeMeta = extractPipeMetadata(targetRaw);
|
|
614
632
|
const targetName = pipeMeta.clean || targetRaw;
|
|
615
633
|
warnUnparsedPipeMeta(targetName, lineNumber, warn);
|
|
616
|
-
const split = pipeMeta.tags
|
|
617
|
-
? parseFloat(pipeMeta.tags
|
|
634
|
+
const split = pipeMeta.tags['split']
|
|
635
|
+
? parseFloat(pipeMeta.tags['split'])
|
|
618
636
|
: null;
|
|
619
|
-
const fanoutRaw = pipeMeta.tags
|
|
620
|
-
? parseInt(pipeMeta.tags
|
|
637
|
+
const fanoutRaw = pipeMeta.tags['fanout']
|
|
638
|
+
? parseInt(pipeMeta.tags['fanout'], 10)
|
|
621
639
|
: null;
|
|
622
640
|
if (fanoutRaw !== null && fanoutRaw < 1) {
|
|
623
641
|
warn(
|
|
@@ -651,11 +669,11 @@ export function parseInfra(content: string): ParsedInfra {
|
|
|
651
669
|
const pipeMeta = extractPipeMetadata(targetRaw);
|
|
652
670
|
const targetName = pipeMeta.clean || targetRaw;
|
|
653
671
|
warnUnparsedPipeMeta(targetName, lineNumber, warn);
|
|
654
|
-
const split = pipeMeta.tags
|
|
655
|
-
? parseFloat(pipeMeta.tags
|
|
672
|
+
const split = pipeMeta.tags['split']
|
|
673
|
+
? parseFloat(pipeMeta.tags['split'])
|
|
656
674
|
: null;
|
|
657
|
-
const fanoutRaw = pipeMeta.tags
|
|
658
|
-
? parseInt(pipeMeta.tags
|
|
675
|
+
const fanoutRaw = pipeMeta.tags['fanout']
|
|
676
|
+
? parseInt(pipeMeta.tags['fanout'], 10)
|
|
659
677
|
: null;
|
|
660
678
|
if (fanoutRaw !== null && fanoutRaw < 1) {
|
|
661
679
|
warn(
|
|
@@ -764,7 +782,7 @@ export function parseInfra(content: string): ParsedInfra {
|
|
|
764
782
|
const compMatch = trimmed.match(COMPONENT_RE);
|
|
765
783
|
if (compMatch) {
|
|
766
784
|
const rawName = (compMatch[1] ?? compMatch[2] ?? '').trim();
|
|
767
|
-
const peeled =
|
|
785
|
+
const peeled = peelInfraDecorations(rawName, lineNumber);
|
|
768
786
|
const name = peeled.label;
|
|
769
787
|
const rest = compMatch[3] || '';
|
|
770
788
|
const { tags: nodeTags } = extractPipeMetadata(rest);
|
|
@@ -796,10 +814,13 @@ export function parseInfra(content: string): ParsedInfra {
|
|
|
796
814
|
finishCurrentTagGroup();
|
|
797
815
|
currentGroup = null;
|
|
798
816
|
|
|
799
|
-
const
|
|
817
|
+
const rawName = (compMatch[1] ?? compMatch[2] ?? '').trim();
|
|
818
|
+
const peeled = peelInfraDecorations(rawName, lineNumber);
|
|
819
|
+
const name = peeled.label;
|
|
800
820
|
const rest = compMatch[3] || '';
|
|
801
821
|
const { tags } = extractPipeMetadata(rest);
|
|
802
822
|
const id = nodeId(name);
|
|
823
|
+
if (peeled.alias) nameAliasMap.set(peeled.alias, id);
|
|
803
824
|
|
|
804
825
|
currentNode = {
|
|
805
826
|
id,
|
|
@@ -871,12 +892,23 @@ export function parseInfra(content: string): ParsedInfra {
|
|
|
871
892
|
// Symbol extraction (for completion API)
|
|
872
893
|
// ============================================================
|
|
873
894
|
|
|
874
|
-
import type { DiagramSymbols } from '../completion';
|
|
895
|
+
import type { DiagramSymbols } from '../completion-types';
|
|
875
896
|
|
|
876
897
|
/**
|
|
877
898
|
* Extract component names (entities) from infra document text.
|
|
878
899
|
* Used by the dgmo completion API for ghost hints and popup completions.
|
|
879
900
|
*/
|
|
901
|
+
/** Strip ` as <alias>` and ` is a/an <type>` decorations from a node name
|
|
902
|
+
* so completion suggests the bare identifier the user will reference. */
|
|
903
|
+
function stripNodeDecorations(name: string): string {
|
|
904
|
+
let s = name.trim();
|
|
905
|
+
const aliasMatch = s.match(/^(.*?)\s+as\s+[A-Za-z][A-Za-z0-9_]{0,11}\s*$/);
|
|
906
|
+
if (aliasMatch) s = aliasMatch[1].trim();
|
|
907
|
+
const isAMatch = s.match(/^(.*?)\s+is\s+an?\s+[A-Za-z][\w-]*\s*$/i);
|
|
908
|
+
if (isAMatch) s = isAMatch[1].trim();
|
|
909
|
+
return s;
|
|
910
|
+
}
|
|
911
|
+
|
|
880
912
|
export function extractSymbols(docText: string): DiagramSymbols {
|
|
881
913
|
const entities: string[] = [];
|
|
882
914
|
let inMetadata = true;
|
|
@@ -916,7 +948,7 @@ export function extractSymbols(docText: string): DiagramSymbols {
|
|
|
916
948
|
if (/^\[/.test(line)) continue; // [Group] header
|
|
917
949
|
const m = COMPONENT_RE.exec(line);
|
|
918
950
|
if (m) {
|
|
919
|
-
const name = (m[1] ?? m[2] ?? '').trim();
|
|
951
|
+
const name = stripNodeDecorations((m[1] ?? m[2] ?? '').trim());
|
|
920
952
|
if (name && !entities.includes(name)) entities.push(name);
|
|
921
953
|
}
|
|
922
954
|
} else {
|
|
@@ -940,7 +972,7 @@ export function extractSymbols(docText: string): DiagramSymbols {
|
|
|
940
972
|
continue;
|
|
941
973
|
const m = COMPONENT_RE.exec(line);
|
|
942
974
|
if (m) {
|
|
943
|
-
const name = (m[1] ?? m[2] ?? '').trim();
|
|
975
|
+
const name = stripNodeDecorations((m[1] ?? m[2] ?? '').trim());
|
|
944
976
|
if (name && !entities.includes(name)) entities.push(name);
|
|
945
977
|
}
|
|
946
978
|
}
|
package/src/infra/renderer.ts
CHANGED
|
@@ -1165,7 +1165,7 @@ function renderEdgePaths(
|
|
|
1165
1165
|
nodes: InfraLayoutNode[],
|
|
1166
1166
|
groups: InfraLayoutGroup[],
|
|
1167
1167
|
palette: PaletteColors,
|
|
1168
|
-
|
|
1168
|
+
_isDark: boolean,
|
|
1169
1169
|
animate: boolean,
|
|
1170
1170
|
direction: 'LR' | 'TB',
|
|
1171
1171
|
speedMultiplier: number = 1
|
|
@@ -1245,7 +1245,7 @@ function renderEdgeLabels(
|
|
|
1245
1245
|
nodes: InfraLayoutNode[],
|
|
1246
1246
|
groups: InfraLayoutGroup[],
|
|
1247
1247
|
palette: PaletteColors,
|
|
1248
|
-
|
|
1248
|
+
_isDark: boolean,
|
|
1249
1249
|
animate: boolean,
|
|
1250
1250
|
direction: 'LR' | 'TB'
|
|
1251
1251
|
) {
|
package/src/internal.ts
CHANGED
|
@@ -1,20 +1,14 @@
|
|
|
1
1
|
// ============================================================
|
|
2
|
-
// @diagrammo/dgmo/internal —
|
|
3
|
-
//
|
|
2
|
+
// @diagrammo/dgmo/internal — DEPRECATED ALIAS for @diagrammo/dgmo/advanced
|
|
3
|
+
//
|
|
4
|
+
// This subpath was renamed to `/advanced` to match its actual contract
|
|
5
|
+
// ("low-level but supported" rather than "private"). Update your imports:
|
|
6
|
+
//
|
|
7
|
+
// import { … } from '@diagrammo/dgmo/internal';
|
|
8
|
+
// →
|
|
9
|
+
// import { … } from '@diagrammo/dgmo/advanced';
|
|
10
|
+
//
|
|
11
|
+
// The `/internal` subpath will be removed in 0.17.x.
|
|
4
12
|
// ============================================================
|
|
5
13
|
|
|
6
|
-
export
|
|
7
|
-
export {
|
|
8
|
-
computeCardArchive,
|
|
9
|
-
computeCardMove,
|
|
10
|
-
isArchiveColumn,
|
|
11
|
-
} from './kanban/mutations';
|
|
12
|
-
export {
|
|
13
|
-
applyGroupOrdering,
|
|
14
|
-
applyPositionOverrides,
|
|
15
|
-
buildNoteMessageMap,
|
|
16
|
-
buildRenderSequence,
|
|
17
|
-
computeActivations,
|
|
18
|
-
groupMessagesBySection,
|
|
19
|
-
} from './sequence/renderer';
|
|
20
|
-
export { orderArcNodes } from './d3';
|
|
14
|
+
export * from './advanced';
|
package/src/kanban/parser.ts
CHANGED
|
@@ -270,8 +270,8 @@ export function parseKanban(
|
|
|
270
270
|
parsePipeMetadata(pipeSegments, metaAliasMap)
|
|
271
271
|
);
|
|
272
272
|
// Extract wip from metadata
|
|
273
|
-
if (columnMetadata
|
|
274
|
-
const wipVal = parseInt(columnMetadata
|
|
273
|
+
if (columnMetadata['wip']) {
|
|
274
|
+
const wipVal = parseInt(columnMetadata['wip'], 10);
|
|
275
275
|
if (!isNaN(wipVal)) {
|
|
276
276
|
wipLimit = wipVal;
|
|
277
277
|
}
|
package/src/mindmap/layout.ts
CHANGED
package/src/mindmap/parser.ts
CHANGED
|
@@ -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/org/parser.ts
CHANGED
|
@@ -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
|
@@ -235,7 +235,7 @@ export function renderOrg(
|
|
|
235
235
|
const rootNodeIds = new Set(parsed.roots.map((r) => r.id));
|
|
236
236
|
|
|
237
237
|
// Render container backgrounds (bottom layer)
|
|
238
|
-
const colorOff = parsed.options?.color === 'off';
|
|
238
|
+
const colorOff = parsed.options?.['color'] === 'off';
|
|
239
239
|
for (const c of layout.containers) {
|
|
240
240
|
const cG = contentG
|
|
241
241
|
.append('g')
|
package/src/palettes/index.ts
CHANGED
|
@@ -34,3 +34,42 @@ export { tokyoNightPalette } from './tokyo-night';
|
|
|
34
34
|
|
|
35
35
|
export { draculaPalette } from './dracula';
|
|
36
36
|
export { monokaiPalette } from './monokai';
|
|
37
|
+
|
|
38
|
+
// ============================================================
|
|
39
|
+
// Public namespace — `palettes` for use with render()
|
|
40
|
+
// ============================================================
|
|
41
|
+
|
|
42
|
+
import { boldPalette } from './bold';
|
|
43
|
+
import { catppuccinPalette } from './catppuccin';
|
|
44
|
+
import { draculaPalette } from './dracula';
|
|
45
|
+
import { gruvboxPalette } from './gruvbox';
|
|
46
|
+
import { monokaiPalette } from './monokai';
|
|
47
|
+
import { nordPalette } from './nord';
|
|
48
|
+
import { oneDarkPalette } from './one-dark';
|
|
49
|
+
import { rosePinePalette } from './rose-pine';
|
|
50
|
+
import { solarizedPalette } from './solarized';
|
|
51
|
+
import { tokyoNightPalette } from './tokyo-night';
|
|
52
|
+
|
|
53
|
+
import type { PaletteConfig } from './types';
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* All built-in palettes, keyed by camelCase id. Use directly with render():
|
|
57
|
+
*
|
|
58
|
+
* await render(text, { palette: palettes.catppuccin });
|
|
59
|
+
*
|
|
60
|
+
* For preference/settings storage, the `.id` field of each entry is the
|
|
61
|
+
* canonical string (e.g. `'tokyo-night'`, `'nord'`) — that's the wire format
|
|
62
|
+
* used by share URLs and the CLI `--palette` flag.
|
|
63
|
+
*/
|
|
64
|
+
export const palettes = {
|
|
65
|
+
nord: nordPalette,
|
|
66
|
+
catppuccin: catppuccinPalette,
|
|
67
|
+
solarized: solarizedPalette,
|
|
68
|
+
gruvbox: gruvboxPalette,
|
|
69
|
+
tokyoNight: tokyoNightPalette,
|
|
70
|
+
oneDark: oneDarkPalette,
|
|
71
|
+
rosePine: rosePinePalette,
|
|
72
|
+
dracula: draculaPalette,
|
|
73
|
+
monokai: monokaiPalette,
|
|
74
|
+
bold: boldPalette,
|
|
75
|
+
} as const satisfies Record<string, PaletteConfig>;
|
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
|
|
@@ -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/raci/parser.ts
CHANGED
|
@@ -389,9 +389,9 @@ export function parseRaci(
|
|
|
389
389
|
let roleColor: string | undefined;
|
|
390
390
|
if (segments.length > 1) {
|
|
391
391
|
const meta = parsePipeMetadata(segments);
|
|
392
|
-
if (meta
|
|
392
|
+
if (meta['color']) {
|
|
393
393
|
roleColor = resolveColorWithDiagnostic(
|
|
394
|
-
meta
|
|
394
|
+
meta['color'],
|
|
395
395
|
j + 1,
|
|
396
396
|
result.diagnostics,
|
|
397
397
|
palette
|
|
@@ -473,9 +473,9 @@ export function parseRaci(
|
|
|
473
473
|
let phaseColor: string | undefined;
|
|
474
474
|
if (phaseMatch[2]) {
|
|
475
475
|
const meta = parsePipeMetadata(['', phaseMatch[2]]);
|
|
476
|
-
if (meta
|
|
476
|
+
if (meta['color']) {
|
|
477
477
|
phaseColor = resolveColorWithDiagnostic(
|
|
478
|
-
meta
|
|
478
|
+
meta['color'],
|
|
479
479
|
lineNumber,
|
|
480
480
|
result.diagnostics,
|
|
481
481
|
palette
|
package/src/raci/renderer.ts
CHANGED
|
@@ -1150,7 +1150,7 @@ function renderTaskRow(
|
|
|
1150
1150
|
surfaceBg: string,
|
|
1151
1151
|
solid: boolean,
|
|
1152
1152
|
taskDiagnostics: Map<string, TaskDiagnosticBucket> | null,
|
|
1153
|
-
|
|
1153
|
+
_hasAnyDiagnostic: boolean,
|
|
1154
1154
|
rowContent: RowContent | undefined,
|
|
1155
1155
|
onClickLine?: (lineNumber: number) => void,
|
|
1156
1156
|
_onMarkerDragStart?: (source: RaciDragSource, e: PointerEvent) => void
|
package/src/render.ts
CHANGED
|
@@ -13,7 +13,7 @@ import type { CompactViewState } from './sharing';
|
|
|
13
13
|
async function ensureDom(): Promise<void> {
|
|
14
14
|
if (typeof document !== 'undefined') return;
|
|
15
15
|
|
|
16
|
-
const { JSDOM } = await
|
|
16
|
+
const { JSDOM } = await loadJsdom();
|
|
17
17
|
const dom = new JSDOM('<!DOCTYPE html><html><body></body></html>');
|
|
18
18
|
const win = dom.window;
|
|
19
19
|
|
|
@@ -39,6 +39,22 @@ async function ensureDom(): Promise<void> {
|
|
|
39
39
|
});
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Load jsdom server-side. The specifier is constructed at runtime so
|
|
44
|
+
* downstream bundlers (Vite, Rollup, esbuild, webpack) cannot statically
|
|
45
|
+
* resolve it. Without this indirection, every browser bundle of
|
|
46
|
+
* @diagrammo/dgmo emits a 5+ MB jsdom chunk even though `ensureDom()`
|
|
47
|
+
* guards execution with a `typeof document` check — the guard prevents
|
|
48
|
+
* runtime evaluation, but the static dependency edge still pulls jsdom
|
|
49
|
+
* into the bundle.
|
|
50
|
+
*/
|
|
51
|
+
async function loadJsdom(): Promise<typeof import('jsdom')> {
|
|
52
|
+
const spec = ['js', 'dom'].join('');
|
|
53
|
+
return import(/* @vite-ignore */ /* webpackIgnore: true */ spec) as Promise<
|
|
54
|
+
typeof import('jsdom')
|
|
55
|
+
>;
|
|
56
|
+
}
|
|
57
|
+
|
|
42
58
|
/**
|
|
43
59
|
* Render DGMO source to an SVG string.
|
|
44
60
|
*
|
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
|
package/src/sitemap/parser.ts
CHANGED
|
@@ -566,7 +566,7 @@ export function parseSitemap(
|
|
|
566
566
|
function parseNodeLabel(
|
|
567
567
|
trimmed: string,
|
|
568
568
|
lineNumber: number,
|
|
569
|
-
|
|
569
|
+
_palette: PaletteColors | undefined,
|
|
570
570
|
counter: number,
|
|
571
571
|
metaAliasMap: Map<string, string> = new Map(),
|
|
572
572
|
warnFn?: (line: number, msg: string) => void,
|
|
@@ -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';
|
package/src/themes.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme — render mode flag. Selects which palette variant the renderer uses
|
|
3
|
+
* for background and text:
|
|
4
|
+
* - 'light' → palette.light colors
|
|
5
|
+
* - 'dark' → palette.dark colors
|
|
6
|
+
* - 'transparent' → no background fill (for embedding in colored containers)
|
|
7
|
+
*/
|
|
8
|
+
export type Theme = 'light' | 'dark' | 'transparent';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* `themes` namespace — use with render() options for a typed handle:
|
|
12
|
+
*
|
|
13
|
+
* await render(text, { theme: themes.dark });
|
|
14
|
+
*
|
|
15
|
+
* Passing the raw string `'dark'` also works (the underlying type is the
|
|
16
|
+
* string-literal union); the namespace is the conventional path.
|
|
17
|
+
*/
|
|
18
|
+
export const themes = {
|
|
19
|
+
light: 'light',
|
|
20
|
+
dark: 'dark',
|
|
21
|
+
transparent: 'transparent',
|
|
22
|
+
} as const satisfies Record<string, Theme>;
|
package/src/utils/tag-groups.ts
CHANGED
|
@@ -418,25 +418,21 @@ export function injectDefaultTagMetadata(
|
|
|
418
418
|
*
|
|
419
419
|
* 1. Programmatic override (from render API / CLI flag) — highest priority
|
|
420
420
|
* 2. Diagram-level `active-tag` option (from parsed source)
|
|
421
|
-
* 3.
|
|
421
|
+
* 3. Auto-activate first declared tag group
|
|
422
|
+
* 4. No coloring (null)
|
|
422
423
|
*
|
|
423
424
|
* The sentinel value `"none"` (case-insensitive) at any level means
|
|
424
|
-
* "suppress tag coloring."
|
|
425
|
+
* "suppress tag coloring." Diagrams with tag groups render colored by
|
|
426
|
+
* default across every render path (CLI, export, share-link, app); use
|
|
427
|
+
* `active-tag none` to opt out.
|
|
425
428
|
*
|
|
426
|
-
*
|
|
427
|
-
* opt-in: either the source carries `active-tag <name>` or the caller
|
|
428
|
-
* (typically the app on user click) supplies a programmatic override.
|
|
429
|
-
* Static exports therefore render the legend as a row of collapsed
|
|
430
|
-
* pills with nodes uncolored — consistent with the app's pre-click
|
|
431
|
-
* default.
|
|
432
|
-
*
|
|
433
|
-
* @param _tagGroups Declared tag groups (kept for API stability; unused since auto-activation removed)
|
|
429
|
+
* @param tagGroups Declared tag groups (only `.name` is used)
|
|
434
430
|
* @param explicitActiveTag Value of `active-tag` option from parsed diagram, if any
|
|
435
431
|
* @param programmaticOverride Value from render API / CLI; `undefined` = not set,
|
|
436
432
|
* `null` or `''` = explicitly no coloring
|
|
437
433
|
*/
|
|
438
434
|
export function resolveActiveTagGroup(
|
|
439
|
-
|
|
435
|
+
tagGroups: ReadonlyArray<{ name: string }>,
|
|
440
436
|
explicitActiveTag: string | undefined,
|
|
441
437
|
programmaticOverride?: string | null
|
|
442
438
|
): string | null {
|
|
@@ -453,7 +449,10 @@ export function resolveActiveTagGroup(
|
|
|
453
449
|
return explicitActiveTag;
|
|
454
450
|
}
|
|
455
451
|
|
|
456
|
-
// 3.
|
|
452
|
+
// 3. Auto-activate first declared group
|
|
453
|
+
if (tagGroups.length > 0) return tagGroups[0].name;
|
|
454
|
+
|
|
455
|
+
// 4. No tag groups → no coloring
|
|
457
456
|
return null;
|
|
458
457
|
}
|
|
459
458
|
|
package/src/wireframe/layout.ts
CHANGED
|
@@ -333,7 +333,8 @@ function layoutElement(
|
|
|
333
333
|
|
|
334
334
|
// Container — layout children
|
|
335
335
|
const isInlineRow =
|
|
336
|
-
el.metadata
|
|
336
|
+
el.metadata['_inlineRow'] === 'true' ||
|
|
337
|
+
el.metadata['_labelField'] === 'true';
|
|
337
338
|
const padTop = isInlineRow ? 0 : GROUP_PADDING_TOP;
|
|
338
339
|
const padBottom = isInlineRow ? 0 : GROUP_PADDING_BOTTOM;
|
|
339
340
|
const padX = isInlineRow ? 0 : GROUP_PADDING_X;
|
|
@@ -402,8 +403,8 @@ function allocateEqualWidths(
|
|
|
402
403
|
function getElementHeight(el: WireframeElement): number {
|
|
403
404
|
if (el.type === 'heading') {
|
|
404
405
|
return el.headingLevel === 2
|
|
405
|
-
? (ELEMENT_HEIGHTS
|
|
406
|
-
: (ELEMENT_HEIGHTS
|
|
406
|
+
? (ELEMENT_HEIGHTS['subheading'] ?? 36)
|
|
407
|
+
: (ELEMENT_HEIGHTS['heading'] ?? 48);
|
|
407
408
|
}
|
|
408
409
|
|
|
409
410
|
if (el.type === 'textInput' && el.fieldVariant === 'textarea') {
|
|
@@ -421,11 +422,11 @@ function getElementHeight(el: WireframeElement): number {
|
|
|
421
422
|
if (el.type === 'image') {
|
|
422
423
|
if (el.imageHint === 'round') return 80;
|
|
423
424
|
if (el.imageHint === 'wide') return 80;
|
|
424
|
-
return ELEMENT_HEIGHTS
|
|
425
|
+
return ELEMENT_HEIGHTS['image'] ?? 120;
|
|
425
426
|
}
|
|
426
427
|
|
|
427
428
|
// Label-field wrapper
|
|
428
|
-
if (el.metadata
|
|
429
|
+
if (el.metadata['_labelField'] === 'true') {
|
|
429
430
|
return 36; // input height
|
|
430
431
|
}
|
|
431
432
|
|
|
@@ -434,7 +435,7 @@ function getElementHeight(el: WireframeElement): number {
|
|
|
434
435
|
|
|
435
436
|
function getSpacingAfter(el: WireframeElement): number {
|
|
436
437
|
if (el.type === 'heading' && el.headingLevel === 2) {
|
|
437
|
-
return SPACING_AFTER
|
|
438
|
+
return SPACING_AFTER['subheading'] ?? 12;
|
|
438
439
|
}
|
|
439
440
|
return SPACING_AFTER[el.type] ?? 8;
|
|
440
441
|
}
|
|
@@ -448,7 +449,10 @@ function computeFieldAlignX(children: WireframeElement[]): number {
|
|
|
448
449
|
let labelFieldCount = 0;
|
|
449
450
|
|
|
450
451
|
for (const child of children) {
|
|
451
|
-
if (
|
|
452
|
+
if (
|
|
453
|
+
child.metadata['_labelField'] === 'true' &&
|
|
454
|
+
child.children.length >= 2
|
|
455
|
+
) {
|
|
452
456
|
const labelEl = child.children[0];
|
|
453
457
|
const labelWidth = labelEl.label.length * CHAR_WIDTH;
|
|
454
458
|
maxLabelWidth = Math.max(maxLabelWidth, labelWidth);
|
package/src/wireframe/parser.ts
CHANGED
|
@@ -650,7 +650,7 @@ export function parseWireframe(content: string): ParsedWireframe {
|
|
|
650
650
|
wrapper.isContainer = true;
|
|
651
651
|
wrapper.orientation = 'horizontal';
|
|
652
652
|
wrapper.children = children;
|
|
653
|
-
wrapper.metadata
|
|
653
|
+
wrapper.metadata['_inlineRow'] = 'true';
|
|
654
654
|
pushElement(wrapper);
|
|
655
655
|
}
|
|
656
656
|
|
|
@@ -852,7 +852,7 @@ export function parseWireframe(content: string): ParsedWireframe {
|
|
|
852
852
|
wrapper.isContainer = true;
|
|
853
853
|
wrapper.orientation = 'horizontal';
|
|
854
854
|
wrapper.children.push(labelEl, fieldEl);
|
|
855
|
-
wrapper.metadata
|
|
855
|
+
wrapper.metadata['_labelField'] = 'true';
|
|
856
856
|
pushElement(wrapper);
|
|
857
857
|
}
|
|
858
858
|
} else {
|