@diagrammo/dgmo 0.0.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/LICENSE +21 -0
- package/README.md +335 -0
- package/dist/index.cjs +6698 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +685 -0
- package/dist/index.d.ts +685 -0
- package/dist/index.js +6611 -0
- package/dist/index.js.map +1 -0
- package/package.json +51 -0
- package/src/chartjs.ts +784 -0
- package/src/colors.ts +75 -0
- package/src/d3.ts +5021 -0
- package/src/dgmo-mermaid.ts +247 -0
- package/src/dgmo-router.ts +77 -0
- package/src/echarts.ts +1207 -0
- package/src/index.ts +126 -0
- package/src/palettes/bold.ts +59 -0
- package/src/palettes/catppuccin.ts +76 -0
- package/src/palettes/color-utils.ts +191 -0
- package/src/palettes/gruvbox.ts +77 -0
- package/src/palettes/index.ts +35 -0
- package/src/palettes/mermaid-bridge.ts +220 -0
- package/src/palettes/nord.ts +59 -0
- package/src/palettes/one-dark.ts +62 -0
- package/src/palettes/registry.ts +92 -0
- package/src/palettes/rose-pine.ts +76 -0
- package/src/palettes/solarized.ts +69 -0
- package/src/palettes/tokyo-night.ts +78 -0
- package/src/palettes/types.ts +67 -0
- package/src/sequence/parser.ts +531 -0
- package/src/sequence/participant-inference.ts +178 -0
- package/src/sequence/renderer.ts +1487 -0
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// .dgmo → Mermaid Translation Layer
|
|
3
|
+
// Parses dgmo quadrant syntax and generates valid Mermaid code.
|
|
4
|
+
// ============================================================
|
|
5
|
+
|
|
6
|
+
import { resolveColor } from './colors';
|
|
7
|
+
|
|
8
|
+
// ============================================================
|
|
9
|
+
// Types
|
|
10
|
+
// ============================================================
|
|
11
|
+
|
|
12
|
+
interface QuadrantLabel {
|
|
13
|
+
text: string;
|
|
14
|
+
color: string | null;
|
|
15
|
+
lineNumber: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ParsedQuadrant {
|
|
19
|
+
title: string | null;
|
|
20
|
+
titleLineNumber: number | null;
|
|
21
|
+
xAxis: [string, string] | null;
|
|
22
|
+
xAxisLineNumber: number | null;
|
|
23
|
+
yAxis: [string, string] | null;
|
|
24
|
+
yAxisLineNumber: number | null;
|
|
25
|
+
quadrants: {
|
|
26
|
+
topRight: QuadrantLabel | null;
|
|
27
|
+
topLeft: QuadrantLabel | null;
|
|
28
|
+
bottomLeft: QuadrantLabel | null;
|
|
29
|
+
bottomRight: QuadrantLabel | null;
|
|
30
|
+
};
|
|
31
|
+
points: { label: string; x: number; y: number; lineNumber: number }[];
|
|
32
|
+
error: string | null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ============================================================
|
|
36
|
+
// Parser
|
|
37
|
+
// ============================================================
|
|
38
|
+
|
|
39
|
+
/** Regex for quadrant label lines: `top-right: Promote (green)` */
|
|
40
|
+
const QUADRANT_LABEL_RE = /^(.+?)(?:\s*\(([^)]+)\))?\s*$/;
|
|
41
|
+
|
|
42
|
+
/** Regex for data point lines: `Label: 0.9, 0.5` */
|
|
43
|
+
const DATA_POINT_RE = /^(.+?):\s*([0-9]*\.?[0-9]+)\s*,\s*([0-9]*\.?[0-9]+)\s*$/;
|
|
44
|
+
|
|
45
|
+
const QUADRANT_POSITIONS = new Set([
|
|
46
|
+
'top-right',
|
|
47
|
+
'top-left',
|
|
48
|
+
'bottom-left',
|
|
49
|
+
'bottom-right',
|
|
50
|
+
]);
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Parses a .dgmo quadrant document into a structured object.
|
|
54
|
+
* Lines are processed sequentially; unknown lines are silently skipped.
|
|
55
|
+
*/
|
|
56
|
+
export function parseQuadrant(content: string): ParsedQuadrant {
|
|
57
|
+
const result: ParsedQuadrant = {
|
|
58
|
+
title: null,
|
|
59
|
+
titleLineNumber: null,
|
|
60
|
+
xAxis: null,
|
|
61
|
+
xAxisLineNumber: null,
|
|
62
|
+
yAxis: null,
|
|
63
|
+
yAxisLineNumber: null,
|
|
64
|
+
quadrants: {
|
|
65
|
+
topRight: null,
|
|
66
|
+
topLeft: null,
|
|
67
|
+
bottomLeft: null,
|
|
68
|
+
bottomRight: null,
|
|
69
|
+
},
|
|
70
|
+
points: [],
|
|
71
|
+
error: null,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const lines = content.split('\n');
|
|
75
|
+
|
|
76
|
+
for (let i = 0; i < lines.length; i++) {
|
|
77
|
+
const line = lines[i].trim();
|
|
78
|
+
const lineNumber = i + 1; // 1-indexed for editor
|
|
79
|
+
|
|
80
|
+
// Skip empty lines and comments
|
|
81
|
+
if (!line || line.startsWith('#') || line.startsWith('//')) continue;
|
|
82
|
+
|
|
83
|
+
// Skip the chart: directive (already consumed by router)
|
|
84
|
+
if (/^chart\s*:/i.test(line)) continue;
|
|
85
|
+
|
|
86
|
+
// title: <text>
|
|
87
|
+
const titleMatch = line.match(/^title\s*:\s*(.+)/i);
|
|
88
|
+
if (titleMatch) {
|
|
89
|
+
result.title = titleMatch[1].trim();
|
|
90
|
+
result.titleLineNumber = lineNumber;
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// x-axis: Low, High
|
|
95
|
+
const xMatch = line.match(/^x-axis\s*:\s*(.+)/i);
|
|
96
|
+
if (xMatch) {
|
|
97
|
+
const parts = xMatch[1].split(',').map((s) => s.trim());
|
|
98
|
+
if (parts.length >= 2) {
|
|
99
|
+
result.xAxis = [parts[0], parts[1]];
|
|
100
|
+
result.xAxisLineNumber = lineNumber;
|
|
101
|
+
}
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// y-axis: Low, High
|
|
106
|
+
const yMatch = line.match(/^y-axis\s*:\s*(.+)/i);
|
|
107
|
+
if (yMatch) {
|
|
108
|
+
const parts = yMatch[1].split(',').map((s) => s.trim());
|
|
109
|
+
if (parts.length >= 2) {
|
|
110
|
+
result.yAxis = [parts[0], parts[1]];
|
|
111
|
+
result.yAxisLineNumber = lineNumber;
|
|
112
|
+
}
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Quadrant position labels: top-right: Label (color)
|
|
117
|
+
const posMatch = line.match(
|
|
118
|
+
/^(top-right|top-left|bottom-left|bottom-right)\s*:\s*(.+)/i
|
|
119
|
+
);
|
|
120
|
+
if (posMatch) {
|
|
121
|
+
const position = posMatch[1].toLowerCase();
|
|
122
|
+
const labelMatch = posMatch[2].match(QUADRANT_LABEL_RE);
|
|
123
|
+
if (labelMatch) {
|
|
124
|
+
const label: QuadrantLabel = {
|
|
125
|
+
text: labelMatch[1].trim(),
|
|
126
|
+
color: labelMatch[2] ? resolveColor(labelMatch[2].trim()) : null,
|
|
127
|
+
lineNumber,
|
|
128
|
+
};
|
|
129
|
+
if (position === 'top-right') result.quadrants.topRight = label;
|
|
130
|
+
else if (position === 'top-left') result.quadrants.topLeft = label;
|
|
131
|
+
else if (position === 'bottom-left')
|
|
132
|
+
result.quadrants.bottomLeft = label;
|
|
133
|
+
else if (position === 'bottom-right')
|
|
134
|
+
result.quadrants.bottomRight = label;
|
|
135
|
+
}
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Data points: Label: x, y
|
|
140
|
+
const pointMatch = line.match(DATA_POINT_RE);
|
|
141
|
+
if (pointMatch) {
|
|
142
|
+
// Make sure this isn't a quadrant position keyword
|
|
143
|
+
const key = pointMatch[1].trim().toLowerCase();
|
|
144
|
+
if (!QUADRANT_POSITIONS.has(key)) {
|
|
145
|
+
result.points.push({
|
|
146
|
+
label: pointMatch[1].trim(),
|
|
147
|
+
x: parseFloat(pointMatch[2]),
|
|
148
|
+
y: parseFloat(pointMatch[3]),
|
|
149
|
+
lineNumber,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (result.points.length === 0) {
|
|
157
|
+
result.error = 'No data points found. Add lines like: Label: 0.5, 0.7';
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return result;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// ============================================================
|
|
164
|
+
// Mermaid Builder
|
|
165
|
+
// ============================================================
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Generates valid Mermaid quadrantChart syntax from a parsed quadrant.
|
|
169
|
+
* Returns a string ready for the Mermaid renderer.
|
|
170
|
+
*/
|
|
171
|
+
export function buildMermaidQuadrant(
|
|
172
|
+
parsed: ParsedQuadrant,
|
|
173
|
+
options: {
|
|
174
|
+
isDark?: boolean;
|
|
175
|
+
textColor?: string;
|
|
176
|
+
mutedTextColor?: string;
|
|
177
|
+
} = {}
|
|
178
|
+
): string {
|
|
179
|
+
const { isDark = false, textColor, mutedTextColor } = options;
|
|
180
|
+
const lines: string[] = [];
|
|
181
|
+
|
|
182
|
+
// %%{init}%% block — fill colors with reduced opacity + text color overrides
|
|
183
|
+
const fillAlpha = isDark ? '30' : '55';
|
|
184
|
+
const primaryText = textColor ?? (isDark ? '#d0d0d0' : '#333333');
|
|
185
|
+
const quadrantLabelText = mutedTextColor ?? (isDark ? '#888888' : '#666666');
|
|
186
|
+
|
|
187
|
+
const colorMap: Record<string, string> = {};
|
|
188
|
+
if (parsed.quadrants.topRight?.color)
|
|
189
|
+
colorMap.quadrant1Fill = parsed.quadrants.topRight.color + fillAlpha;
|
|
190
|
+
if (parsed.quadrants.topLeft?.color)
|
|
191
|
+
colorMap.quadrant2Fill = parsed.quadrants.topLeft.color + fillAlpha;
|
|
192
|
+
if (parsed.quadrants.bottomLeft?.color)
|
|
193
|
+
colorMap.quadrant3Fill = parsed.quadrants.bottomLeft.color + fillAlpha;
|
|
194
|
+
if (parsed.quadrants.bottomRight?.color)
|
|
195
|
+
colorMap.quadrant4Fill = parsed.quadrants.bottomRight.color + fillAlpha;
|
|
196
|
+
|
|
197
|
+
// Quadrant labels use muted color, points use primary text color
|
|
198
|
+
colorMap.quadrant1TextFill = quadrantLabelText;
|
|
199
|
+
colorMap.quadrant2TextFill = quadrantLabelText;
|
|
200
|
+
colorMap.quadrant3TextFill = quadrantLabelText;
|
|
201
|
+
colorMap.quadrant4TextFill = quadrantLabelText;
|
|
202
|
+
colorMap.quadrantPointTextFill = primaryText;
|
|
203
|
+
colorMap.quadrantXAxisTextFill = primaryText;
|
|
204
|
+
colorMap.quadrantYAxisTextFill = primaryText;
|
|
205
|
+
colorMap.quadrantTitleFill = primaryText;
|
|
206
|
+
|
|
207
|
+
const vars = JSON.stringify(colorMap);
|
|
208
|
+
lines.push(`%%{init: {"themeVariables": ${vars}}}%%`);
|
|
209
|
+
|
|
210
|
+
lines.push('quadrantChart');
|
|
211
|
+
|
|
212
|
+
if (parsed.title) {
|
|
213
|
+
lines.push(` title ${parsed.title}`);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (parsed.xAxis) {
|
|
217
|
+
lines.push(` x-axis ${parsed.xAxis[0]} --> ${parsed.xAxis[1]}`);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (parsed.yAxis) {
|
|
221
|
+
lines.push(` y-axis ${parsed.yAxis[0]} --> ${parsed.yAxis[1]}`);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Helper to quote labels that need it (contain spaces or special chars)
|
|
225
|
+
const quote = (s: string): string => (/[\s,:[\]]/.test(s) ? `"${s}"` : s);
|
|
226
|
+
|
|
227
|
+
// Quadrant labels: 1=top-right, 2=top-left, 3=bottom-left, 4=bottom-right
|
|
228
|
+
if (parsed.quadrants.topRight) {
|
|
229
|
+
lines.push(` quadrant-1 ${quote(parsed.quadrants.topRight.text)}`);
|
|
230
|
+
}
|
|
231
|
+
if (parsed.quadrants.topLeft) {
|
|
232
|
+
lines.push(` quadrant-2 ${quote(parsed.quadrants.topLeft.text)}`);
|
|
233
|
+
}
|
|
234
|
+
if (parsed.quadrants.bottomLeft) {
|
|
235
|
+
lines.push(` quadrant-3 ${quote(parsed.quadrants.bottomLeft.text)}`);
|
|
236
|
+
}
|
|
237
|
+
if (parsed.quadrants.bottomRight) {
|
|
238
|
+
lines.push(` quadrant-4 ${quote(parsed.quadrants.bottomRight.text)}`);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Data points
|
|
242
|
+
for (const point of parsed.points) {
|
|
243
|
+
lines.push(` ${quote(point.label)}: [${point.x}, ${point.y}]`);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return lines.join('\n');
|
|
247
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// .dgmo Unified Format — Chart Type Router
|
|
3
|
+
// ============================================================
|
|
4
|
+
|
|
5
|
+
import { looksLikeSequence } from './sequence/parser';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Framework identifiers used by the .dgmo router.
|
|
9
|
+
* Maps to the existing preview components and export paths.
|
|
10
|
+
*/
|
|
11
|
+
export type DgmoFramework = 'chartjs' | 'echart' | 'd3' | 'mermaid';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Maps every supported chart type string to its backing framework.
|
|
15
|
+
*
|
|
16
|
+
* Chart.js: standard chart types (bar, line, pie, etc.)
|
|
17
|
+
* ECharts: scatter, flow/relationship diagrams, math, heatmap
|
|
18
|
+
* D3: slope, wordcloud, arc diagram, timeline
|
|
19
|
+
*/
|
|
20
|
+
export const DGMO_CHART_TYPE_MAP: Record<string, DgmoFramework> = {
|
|
21
|
+
// Chart.js
|
|
22
|
+
bar: 'chartjs',
|
|
23
|
+
line: 'chartjs',
|
|
24
|
+
'multi-line': 'chartjs',
|
|
25
|
+
area: 'chartjs',
|
|
26
|
+
pie: 'chartjs',
|
|
27
|
+
doughnut: 'chartjs',
|
|
28
|
+
radar: 'chartjs',
|
|
29
|
+
'polar-area': 'chartjs',
|
|
30
|
+
'bar-stacked': 'chartjs',
|
|
31
|
+
|
|
32
|
+
// ECharts
|
|
33
|
+
scatter: 'echart',
|
|
34
|
+
sankey: 'echart',
|
|
35
|
+
chord: 'echart',
|
|
36
|
+
function: 'echart',
|
|
37
|
+
heatmap: 'echart',
|
|
38
|
+
funnel: 'echart',
|
|
39
|
+
|
|
40
|
+
// D3
|
|
41
|
+
slope: 'd3',
|
|
42
|
+
wordcloud: 'd3',
|
|
43
|
+
arc: 'd3',
|
|
44
|
+
timeline: 'd3',
|
|
45
|
+
venn: 'd3',
|
|
46
|
+
quadrant: 'd3',
|
|
47
|
+
sequence: 'd3',
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Returns the framework for a given chart type, or `null` if unknown.
|
|
52
|
+
*/
|
|
53
|
+
export function getDgmoFramework(chartType: string): DgmoFramework | null {
|
|
54
|
+
return DGMO_CHART_TYPE_MAP[chartType.toLowerCase()] ?? null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Extracts the `chart:` type value from raw file content.
|
|
59
|
+
* Falls back to inference when no explicit `chart:` line is found
|
|
60
|
+
* (e.g. content containing `->` is inferred as `sequence`).
|
|
61
|
+
*/
|
|
62
|
+
export function parseDgmoChartType(content: string): string | null {
|
|
63
|
+
const lines = content.split('\n');
|
|
64
|
+
for (const line of lines) {
|
|
65
|
+
const trimmed = line.trim();
|
|
66
|
+
// Skip empty lines and comments
|
|
67
|
+
if (!trimmed || trimmed.startsWith('#') || trimmed.startsWith('//'))
|
|
68
|
+
continue;
|
|
69
|
+
const match = trimmed.match(/^chart\s*:\s*(.+)/i);
|
|
70
|
+
if (match) return match[1].trim().toLowerCase();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Infer sequence chart type when content contains arrow patterns
|
|
74
|
+
if (looksLikeSequence(content)) return 'sequence';
|
|
75
|
+
|
|
76
|
+
return null;
|
|
77
|
+
}
|