@diagrammo/dgmo 0.6.2 → 0.6.3
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/.claude/commands/dgmo.md +231 -13
- package/AGENTS.md +148 -0
- package/dist/cli.cjs +327 -153
- package/dist/index.cjs +305 -177
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -3
- package/dist/index.d.ts +24 -3
- package/dist/index.js +303 -177
- package/dist/index.js.map +1 -1
- package/package.json +5 -3
- package/src/c4/layout.ts +0 -5
- package/src/c4/parser.ts +0 -16
- package/src/c4/renderer.ts +1 -5
- package/src/class/layout.ts +0 -1
- package/src/class/parser.ts +28 -0
- package/src/class/renderer.ts +5 -26
- package/src/cli.ts +563 -14
- package/src/completion.ts +58 -0
- package/src/d3.ts +58 -106
- package/src/dgmo-router.ts +0 -57
- package/src/echarts.ts +96 -55
- package/src/er/parser.ts +30 -1
- package/src/er/renderer.ts +1 -2
- package/src/graph/flowchart-parser.ts +27 -4
- package/src/graph/flowchart-renderer.ts +1 -2
- package/src/graph/state-parser.ts +0 -1
- package/src/graph/state-renderer.ts +1 -3
- package/src/index.ts +10 -0
- package/src/infra/compute.ts +0 -7
- package/src/infra/layout.ts +0 -2
- package/src/infra/parser.ts +46 -4
- package/src/infra/renderer.ts +1 -15
- package/src/initiative-status/renderer.ts +5 -25
- package/src/kanban/parser.ts +0 -2
- package/src/org/layout.ts +0 -4
- package/src/org/renderer.ts +7 -28
- package/src/sequence/parser.ts +14 -11
- package/src/sequence/renderer.ts +0 -2
- package/src/sequence/tag-resolution.ts +0 -1
- package/src/sitemap/layout.ts +1 -14
- package/src/sitemap/parser.ts +1 -2
- package/src/sitemap/renderer.ts +0 -3
- package/src/utils/arrows.ts +7 -7
- package/src/utils/export-container.ts +40 -0
package/src/infra/renderer.ts
CHANGED
|
@@ -7,12 +7,10 @@ import * as d3Shape from 'd3-shape';
|
|
|
7
7
|
import { FONT_FAMILY } from '../fonts';
|
|
8
8
|
import type { PaletteColors } from '../palettes';
|
|
9
9
|
import { mix } from '../palettes/color-utils';
|
|
10
|
-
import type {
|
|
10
|
+
import type { InfraTagGroup } from './types';
|
|
11
11
|
import { resolveColor } from '../colors';
|
|
12
|
-
import type { ComputedInfraModel } from './types';
|
|
13
12
|
import type { InfraLayoutResult, InfraLayoutNode, InfraLayoutEdge, InfraLayoutGroup } from './layout';
|
|
14
13
|
import { inferRoles, collectDiagramRoles, collectFanoutSourceIds, FANOUT_ROLE } from './roles';
|
|
15
|
-
import type { InfraRole } from './roles';
|
|
16
14
|
import { parseInfra } from './parser';
|
|
17
15
|
import { computeInfra } from './compute';
|
|
18
16
|
import { layoutInfra } from './layout';
|
|
@@ -34,11 +32,9 @@ import {
|
|
|
34
32
|
// Constants
|
|
35
33
|
// ============================================================
|
|
36
34
|
|
|
37
|
-
const DIAGRAM_PADDING = 20;
|
|
38
35
|
const NODE_FONT_SIZE = 13;
|
|
39
36
|
const META_FONT_SIZE = 10;
|
|
40
37
|
const META_LINE_HEIGHT = 14;
|
|
41
|
-
const RPS_FONT_SIZE = 11;
|
|
42
38
|
const EDGE_LABEL_FONT_SIZE = 11;
|
|
43
39
|
const GROUP_LABEL_FONT_SIZE = 14;
|
|
44
40
|
const NODE_BORDER_RADIUS = 8;
|
|
@@ -58,8 +54,6 @@ const LEGEND_FIXED_GAP = 16; // gap between fixed legend and scaled diagram —
|
|
|
58
54
|
const COLOR_HEALTHY = '#22c55e';
|
|
59
55
|
const COLOR_WARNING = '#eab308';
|
|
60
56
|
const COLOR_OVERLOADED = '#ef4444';
|
|
61
|
-
const COLOR_NEUTRAL = '#94a3b8';
|
|
62
|
-
|
|
63
57
|
/** SLO thresholds resolved for a single node (chart-level + per-node override). */
|
|
64
58
|
interface NodeSlo {
|
|
65
59
|
availThreshold: number | null; // fraction e.g. 0.999
|
|
@@ -106,11 +100,8 @@ interface ComputedRow {
|
|
|
106
100
|
}
|
|
107
101
|
|
|
108
102
|
// Animation constants
|
|
109
|
-
const FLOW_DASH = '8 6'; // dash-array for animated edges
|
|
110
|
-
const FLOW_DASH_LEN = 14; // sum of dash + gap (for offset keyframe)
|
|
111
103
|
const FLOW_SPEED_MIN = 2.5; // seconds at max RPS
|
|
112
104
|
const FLOW_SPEED_MAX = 6; // seconds at min RPS
|
|
113
|
-
const OVERLOAD_PULSE_SPEED = 0.8; // seconds for overload pulse cycle
|
|
114
105
|
const PARTICLE_R = 5; // particle circle radius
|
|
115
106
|
const PARTICLE_COUNT_MIN = 1; // min particles per edge
|
|
116
107
|
const PARTICLE_COUNT_MAX = 4; // max particles per edge (at max RPS)
|
|
@@ -742,11 +733,6 @@ function getDisplayProps(node: InfraLayoutNode, expanded: boolean, diagramOption
|
|
|
742
733
|
}
|
|
743
734
|
|
|
744
735
|
|
|
745
|
-
function formatRps(rps: number): string {
|
|
746
|
-
if (rps >= 1000) return `${(rps / 1000).toFixed(1)}k rps`;
|
|
747
|
-
return `${Math.round(rps)} rps`;
|
|
748
|
-
}
|
|
749
|
-
|
|
750
736
|
/** RPS value without "rps" suffix — for key-value rows where the key already says "RPS". */
|
|
751
737
|
function formatRpsShort(rps: number): string {
|
|
752
738
|
if (rps >= 1000) return `${(rps / 1000).toFixed(1)}k`;
|
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
import * as d3Selection from 'd3-selection';
|
|
6
6
|
import * as d3Shape from 'd3-shape';
|
|
7
7
|
import { FONT_FAMILY } from '../fonts';
|
|
8
|
+
import { runInExportContainer, extractExportSvg } from '../utils/export-container';
|
|
8
9
|
import { contrastText, mix } from '../palettes/color-utils';
|
|
9
10
|
import type { PaletteColors } from '../palettes';
|
|
10
11
|
import type { ParsedInitiativeStatus, InitiativeStatus } from './types';
|
|
11
12
|
import type { ParticipantType } from '../sequence/parser';
|
|
12
|
-
import type { ISLayoutResult
|
|
13
|
+
import type { ISLayoutResult } from './layout';
|
|
13
14
|
import { parseInitiativeStatus } from './parser';
|
|
14
15
|
import { layoutInitiativeStatus } from './layout';
|
|
15
16
|
|
|
@@ -436,7 +437,6 @@ export function renderInitiativeStatus(
|
|
|
436
437
|
const scale = Math.min(MAX_SCALE, scaleX, scaleY);
|
|
437
438
|
|
|
438
439
|
const scaledW = diagramW * scale;
|
|
439
|
-
const scaledH = diagramH * scale;
|
|
440
440
|
const offsetX = (width - scaledW) / 2;
|
|
441
441
|
const offsetY = titleHeight + DIAGRAM_PADDING;
|
|
442
442
|
|
|
@@ -850,14 +850,7 @@ export function renderInitiativeStatusForExport(
|
|
|
850
850
|
const exportWidth = layout.width + DIAGRAM_PADDING * 2;
|
|
851
851
|
const exportHeight = layout.height + DIAGRAM_PADDING * 2 + titleOffset;
|
|
852
852
|
|
|
853
|
-
|
|
854
|
-
container.style.width = `${exportWidth}px`;
|
|
855
|
-
container.style.height = `${exportHeight}px`;
|
|
856
|
-
container.style.position = 'absolute';
|
|
857
|
-
container.style.left = '-9999px';
|
|
858
|
-
document.body.appendChild(container);
|
|
859
|
-
|
|
860
|
-
try {
|
|
853
|
+
return runInExportContainer(exportWidth, exportHeight, (container) => {
|
|
861
854
|
renderInitiativeStatus(
|
|
862
855
|
container,
|
|
863
856
|
parsed,
|
|
@@ -867,19 +860,6 @@ export function renderInitiativeStatusForExport(
|
|
|
867
860
|
undefined,
|
|
868
861
|
{ width: exportWidth, height: exportHeight }
|
|
869
862
|
);
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
if (!svgEl) return '';
|
|
873
|
-
|
|
874
|
-
if (theme === 'transparent') {
|
|
875
|
-
svgEl.style.background = 'none';
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
svgEl.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
|
|
879
|
-
svgEl.style.fontFamily = FONT_FAMILY;
|
|
880
|
-
|
|
881
|
-
return svgEl.outerHTML;
|
|
882
|
-
} finally {
|
|
883
|
-
document.body.removeChild(container);
|
|
884
|
-
}
|
|
863
|
+
return extractExportSvg(container, theme);
|
|
864
|
+
});
|
|
885
865
|
}
|
package/src/kanban/parser.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { PaletteColors } from '../palettes';
|
|
2
|
-
import type { DgmoError } from '../diagnostics';
|
|
3
2
|
import { makeDgmoError, formatDgmoError, suggest } from '../diagnostics';
|
|
4
3
|
import { resolveColor } from '../colors';
|
|
5
4
|
import { matchTagBlockHeading } from '../utils/tag-groups';
|
|
@@ -15,7 +14,6 @@ import type {
|
|
|
15
14
|
KanbanColumn,
|
|
16
15
|
KanbanCard,
|
|
17
16
|
KanbanTagGroup,
|
|
18
|
-
KanbanTagEntry,
|
|
19
17
|
} from './types';
|
|
20
18
|
|
|
21
19
|
// ============================================================
|
package/src/org/layout.ts
CHANGED
|
@@ -81,8 +81,6 @@ export interface OrgLayoutResult {
|
|
|
81
81
|
// ============================================================
|
|
82
82
|
|
|
83
83
|
const CHAR_WIDTH = 7.5;
|
|
84
|
-
const LABEL_FONT_SIZE = 13;
|
|
85
|
-
const META_FONT_SIZE = 11;
|
|
86
84
|
const META_LINE_HEIGHT = 16;
|
|
87
85
|
const HEADER_HEIGHT = 28;
|
|
88
86
|
const SEPARATOR_GAP = 6;
|
|
@@ -1128,8 +1126,6 @@ export function layoutOrg(
|
|
|
1128
1126
|
const allExpanded = expandAllLegend && activeTagGroup == null;
|
|
1129
1127
|
const effectiveW = (g: OrgLegendGroup) =>
|
|
1130
1128
|
activeTagGroup != null || allExpanded ? g.width : g.minifiedWidth;
|
|
1131
|
-
const effectiveH = (g: OrgLegendGroup) =>
|
|
1132
|
-
activeTagGroup != null || allExpanded ? g.height : g.minifiedHeight;
|
|
1133
1129
|
|
|
1134
1130
|
if (visibleGroups.length > 0) {
|
|
1135
1131
|
if (legendPosition === 'bottom') {
|
package/src/org/renderer.ts
CHANGED
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
|
|
5
5
|
import * as d3Selection from 'd3-selection';
|
|
6
6
|
import { FONT_FAMILY } from '../fonts';
|
|
7
|
+
import { runInExportContainer, extractExportSvg } from '../utils/export-container';
|
|
7
8
|
import type { PaletteColors } from '../palettes';
|
|
8
9
|
import { mix } from '../palettes/color-utils';
|
|
9
10
|
import type { ParsedOrg } from './parser';
|
|
10
|
-
import type { OrgLayoutResult
|
|
11
|
+
import type { OrgLayoutResult } from './layout';
|
|
11
12
|
import { parseOrg } from './parser';
|
|
12
13
|
import { layoutOrg } from './layout';
|
|
13
14
|
import {
|
|
@@ -687,38 +688,16 @@ export function renderOrgForExport(
|
|
|
687
688
|
const layout = layoutOrg(parsed, undefined, undefined, exportHidden);
|
|
688
689
|
const isDark = theme === 'dark';
|
|
689
690
|
|
|
690
|
-
// Create offscreen container
|
|
691
|
-
const container = document.createElement('div');
|
|
692
691
|
const titleOffset = parsed.title ? TITLE_HEIGHT : 0;
|
|
693
692
|
const exportWidth = layout.width + DIAGRAM_PADDING * 2;
|
|
694
|
-
const exportHeight =
|
|
695
|
-
layout.height + DIAGRAM_PADDING * 2 + titleOffset;
|
|
693
|
+
const exportHeight = layout.height + DIAGRAM_PADDING * 2 + titleOffset;
|
|
696
694
|
|
|
697
|
-
|
|
698
|
-
container
|
|
699
|
-
container.style.position = 'absolute';
|
|
700
|
-
container.style.left = '-9999px';
|
|
701
|
-
document.body.appendChild(container);
|
|
702
|
-
|
|
703
|
-
try {
|
|
704
|
-
// No hiddenAttributes passed to renderOrg — export never shows eye icons
|
|
695
|
+
// No hiddenAttributes passed to renderOrg — export never shows eye icons
|
|
696
|
+
return runInExportContainer(exportWidth, exportHeight, (container) => {
|
|
705
697
|
renderOrg(container, parsed, layout, palette, isDark, undefined, {
|
|
706
698
|
width: exportWidth,
|
|
707
699
|
height: exportHeight,
|
|
708
700
|
});
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
if (!svgEl) return '';
|
|
712
|
-
|
|
713
|
-
if (theme === 'transparent') {
|
|
714
|
-
svgEl.style.background = 'none';
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
svgEl.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
|
|
718
|
-
svgEl.style.fontFamily = FONT_FAMILY;
|
|
719
|
-
|
|
720
|
-
return svgEl.outerHTML;
|
|
721
|
-
} finally {
|
|
722
|
-
document.body.removeChild(container);
|
|
723
|
-
}
|
|
701
|
+
return extractExportSvg(container, theme);
|
|
702
|
+
});
|
|
724
703
|
}
|
package/src/sequence/parser.ts
CHANGED
|
@@ -153,12 +153,14 @@ export interface ParsedSequenceDgmo {
|
|
|
153
153
|
error: string | null;
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
-
// "Name is a type" pattern — e.g. "
|
|
156
|
+
// "Name is a type" pattern — e.g. "Auth Server is a service"
|
|
157
|
+
// Participant names may contain spaces; [^:]+? stops at colons so that
|
|
158
|
+
// note lines like "note right of A: this is a service" are not falsely matched.
|
|
157
159
|
// Remainder after type is parsed separately for aka/position modifiers
|
|
158
|
-
const IS_A_PATTERN = /^(
|
|
160
|
+
const IS_A_PATTERN = /^([^:]+?)\s+is\s+an?\s+(\w+)(?:\s+(.+))?$/i;
|
|
159
161
|
|
|
160
162
|
// Standalone "Name position N" pattern — e.g. "DB position -1"
|
|
161
|
-
const POSITION_ONLY_PATTERN = /^(
|
|
163
|
+
const POSITION_ONLY_PATTERN = /^([^:]+?)\s+position\s+(-?\d+)$/i;
|
|
162
164
|
|
|
163
165
|
// Colored participant declaration — e.g. "Tapin2(green)", "API(blue)"
|
|
164
166
|
const COLORED_PARTICIPANT_PATTERN = /^(\S+?)\(([^)]+)\)\s*$/;
|
|
@@ -174,9 +176,10 @@ const SECTION_PATTERN = /^==\s+(.+?)(?:\s*==)?\s*$/;
|
|
|
174
176
|
// Arrow pattern for sequence inference — detects any arrow form
|
|
175
177
|
const ARROW_PATTERN = /\S+\s*(?:<-\S+-|<~\S+~|-\S+->|~\S+~>|->|~>|<-|<~)\s*\S+/;
|
|
176
178
|
|
|
177
|
-
// Note patterns — "note: text", "note right of
|
|
178
|
-
|
|
179
|
-
const
|
|
179
|
+
// Note patterns — "note: text", "note right of Auth Server: text"
|
|
180
|
+
// Participant names may contain spaces; the colon acts as the delimiter.
|
|
181
|
+
const NOTE_SINGLE = /^note(?:\s+(right|left)\s+of\s+(.+?))?\s*:\s*(.+)$/i;
|
|
182
|
+
const NOTE_MULTI = /^note(?:\s+(right|left)\s+of\s+(.+?))?\s*:?\s*$/i;
|
|
180
183
|
|
|
181
184
|
/**
|
|
182
185
|
* Parse a .dgmo file with `chart: sequence` into a structured representation.
|
|
@@ -673,7 +676,7 @@ export function parseSequenceDgmo(content: string): ParsedSequenceDgmo {
|
|
|
673
676
|
|
|
674
677
|
// ---- Error: plain bidirectional arrows (A <-> B, A <~> B) ----
|
|
675
678
|
const bidiPlainMatch = arrowCore.match(
|
|
676
|
-
/^(
|
|
679
|
+
/^(.+?)\s*(?:<->|<~>)\s*(.+)/
|
|
677
680
|
);
|
|
678
681
|
if (bidiPlainMatch) {
|
|
679
682
|
pushError(
|
|
@@ -684,8 +687,8 @@ export function parseSequenceDgmo(content: string): ParsedSequenceDgmo {
|
|
|
684
687
|
}
|
|
685
688
|
|
|
686
689
|
// ---- Deprecated bare return arrows: A <- B, A <~ B ----
|
|
687
|
-
const bareReturnSync = arrowCore.match(/^(
|
|
688
|
-
const bareReturnAsync = arrowCore.match(/^(
|
|
690
|
+
const bareReturnSync = arrowCore.match(/^(.+?)\s+<-\s+(.+)$/);
|
|
691
|
+
const bareReturnAsync = arrowCore.match(/^(.+?)\s+<~\s+(.+)$/);
|
|
689
692
|
const bareReturn = bareReturnSync || bareReturnAsync;
|
|
690
693
|
if (bareReturn) {
|
|
691
694
|
const to = bareReturn[1];
|
|
@@ -698,8 +701,8 @@ export function parseSequenceDgmo(content: string): ParsedSequenceDgmo {
|
|
|
698
701
|
}
|
|
699
702
|
|
|
700
703
|
// ---- Bare (unlabeled) call arrows: A -> B, A ~> B ----
|
|
701
|
-
const bareCallSync = arrowCore.match(/^(
|
|
702
|
-
const bareCallAsync = arrowCore.match(/^(
|
|
704
|
+
const bareCallSync = arrowCore.match(/^(.+?)\s*->\s*(.+)$/);
|
|
705
|
+
const bareCallAsync = arrowCore.match(/^(.+?)\s*~>\s*(.+)$/);
|
|
703
706
|
const bareCall = bareCallSync || bareCallAsync;
|
|
704
707
|
if (bareCall) {
|
|
705
708
|
contentStarted = true;
|
package/src/sequence/renderer.ts
CHANGED
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
truncateBareUrl,
|
|
11
11
|
renderInlineText,
|
|
12
12
|
} from '../utils/inline-markdown';
|
|
13
|
-
export type { InlineSpan } from '../utils/inline-markdown';
|
|
14
13
|
export { parseInlineMarkdown, truncateBareUrl };
|
|
15
14
|
import { FONT_FAMILY } from '../fonts';
|
|
16
15
|
import { resolveColor } from '../colors';
|
|
@@ -2129,7 +2128,6 @@ export function renderSequenceDiagram(
|
|
|
2129
2128
|
// IMPORTANT: only the <g> carries data-line-number / data-section —
|
|
2130
2129
|
// children must NOT have them, otherwise the click walk-up resolves
|
|
2131
2130
|
// to a line-number navigation before reaching data-section-toggle.
|
|
2132
|
-
const HIT_AREA_HEIGHT = 36;
|
|
2133
2131
|
const sectionG = svg
|
|
2134
2132
|
.append('g')
|
|
2135
2133
|
.attr('data-section-toggle', '')
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
// Resolves effective tag values for participants and messages
|
|
6
6
|
// using the priority chain: explicit > group > receiver-inherit > default > neutral
|
|
7
7
|
|
|
8
|
-
import type { TagGroup } from '../utils/tag-groups';
|
|
9
8
|
import type {
|
|
10
9
|
ParsedSequenceDgmo,
|
|
11
10
|
SequenceParticipant,
|
package/src/sitemap/layout.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// ============================================================
|
|
4
4
|
|
|
5
5
|
import dagre from '@dagrejs/dagre';
|
|
6
|
-
import type { ParsedSitemap, SitemapNode
|
|
6
|
+
import type { ParsedSitemap, SitemapNode } from './types';
|
|
7
7
|
import type { TagGroup } from '../utils/tag-groups';
|
|
8
8
|
import { resolveTagColor, injectDefaultTagMetadata } from '../utils/tag-groups';
|
|
9
9
|
|
|
@@ -89,8 +89,6 @@ export interface SitemapLayoutResult {
|
|
|
89
89
|
// ============================================================
|
|
90
90
|
|
|
91
91
|
const CHAR_WIDTH = 7.5;
|
|
92
|
-
const LABEL_FONT_SIZE = 13;
|
|
93
|
-
const META_FONT_SIZE = 11;
|
|
94
92
|
const META_LINE_HEIGHT = 16;
|
|
95
93
|
const HEADER_HEIGHT = 28;
|
|
96
94
|
const SEPARATOR_GAP = 6;
|
|
@@ -105,7 +103,6 @@ const CONTAINER_LABEL_HEIGHT = 28;
|
|
|
105
103
|
const CONTAINER_META_LINE_HEIGHT = 16;
|
|
106
104
|
|
|
107
105
|
// Legend (kanban-style pills)
|
|
108
|
-
const LEGEND_GAP = 30;
|
|
109
106
|
const LEGEND_HEIGHT = 28;
|
|
110
107
|
const LEGEND_PILL_PAD = 16;
|
|
111
108
|
const LEGEND_PILL_FONT_W = 11 * 0.6;
|
|
@@ -162,16 +159,6 @@ function resolveNodeColor(
|
|
|
162
159
|
|
|
163
160
|
const OVERLAP_GAP = 20;
|
|
164
161
|
|
|
165
|
-
function countDescendantNodes(node: SitemapNode, hiddenCounts?: Map<string, number>): number {
|
|
166
|
-
let count = 0;
|
|
167
|
-
for (const child of node.children) {
|
|
168
|
-
count += (child.isContainer ? 0 : 1) + countDescendantNodes(child, hiddenCounts);
|
|
169
|
-
const hc = hiddenCounts?.get(child.id);
|
|
170
|
-
if (hc) count += hc;
|
|
171
|
-
}
|
|
172
|
-
return count;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
162
|
// ============================================================
|
|
176
163
|
// Legend
|
|
177
164
|
// ============================================================
|
package/src/sitemap/parser.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import type { PaletteColors } from '../palettes';
|
|
6
6
|
import { resolveColor } from '../colors';
|
|
7
7
|
import { makeDgmoError, formatDgmoError, suggest } from '../diagnostics';
|
|
8
|
-
import type { TagGroup
|
|
8
|
+
import type { TagGroup } from '../utils/tag-groups';
|
|
9
9
|
import { isTagBlockHeading, matchTagBlockHeading, validateTagValues } from '../utils/tag-groups';
|
|
10
10
|
import {
|
|
11
11
|
measureIndent,
|
|
@@ -17,7 +17,6 @@ import {
|
|
|
17
17
|
} from '../utils/parsing';
|
|
18
18
|
import type {
|
|
19
19
|
SitemapNode,
|
|
20
|
-
SitemapEdge,
|
|
21
20
|
SitemapDirection,
|
|
22
21
|
ParsedSitemap,
|
|
23
22
|
} from './types';
|
package/src/sitemap/renderer.ts
CHANGED
|
@@ -10,9 +10,6 @@ import { mix } from '../palettes/color-utils';
|
|
|
10
10
|
import type { ParsedSitemap } from './types';
|
|
11
11
|
import type {
|
|
12
12
|
SitemapLayoutResult,
|
|
13
|
-
SitemapLayoutNode,
|
|
14
|
-
SitemapLayoutEdge,
|
|
15
|
-
SitemapContainerBounds,
|
|
16
13
|
SitemapLegendGroup,
|
|
17
14
|
} from './layout';
|
|
18
15
|
import {
|
package/src/utils/arrows.ts
CHANGED
|
@@ -13,15 +13,15 @@ export interface ParsedArrow {
|
|
|
13
13
|
async: boolean;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
// Forward (call) patterns
|
|
17
|
-
const SYNC_LABELED_RE = /^(
|
|
18
|
-
const ASYNC_LABELED_RE = /^(
|
|
16
|
+
// Forward (call) patterns — participant names may contain spaces, so use non-greedy (.+?)
|
|
17
|
+
const SYNC_LABELED_RE = /^(.+?)\s+-(.+)->\s+(.+)$/;
|
|
18
|
+
const ASYNC_LABELED_RE = /^(.+?)\s+~(.+)~>\s+(.+)$/;
|
|
19
19
|
|
|
20
20
|
// Deprecated patterns — produce errors
|
|
21
|
-
const RETURN_SYNC_LABELED_RE = /^(
|
|
22
|
-
const RETURN_ASYNC_LABELED_RE = /^(
|
|
23
|
-
const BIDI_SYNC_RE = /^(
|
|
24
|
-
const BIDI_ASYNC_RE = /^(
|
|
21
|
+
const RETURN_SYNC_LABELED_RE = /^(.+?)\s+<-(.+)-\s+(.+)$/;
|
|
22
|
+
const RETURN_ASYNC_LABELED_RE = /^(.+?)\s+<~(.+)~\s+(.+)$/;
|
|
23
|
+
const BIDI_SYNC_RE = /^(.+?)\s+<-(.+)->\s+(.+)$/;
|
|
24
|
+
const BIDI_ASYNC_RE = /^(.+?)\s+<~(.+)~>\s+(.+)$/;
|
|
25
25
|
|
|
26
26
|
const ARROW_CHARS = ['->', '~>'];
|
|
27
27
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { FONT_FAMILY } from '../fonts';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Creates an offscreen DOM container at the given dimensions, runs `fn` inside it,
|
|
5
|
+
* then removes it (try/finally). Returns whatever `fn` returns.
|
|
6
|
+
*/
|
|
7
|
+
export function runInExportContainer<T>(
|
|
8
|
+
width: number,
|
|
9
|
+
height: number,
|
|
10
|
+
fn: (container: HTMLDivElement) => T,
|
|
11
|
+
): T {
|
|
12
|
+
const container = document.createElement('div');
|
|
13
|
+
container.style.width = `${width}px`;
|
|
14
|
+
container.style.height = `${height}px`;
|
|
15
|
+
container.style.position = 'absolute';
|
|
16
|
+
container.style.left = '-9999px';
|
|
17
|
+
document.body.appendChild(container);
|
|
18
|
+
try {
|
|
19
|
+
return fn(container);
|
|
20
|
+
} finally {
|
|
21
|
+
document.body.removeChild(container);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Extracts the SVG element from an export container, applies required export attributes
|
|
27
|
+
* (xmlns, fontFamily, transparent background if requested), and returns its outerHTML.
|
|
28
|
+
* Returns '' if no SVG element is found.
|
|
29
|
+
*/
|
|
30
|
+
export function extractExportSvg(
|
|
31
|
+
container: HTMLElement,
|
|
32
|
+
theme: 'light' | 'dark' | 'transparent',
|
|
33
|
+
): string {
|
|
34
|
+
const svgEl = container.querySelector('svg');
|
|
35
|
+
if (!svgEl) return '';
|
|
36
|
+
if (theme === 'transparent') svgEl.style.background = 'none';
|
|
37
|
+
svgEl.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
|
|
38
|
+
svgEl.style.fontFamily = FONT_FAMILY;
|
|
39
|
+
return svgEl.outerHTML;
|
|
40
|
+
}
|