@diagrammo/dgmo 0.4.3 → 0.4.4
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/dist/cli.cjs +107 -107
- package/dist/index.cjs +40 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +40 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/infra/layout.ts +6 -3
- package/src/infra/parser.ts +2 -2
- package/src/infra/renderer.ts +52 -8
- package/src/sharing.ts +8 -0
package/package.json
CHANGED
package/src/infra/layout.ts
CHANGED
|
@@ -335,7 +335,7 @@ function formatUptime(fraction: number): string {
|
|
|
335
335
|
// Layout engine
|
|
336
336
|
// ============================================================
|
|
337
337
|
|
|
338
|
-
export function layoutInfra(computed: ComputedInfraModel, selectedNodeId?: string | null): InfraLayoutResult {
|
|
338
|
+
export function layoutInfra(computed: ComputedInfraModel, selectedNodeId?: string | null, collapsedNodes?: Set<string> | null): InfraLayoutResult {
|
|
339
339
|
if (computed.nodes.length === 0) {
|
|
340
340
|
return { nodes: [], edges: [], groups: [], options: {}, width: 0, height: 0 };
|
|
341
341
|
}
|
|
@@ -363,9 +363,12 @@ export function layoutInfra(computed: ComputedInfraModel, selectedNodeId?: strin
|
|
|
363
363
|
const widthMap = new Map<string, number>();
|
|
364
364
|
const heightMap = new Map<string, number>();
|
|
365
365
|
for (const node of computed.nodes) {
|
|
366
|
-
const
|
|
366
|
+
const isNodeCollapsed = collapsedNodes?.has(node.id) ?? false;
|
|
367
|
+
const expanded = !isNodeCollapsed && node.id === selectedNodeId;
|
|
367
368
|
const width = computeNodeWidth(node, expanded, computed.options);
|
|
368
|
-
const height =
|
|
369
|
+
const height = isNodeCollapsed
|
|
370
|
+
? NODE_HEADER_HEIGHT + NODE_PAD_BOTTOM
|
|
371
|
+
: computeNodeHeight(node, expanded, computed.options);
|
|
369
372
|
widthMap.set(node.id, width);
|
|
370
373
|
heightMap.set(node.id, height);
|
|
371
374
|
const inGroup = groupedNodeIds.has(node.id);
|
package/src/infra/parser.ts
CHANGED
|
@@ -43,8 +43,8 @@ const TAG_VALUE_RE = /^(\w[\w\s]*?)(?:\(([^)]+)\))?(\s+default)?\s*$/;
|
|
|
43
43
|
// Component line: ComponentName or ComponentName | t: Backend | env: Prod
|
|
44
44
|
const COMPONENT_RE = /^([a-zA-Z_][\w]*)(.*)$/;
|
|
45
45
|
|
|
46
|
-
// Pipe metadata: | key: value
|
|
47
|
-
const PIPE_META_RE =
|
|
46
|
+
// Pipe metadata: | key: value or | k1: v1, k2: v2 (comma-separated)
|
|
47
|
+
const PIPE_META_RE = /[|,]\s*(\w+)\s*:\s*([^|,]+)/g;
|
|
48
48
|
|
|
49
49
|
// Property: key: value
|
|
50
50
|
const PROPERTY_RE = /^([\w-]+)\s*:\s*(.+)$/;
|
package/src/infra/renderer.ts
CHANGED
|
@@ -606,6 +606,23 @@ function renderEdgeLabels(
|
|
|
606
606
|
}
|
|
607
607
|
}
|
|
608
608
|
|
|
609
|
+
/** Returns the resolved tag color for a node's active tag group, or null if not applicable. */
|
|
610
|
+
function resolveActiveTagStroke(
|
|
611
|
+
node: InfraLayoutNode,
|
|
612
|
+
activeGroup: string,
|
|
613
|
+
tagGroups: InfraTagGroup[],
|
|
614
|
+
palette: PaletteColors,
|
|
615
|
+
): string | null {
|
|
616
|
+
const tg = tagGroups.find((t) => t.name.toLowerCase() === activeGroup.toLowerCase());
|
|
617
|
+
if (!tg) return null;
|
|
618
|
+
const tagKey = (tg.alias ?? tg.name).toLowerCase();
|
|
619
|
+
const tagVal = node.tags[tagKey];
|
|
620
|
+
if (!tagVal) return null;
|
|
621
|
+
const tv = tg.values.find((v) => v.name.toLowerCase() === tagVal.toLowerCase());
|
|
622
|
+
if (!tv?.color) return null;
|
|
623
|
+
return resolveColor(tv.color, palette);
|
|
624
|
+
}
|
|
625
|
+
|
|
609
626
|
function renderNodes(
|
|
610
627
|
svg: d3Selection.Selection<SVGGElement, unknown, null, undefined>,
|
|
611
628
|
nodes: InfraLayoutNode[],
|
|
@@ -615,11 +632,22 @@ function renderNodes(
|
|
|
615
632
|
selectedNodeId?: string | null,
|
|
616
633
|
activeGroup?: string | null,
|
|
617
634
|
diagramOptions?: Record<string, string>,
|
|
635
|
+
collapsedNodes?: Set<string> | null,
|
|
636
|
+
tagGroups?: InfraTagGroup[],
|
|
618
637
|
) {
|
|
619
638
|
const mutedColor = palette.textMuted;
|
|
620
639
|
|
|
621
640
|
for (const node of nodes) {
|
|
622
|
-
|
|
641
|
+
let { fill, stroke, textFill } = nodeColor(node, palette, isDark);
|
|
642
|
+
|
|
643
|
+
// When a tag legend is active, override border color with tag color
|
|
644
|
+
if (activeGroup && tagGroups && !node.isEdge) {
|
|
645
|
+
const tagStroke = resolveActiveTagStroke(node, activeGroup, tagGroups, palette);
|
|
646
|
+
if (tagStroke) {
|
|
647
|
+
stroke = tagStroke;
|
|
648
|
+
fill = mix(palette.bg, tagStroke, isDark ? 88 : 94);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
623
651
|
let cls = 'infra-node';
|
|
624
652
|
if (animate && node.isEdge) {
|
|
625
653
|
cls += ' infra-node-edge-throb';
|
|
@@ -632,12 +660,13 @@ function renderNodes(
|
|
|
632
660
|
const g = svg.append('g')
|
|
633
661
|
.attr('class', cls)
|
|
634
662
|
.attr('data-line-number', node.lineNumber)
|
|
635
|
-
.attr('data-infra-node', node.id)
|
|
663
|
+
.attr('data-infra-node', node.id)
|
|
664
|
+
.attr('data-node-collapse', node.id)
|
|
665
|
+
.style('cursor', 'pointer');
|
|
636
666
|
|
|
637
|
-
// Collapsed group nodes: toggle attribute
|
|
667
|
+
// Collapsed group nodes: toggle attribute
|
|
638
668
|
if (node.id.startsWith('[')) {
|
|
639
|
-
g.attr('data-node-toggle', node.id)
|
|
640
|
-
.style('cursor', 'pointer');
|
|
669
|
+
g.attr('data-node-toggle', node.id);
|
|
641
670
|
}
|
|
642
671
|
|
|
643
672
|
// Expose tag values for legend hover dimming
|
|
@@ -681,8 +710,22 @@ function renderNodes(
|
|
|
681
710
|
.attr('fill', textFill)
|
|
682
711
|
.text(node.label);
|
|
683
712
|
|
|
684
|
-
// --- Key-value rows below header ---
|
|
685
|
-
|
|
713
|
+
// --- Key-value rows below header (skipped for collapsed nodes) ---
|
|
714
|
+
const isNodeCollapsed = collapsedNodes?.has(node.id) ?? false;
|
|
715
|
+
if (isNodeCollapsed) {
|
|
716
|
+
// Collapsed: show a subtle chevron indicator at the bottom of the header
|
|
717
|
+
const chevronY = y + node.height - 6;
|
|
718
|
+
g.append('text')
|
|
719
|
+
.attr('x', node.x)
|
|
720
|
+
.attr('y', chevronY)
|
|
721
|
+
.attr('text-anchor', 'middle')
|
|
722
|
+
.attr('font-family', FONT_FAMILY)
|
|
723
|
+
.attr('font-size', 8)
|
|
724
|
+
.attr('fill', textFill)
|
|
725
|
+
.attr('opacity', 0.5)
|
|
726
|
+
.text('▼');
|
|
727
|
+
}
|
|
728
|
+
if (!isNodeCollapsed) {
|
|
686
729
|
const expanded = node.id === selectedNodeId;
|
|
687
730
|
// Declared properties only shown when node is selected (expanded)
|
|
688
731
|
const displayProps = (!node.isEdge && expanded) ? getDisplayProps(node, expanded, diagramOptions) : [];
|
|
@@ -1380,6 +1423,7 @@ export function renderInfra(
|
|
|
1380
1423
|
playback?: InfraPlaybackState | null,
|
|
1381
1424
|
selectedNodeId?: string | null,
|
|
1382
1425
|
exportMode?: boolean,
|
|
1426
|
+
collapsedNodes?: Set<string> | null,
|
|
1383
1427
|
) {
|
|
1384
1428
|
// Clear previous render (preserve tooltips if any)
|
|
1385
1429
|
d3Selection.select(container).selectAll(':not([data-d3-tooltip])').remove();
|
|
@@ -1470,7 +1514,7 @@ export function renderInfra(
|
|
|
1470
1514
|
// Render layers: groups (back), edge paths, nodes, reject particles, edge labels (front)
|
|
1471
1515
|
renderGroups(svg, layout.groups, palette, isDark);
|
|
1472
1516
|
renderEdgePaths(svg, layout.edges, layout.nodes, palette, isDark, shouldAnimate);
|
|
1473
|
-
renderNodes(svg, layout.nodes, palette, isDark, shouldAnimate, selectedNodeId, activeGroup, layout.options);
|
|
1517
|
+
renderNodes(svg, layout.nodes, palette, isDark, shouldAnimate, selectedNodeId, activeGroup, layout.options, collapsedNodes, tagGroups ?? []);
|
|
1474
1518
|
if (shouldAnimate) {
|
|
1475
1519
|
renderRejectParticles(svg, layout.nodes);
|
|
1476
1520
|
}
|
package/src/sharing.ts
CHANGED
|
@@ -8,6 +8,7 @@ const COMPRESSED_SIZE_LIMIT = 8192; // 8 KB
|
|
|
8
8
|
|
|
9
9
|
export interface DiagramViewState {
|
|
10
10
|
activeTagGroup?: string;
|
|
11
|
+
collapsedGroups?: string[];
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
export interface DecodedDiagramUrl {
|
|
@@ -47,6 +48,10 @@ export function encodeDiagramUrl(
|
|
|
47
48
|
hash += `&tag=${encodeURIComponent(options.viewState.activeTagGroup)}`;
|
|
48
49
|
}
|
|
49
50
|
|
|
51
|
+
if (options?.viewState?.collapsedGroups?.length) {
|
|
52
|
+
hash += `&cg=${encodeURIComponent(options.viewState.collapsedGroups.join(','))}`;
|
|
53
|
+
}
|
|
54
|
+
|
|
50
55
|
// Encode in both query param AND hash fragment — some share mechanisms
|
|
51
56
|
// strip one or the other (iOS share sheet strips #, AirDrop strips ?)
|
|
52
57
|
return { url: `${baseUrl}?${hash}#${hash}` };
|
|
@@ -89,6 +94,9 @@ export function decodeDiagramUrl(hash: string): DecodedDiagramUrl {
|
|
|
89
94
|
if (key === 'tag' && val) {
|
|
90
95
|
viewState.activeTagGroup = val;
|
|
91
96
|
}
|
|
97
|
+
if (key === 'cg' && val) {
|
|
98
|
+
viewState.collapsedGroups = val.split(',').filter(Boolean);
|
|
99
|
+
}
|
|
92
100
|
}
|
|
93
101
|
|
|
94
102
|
// Strip 'dgmo=' prefix
|