@diagrammo/dgmo 0.8.4 → 0.8.5
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 +267 -0
- package/dist/cli.cjs +188 -185
- package/dist/editor.cjs +2 -0
- package/dist/editor.cjs.map +1 -1
- package/dist/editor.js +2 -0
- package/dist/editor.js.map +1 -1
- package/dist/highlight.cjs +560 -0
- package/dist/highlight.cjs.map +1 -0
- package/dist/highlight.d.cts +32 -0
- package/dist/highlight.d.ts +32 -0
- package/dist/highlight.js +530 -0
- package/dist/highlight.js.map +1 -0
- package/dist/index.cjs +117 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -1
- package/dist/index.d.ts +22 -1
- package/dist/index.js +116 -9
- package/dist/index.js.map +1 -1
- package/docs/language-reference.md +17 -9
- package/gallery/fixtures/slope.dgmo +7 -6
- package/package.json +26 -6
- package/src/cli.ts +43 -1
- package/src/d3.ts +161 -19
- package/src/editor/highlight-api.ts +444 -0
- package/src/editor/keywords.ts +2 -0
- package/src/index.ts +96 -31
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standalone DGMO syntax highlighter — no CodeMirror dependency.
|
|
3
|
+
*
|
|
4
|
+
* Exports:
|
|
5
|
+
* - `highlightDgmo(source)` → `HighlightToken[]` (consumer-agnostic)
|
|
6
|
+
* - `NORD_ROLE_STYLES` — inline style objects keyed by role (for React/Astro)
|
|
7
|
+
* - `ROLE_TO_ANSI` — ANSI escape codes keyed by role (for CLI)
|
|
8
|
+
*
|
|
9
|
+
* Uses the raw Lezer parser directly — keyword specialization is wired into
|
|
10
|
+
* the grammar, so `parser.parse()` runs it automatically.
|
|
11
|
+
*
|
|
12
|
+
* @module @diagrammo/dgmo/highlight
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { parser } from './dgmo.grammar.js';
|
|
16
|
+
|
|
17
|
+
// ============================================================
|
|
18
|
+
// Types
|
|
19
|
+
// ============================================================
|
|
20
|
+
|
|
21
|
+
export interface HighlightToken {
|
|
22
|
+
text: string;
|
|
23
|
+
role: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// ============================================================
|
|
27
|
+
// NODE_TO_ROLE — keep in sync with highlight.ts
|
|
28
|
+
// ============================================================
|
|
29
|
+
|
|
30
|
+
const NODE_TO_ROLE: Record<string, string> = {
|
|
31
|
+
Comment: 'comment',
|
|
32
|
+
ChartType: 'chartType',
|
|
33
|
+
TagKeyword: 'definitionKeyword',
|
|
34
|
+
DirectiveKeyword: 'keyword',
|
|
35
|
+
ControlKeyword: 'controlKeyword',
|
|
36
|
+
ModifierKeyword: 'modifier',
|
|
37
|
+
SyncArrow: 'operator',
|
|
38
|
+
AsyncArrow: 'operator',
|
|
39
|
+
Dash: 'operator',
|
|
40
|
+
Tilde: 'operator',
|
|
41
|
+
Star: 'operator',
|
|
42
|
+
Question: 'operator',
|
|
43
|
+
Duration: 'number',
|
|
44
|
+
DateLiteral: 'number',
|
|
45
|
+
Number: 'number',
|
|
46
|
+
Percentage: 'number',
|
|
47
|
+
SectionMarker: 'heading',
|
|
48
|
+
Url: 'url',
|
|
49
|
+
ColorAnnotation: 'colorAnnotation',
|
|
50
|
+
OpenBracket: 'bracket',
|
|
51
|
+
CloseBracket: 'bracket',
|
|
52
|
+
OpenParen: 'bracket',
|
|
53
|
+
CloseParen: 'bracket',
|
|
54
|
+
OpenAngle: 'bracket',
|
|
55
|
+
CloseAngle: 'bracket',
|
|
56
|
+
Pipe: 'separator',
|
|
57
|
+
Colon: 'separator',
|
|
58
|
+
Plus: 'separator',
|
|
59
|
+
Comma: 'punctuation',
|
|
60
|
+
Punct: 'punctuation',
|
|
61
|
+
Identifier: 'default',
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// ============================================================
|
|
65
|
+
// Entity detection — keep in sync with entity-highlight.ts
|
|
66
|
+
// ============================================================
|
|
67
|
+
|
|
68
|
+
/** Tokens that have grammar-level styling which should be overridden in labels. */
|
|
69
|
+
const OVERRIDE_IN_LABEL = new Set([
|
|
70
|
+
'ChartType',
|
|
71
|
+
'TagKeyword',
|
|
72
|
+
'DirectiveKeyword',
|
|
73
|
+
'ControlKeyword',
|
|
74
|
+
'ModifierKeyword',
|
|
75
|
+
'Number',
|
|
76
|
+
'Percentage',
|
|
77
|
+
'Duration',
|
|
78
|
+
'DateLiteral',
|
|
79
|
+
]);
|
|
80
|
+
|
|
81
|
+
/** Lines starting with these are keyword-led — not entity declarations. */
|
|
82
|
+
const KEYWORD_STARTS = new Set([
|
|
83
|
+
'TagKeyword',
|
|
84
|
+
'DirectiveKeyword',
|
|
85
|
+
'ControlKeyword',
|
|
86
|
+
'ModifierKeyword',
|
|
87
|
+
'SectionMarker',
|
|
88
|
+
'Comment',
|
|
89
|
+
'Duration',
|
|
90
|
+
'DateLiteral',
|
|
91
|
+
]);
|
|
92
|
+
|
|
93
|
+
// ============================================================
|
|
94
|
+
// Core: highlightDgmo()
|
|
95
|
+
// ============================================================
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Tokenize DGMO source into annotated highlight spans.
|
|
99
|
+
*
|
|
100
|
+
* Guarantees lossless round-trip:
|
|
101
|
+
* `highlightDgmo(src).map(t => t.text).join('') === src`
|
|
102
|
+
*/
|
|
103
|
+
export function highlightDgmo(source: string): HighlightToken[] {
|
|
104
|
+
const tree = parser.parse(source);
|
|
105
|
+
const tokens: HighlightToken[] = [];
|
|
106
|
+
|
|
107
|
+
// Phase 1: Walk tree cursor, collect leaf tokens with gap filling
|
|
108
|
+
let pos = 0;
|
|
109
|
+
const cursor = tree.cursor();
|
|
110
|
+
|
|
111
|
+
// Descend to leaves, process them, then advance via next() or parent+next()
|
|
112
|
+
function descend(): void {
|
|
113
|
+
for (;;) {
|
|
114
|
+
// Try to go deeper
|
|
115
|
+
if (cursor.firstChild()) continue;
|
|
116
|
+
|
|
117
|
+
// At a leaf — emit it
|
|
118
|
+
emitLeaf();
|
|
119
|
+
|
|
120
|
+
// Try to advance to next sibling or ascend
|
|
121
|
+
while (!cursor.nextSibling()) {
|
|
122
|
+
if (!cursor.parent()) return; // back at root — done
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Now at next sibling — loop will try to descend into it
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function emitLeaf(): void {
|
|
130
|
+
const from = cursor.from;
|
|
131
|
+
const to = cursor.to;
|
|
132
|
+
|
|
133
|
+
// Fill gap before this node
|
|
134
|
+
if (from > pos) {
|
|
135
|
+
tokens.push({ text: source.slice(pos, from), role: 'default' });
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Emit this leaf node
|
|
139
|
+
if (to > from) {
|
|
140
|
+
const role = NODE_TO_ROLE[cursor.name] ?? 'default';
|
|
141
|
+
tokens.push({ text: source.slice(from, to), role });
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
pos = to;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
descend();
|
|
148
|
+
|
|
149
|
+
// Fill trailing gap
|
|
150
|
+
if (pos < source.length) {
|
|
151
|
+
tokens.push({ text: source.slice(pos, source.length), role: 'default' });
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Phase 2: Post-process — entity detection (label override only)
|
|
155
|
+
applyLabelOverrides(tokens);
|
|
156
|
+
|
|
157
|
+
// Phase 3: Post-process — note content detection
|
|
158
|
+
applyNoteContent(tokens);
|
|
159
|
+
|
|
160
|
+
return tokens;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// ============================================================
|
|
164
|
+
// Post-processing: label overrides
|
|
165
|
+
// ============================================================
|
|
166
|
+
|
|
167
|
+
interface LineTokenRef {
|
|
168
|
+
/** Index into the flat token array. */
|
|
169
|
+
idx: number;
|
|
170
|
+
/** Grammar node name (looked up from role + NODE_TO_ROLE reverse). */
|
|
171
|
+
nodeName: string;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Override keyword/number tokens in message-label positions to `default` role.
|
|
176
|
+
*
|
|
177
|
+
* A "label" is the span between the first Dash/Tilde and the last arrow on a
|
|
178
|
+
* content line. Tokens in OVERRIDE_IN_LABEL within that zone get their role
|
|
179
|
+
* set to `default` so they render as plain text.
|
|
180
|
+
*
|
|
181
|
+
* Also handles ChartType tokens on non-first content lines — they become
|
|
182
|
+
* `default` in labels.
|
|
183
|
+
*/
|
|
184
|
+
function applyLabelOverrides(tokens: HighlightToken[]): void {
|
|
185
|
+
// Build reverse map: role → possible node names (for override detection)
|
|
186
|
+
const ROLE_TO_NODES: Record<string, string[]> = {};
|
|
187
|
+
for (const [node, role] of Object.entries(NODE_TO_ROLE)) {
|
|
188
|
+
(ROLE_TO_NODES[role] ??= []).push(node);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Split tokens into lines
|
|
192
|
+
const lines: LineTokenRef[][] = [[]];
|
|
193
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
194
|
+
const t = tokens[i];
|
|
195
|
+
// If the token contains newlines, it belongs to the current line
|
|
196
|
+
// but signals the start of a new line after it
|
|
197
|
+
const currentLine = lines[lines.length - 1];
|
|
198
|
+
const role = t.role;
|
|
199
|
+
|
|
200
|
+
// Determine which node name this token likely had
|
|
201
|
+
let nodeName = '';
|
|
202
|
+
for (const [node, r] of Object.entries(NODE_TO_ROLE)) {
|
|
203
|
+
if (r === role) {
|
|
204
|
+
nodeName = node;
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// For roles mapping to multiple nodes, refine
|
|
209
|
+
if (role === 'operator') {
|
|
210
|
+
const text = t.text;
|
|
211
|
+
if (text === '->' || text.endsWith('->')) nodeName = 'SyncArrow';
|
|
212
|
+
else if (text === '~>' || text.endsWith('~>')) nodeName = 'AsyncArrow';
|
|
213
|
+
else if (text === '-') nodeName = 'Dash';
|
|
214
|
+
else if (text === '~') nodeName = 'Tilde';
|
|
215
|
+
else if (text === '*') nodeName = 'Star';
|
|
216
|
+
else if (text === '?') nodeName = 'Question';
|
|
217
|
+
} else if (role === 'number') {
|
|
218
|
+
const text = t.text;
|
|
219
|
+
if (/^\d+[smhd]$/i.test(text)) nodeName = 'Duration';
|
|
220
|
+
else if (/^\d{4}-\d{2}-\d{2}/.test(text)) nodeName = 'DateLiteral';
|
|
221
|
+
else if (text.endsWith('%')) nodeName = 'Percentage';
|
|
222
|
+
else nodeName = 'Number';
|
|
223
|
+
} else if (role === 'bracket') {
|
|
224
|
+
const text = t.text;
|
|
225
|
+
if (text === '[') nodeName = 'OpenBracket';
|
|
226
|
+
else if (text === ']') nodeName = 'CloseBracket';
|
|
227
|
+
else if (text === '(') nodeName = 'OpenParen';
|
|
228
|
+
else if (text === ')') nodeName = 'CloseParen';
|
|
229
|
+
else if (text === '<') nodeName = 'OpenAngle';
|
|
230
|
+
else if (text === '>') nodeName = 'CloseAngle';
|
|
231
|
+
} else if (role === 'separator') {
|
|
232
|
+
if (t.text === '|') nodeName = 'Pipe';
|
|
233
|
+
else if (t.text === ':') nodeName = 'Colon';
|
|
234
|
+
else if (t.text === '+') nodeName = 'Plus';
|
|
235
|
+
} else if (role === 'punctuation') {
|
|
236
|
+
if (t.text === ',') nodeName = 'Comma';
|
|
237
|
+
else nodeName = 'Punct';
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
currentLine.push({ idx: i, nodeName });
|
|
241
|
+
|
|
242
|
+
// Check if token text ends with newline — start a new line
|
|
243
|
+
if (t.text.includes('\n')) {
|
|
244
|
+
lines.push([]);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Track first content line (for ChartType handling)
|
|
249
|
+
let seenFirstContent = false;
|
|
250
|
+
|
|
251
|
+
for (const line of lines) {
|
|
252
|
+
// Skip empty lines and whitespace-only
|
|
253
|
+
const nonWs = line.filter((ref) => tokens[ref.idx].text.trim().length > 0);
|
|
254
|
+
if (nonWs.length === 0) continue;
|
|
255
|
+
|
|
256
|
+
const firstTok = nonWs[0];
|
|
257
|
+
|
|
258
|
+
// Skip keyword-led lines
|
|
259
|
+
if (KEYWORD_STARTS.has(firstTok.nodeName)) continue;
|
|
260
|
+
|
|
261
|
+
// First-line chart type — skip
|
|
262
|
+
if (firstTok.nodeName === 'ChartType' && !seenFirstContent) {
|
|
263
|
+
seenFirstContent = true;
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
seenFirstContent = true;
|
|
267
|
+
|
|
268
|
+
// Find structural boundaries within this line
|
|
269
|
+
let firstDashTildeIdx = -1;
|
|
270
|
+
let lastArrowIdx = -1;
|
|
271
|
+
|
|
272
|
+
for (let li = 0; li < nonWs.length; li++) {
|
|
273
|
+
const ref = nonWs[li];
|
|
274
|
+
if (
|
|
275
|
+
(ref.nodeName === 'Dash' || ref.nodeName === 'Tilde') &&
|
|
276
|
+
firstDashTildeIdx < 0
|
|
277
|
+
) {
|
|
278
|
+
firstDashTildeIdx = li;
|
|
279
|
+
}
|
|
280
|
+
if (ref.nodeName === 'SyncArrow' || ref.nodeName === 'AsyncArrow') {
|
|
281
|
+
lastArrowIdx = li;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const hasArrow = firstDashTildeIdx >= 0 && lastArrowIdx > firstDashTildeIdx;
|
|
286
|
+
|
|
287
|
+
if (!hasArrow) continue;
|
|
288
|
+
|
|
289
|
+
// Override tokens in label zone (between first dash/tilde and last arrow)
|
|
290
|
+
for (let li = firstDashTildeIdx + 1; li < lastArrowIdx; li++) {
|
|
291
|
+
const ref = nonWs[li];
|
|
292
|
+
if (OVERRIDE_IN_LABEL.has(ref.nodeName)) {
|
|
293
|
+
tokens[ref.idx].role = 'default';
|
|
294
|
+
}
|
|
295
|
+
// ChartType in label also overridden
|
|
296
|
+
if (ref.nodeName === 'ChartType') {
|
|
297
|
+
tokens[ref.idx].role = 'default';
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// ============================================================
|
|
304
|
+
// Post-processing: note content detection
|
|
305
|
+
// ============================================================
|
|
306
|
+
|
|
307
|
+
const NOTE_HEAD_RE = /^note(\s|$)/i;
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Detect `note` keyword lines and mark indented followers as `noteContent`.
|
|
311
|
+
*/
|
|
312
|
+
function applyNoteContent(tokens: HighlightToken[]): void {
|
|
313
|
+
// Reconstruct lines from token text
|
|
314
|
+
const fullText = tokens.map((t) => t.text).join('');
|
|
315
|
+
const lines = fullText.split('\n');
|
|
316
|
+
|
|
317
|
+
let inNote = false;
|
|
318
|
+
let noteIndent = 0;
|
|
319
|
+
let charOffset = 0;
|
|
320
|
+
|
|
321
|
+
for (const lineText of lines) {
|
|
322
|
+
const lineStart = charOffset;
|
|
323
|
+
const lineEnd = charOffset + lineText.length;
|
|
324
|
+
const trimmed = lineText.trimStart();
|
|
325
|
+
const indent = lineText.length - trimmed.length;
|
|
326
|
+
|
|
327
|
+
if (NOTE_HEAD_RE.test(trimmed)) {
|
|
328
|
+
inNote = true;
|
|
329
|
+
noteIndent = indent;
|
|
330
|
+
} else if (inNote) {
|
|
331
|
+
if (trimmed.length === 0) {
|
|
332
|
+
// Blank line — stays in note block
|
|
333
|
+
} else if (indent > noteIndent) {
|
|
334
|
+
// Mark all tokens within this line range as noteContent
|
|
335
|
+
markTokensInRange(tokens, lineStart, lineEnd, 'noteContent');
|
|
336
|
+
} else {
|
|
337
|
+
inNote = false;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
charOffset = lineEnd + 1; // +1 for the \n
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Set the role of all tokens overlapping [from, to) to the given role.
|
|
347
|
+
*/
|
|
348
|
+
function markTokensInRange(
|
|
349
|
+
tokens: HighlightToken[],
|
|
350
|
+
from: number,
|
|
351
|
+
to: number,
|
|
352
|
+
role: string
|
|
353
|
+
): void {
|
|
354
|
+
let pos = 0;
|
|
355
|
+
for (const token of tokens) {
|
|
356
|
+
const tokenEnd = pos + token.text.length;
|
|
357
|
+
// Token overlaps range and is not just whitespace
|
|
358
|
+
if (tokenEnd > from && pos < to && token.text.trim().length > 0) {
|
|
359
|
+
token.role = role;
|
|
360
|
+
}
|
|
361
|
+
pos = tokenEnd;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// ============================================================
|
|
366
|
+
// NORD_ROLE_STYLES — hardcoded Nord dark palette for static contexts
|
|
367
|
+
// ============================================================
|
|
368
|
+
|
|
369
|
+
export const NORD_ROLE_STYLES: Record<string, Record<string, string>> = {
|
|
370
|
+
keyword: { color: '#81A1C1', fontWeight: 'bold' }, // nord9
|
|
371
|
+
controlKeyword: { color: '#B48EAD', fontWeight: 'bold' }, // nord15
|
|
372
|
+
definitionKeyword: { color: '#5E81AC', fontWeight: 'bold' }, // nord10
|
|
373
|
+
modifier: { color: '#B48EAD' }, // nord15
|
|
374
|
+
chartType: { color: '#D08770', fontWeight: 'bold' }, // nord12
|
|
375
|
+
operator: { color: '#BF616A', fontWeight: 'bold' }, // nord11
|
|
376
|
+
number: { color: '#B48EAD' }, // nord15
|
|
377
|
+
comment: { color: '#616E88', fontStyle: 'italic' },
|
|
378
|
+
heading: { color: '#D08770', fontWeight: 'bold' }, // nord12
|
|
379
|
+
bracket: { color: '#5E81AC' }, // nord10
|
|
380
|
+
separator: { color: '#88C0D0' }, // nord8
|
|
381
|
+
url: { color: '#88C0D0', textDecoration: 'underline' }, // nord8
|
|
382
|
+
colorAnnotation: { color: '#D08770', fontStyle: 'italic' }, // nord12
|
|
383
|
+
punctuation: { color: '#616E88' },
|
|
384
|
+
noteContent: { color: '#616E88', fontStyle: 'italic' },
|
|
385
|
+
default: {},
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
// ============================================================
|
|
389
|
+
// ROLE_TO_ANSI — ANSI escape codes for CLI output
|
|
390
|
+
// ============================================================
|
|
391
|
+
|
|
392
|
+
export const ROLE_TO_ANSI: Record<string, string> = {
|
|
393
|
+
comment: '\x1b[3;90m', // italic dim
|
|
394
|
+
keyword: '\x1b[1;34m', // bold blue
|
|
395
|
+
controlKeyword: '\x1b[1;35m', // bold magenta
|
|
396
|
+
definitionKeyword: '\x1b[1;34m', // bold blue
|
|
397
|
+
modifier: '\x1b[35m', // magenta
|
|
398
|
+
chartType: '\x1b[1;33m', // bold yellow
|
|
399
|
+
operator: '\x1b[1;31m', // bold red
|
|
400
|
+
number: '\x1b[35m', // magenta
|
|
401
|
+
heading: '\x1b[1;33m', // bold yellow
|
|
402
|
+
bracket: '\x1b[34m', // blue
|
|
403
|
+
separator: '\x1b[36m', // cyan
|
|
404
|
+
url: '\x1b[4;36m', // underline cyan
|
|
405
|
+
colorAnnotation: '\x1b[3;33m', // italic yellow
|
|
406
|
+
punctuation: '\x1b[90m', // dim
|
|
407
|
+
noteContent: '\x1b[3;90m', // italic dim
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
const ANSI_RESET = '\x1b[0m';
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Render highlighted tokens to an ANSI string for terminal display.
|
|
414
|
+
*/
|
|
415
|
+
export function renderAnsi(
|
|
416
|
+
tokens: HighlightToken[],
|
|
417
|
+
useColor: boolean
|
|
418
|
+
): string {
|
|
419
|
+
if (!useColor) {
|
|
420
|
+
return tokens.map((t) => t.text).join('');
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
let out = '';
|
|
424
|
+
let inStyled = false;
|
|
425
|
+
|
|
426
|
+
for (const token of tokens) {
|
|
427
|
+
const ansi = ROLE_TO_ANSI[token.role];
|
|
428
|
+
if (ansi) {
|
|
429
|
+
if (inStyled) out += ANSI_RESET;
|
|
430
|
+
out += ansi + token.text;
|
|
431
|
+
inStyled = true;
|
|
432
|
+
} else {
|
|
433
|
+
if (inStyled) {
|
|
434
|
+
out += ANSI_RESET;
|
|
435
|
+
inStyled = false;
|
|
436
|
+
}
|
|
437
|
+
out += token.text;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// Final reset to prevent terminal style leakage
|
|
442
|
+
out += ANSI_RESET;
|
|
443
|
+
return out;
|
|
444
|
+
}
|
package/src/editor/keywords.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -27,13 +27,8 @@ export type { RenderCategory } from './dgmo-router';
|
|
|
27
27
|
// Parsers
|
|
28
28
|
// ============================================================
|
|
29
29
|
|
|
30
|
-
export { parseChart } from './chart';
|
|
31
|
-
export type {
|
|
32
|
-
ParsedChart,
|
|
33
|
-
ChartType,
|
|
34
|
-
ChartDataPoint,
|
|
35
|
-
ChartEra,
|
|
36
|
-
} from './chart';
|
|
30
|
+
export { parseChart, parseDataRowValues } from './chart';
|
|
31
|
+
export type { ParsedChart, ChartType, ChartDataPoint, ChartEra } from './chart';
|
|
37
32
|
|
|
38
33
|
export { parseExtendedChart } from './echarts';
|
|
39
34
|
export type { ParsedExtendedChart, ExtendedChartType } from './echarts';
|
|
@@ -46,7 +41,13 @@ export {
|
|
|
46
41
|
computeTimeTicks,
|
|
47
42
|
formatDateLabel,
|
|
48
43
|
} from './d3';
|
|
49
|
-
export type {
|
|
44
|
+
export type {
|
|
45
|
+
ParsedVisualization,
|
|
46
|
+
VisualizationType,
|
|
47
|
+
D3ExportDimensions,
|
|
48
|
+
ArcLink,
|
|
49
|
+
ArcNodeGroup,
|
|
50
|
+
} from './d3';
|
|
50
51
|
|
|
51
52
|
export {
|
|
52
53
|
parseSequenceDgmo,
|
|
@@ -99,7 +100,10 @@ export type {
|
|
|
99
100
|
ClassLayoutEdge,
|
|
100
101
|
} from './class/layout';
|
|
101
102
|
|
|
102
|
-
export {
|
|
103
|
+
export {
|
|
104
|
+
renderClassDiagram,
|
|
105
|
+
renderClassDiagramForExport,
|
|
106
|
+
} from './class/renderer';
|
|
103
107
|
|
|
104
108
|
export { parseERDiagram, looksLikeERDiagram } from './er/parser';
|
|
105
109
|
|
|
@@ -113,11 +117,7 @@ export type {
|
|
|
113
117
|
} from './er/types';
|
|
114
118
|
|
|
115
119
|
export { layoutERDiagram } from './er/layout';
|
|
116
|
-
export type {
|
|
117
|
-
ERLayoutResult,
|
|
118
|
-
ERLayoutNode,
|
|
119
|
-
ERLayoutEdge,
|
|
120
|
-
} from './er/layout';
|
|
120
|
+
export type { ERLayoutResult, ERLayoutNode, ERLayoutEdge } from './er/layout';
|
|
121
121
|
|
|
122
122
|
export { renderERDiagram, renderERDiagramForExport } from './er/renderer';
|
|
123
123
|
|
|
@@ -136,10 +136,7 @@ export { parseInlineMarkdown, truncateBareUrl } from './utils/inline-markdown';
|
|
|
136
136
|
export type { InlineSpan } from './utils/inline-markdown';
|
|
137
137
|
|
|
138
138
|
export { parseOrg } from './org/parser';
|
|
139
|
-
export type {
|
|
140
|
-
ParsedOrg,
|
|
141
|
-
OrgNode,
|
|
142
|
-
} from './org/parser';
|
|
139
|
+
export type { ParsedOrg, OrgNode } from './org/parser';
|
|
143
140
|
|
|
144
141
|
export { layoutOrg } from './org/layout';
|
|
145
142
|
export type {
|
|
@@ -159,7 +156,11 @@ export type {
|
|
|
159
156
|
KanbanTagGroup,
|
|
160
157
|
KanbanTagEntry,
|
|
161
158
|
} from './kanban/types';
|
|
162
|
-
export {
|
|
159
|
+
export {
|
|
160
|
+
computeCardMove,
|
|
161
|
+
computeCardArchive,
|
|
162
|
+
isArchiveColumn,
|
|
163
|
+
} from './kanban/mutations';
|
|
163
164
|
export { renderKanban, renderKanbanForExport } from './kanban/renderer';
|
|
164
165
|
|
|
165
166
|
export { parseC4 } from './c4/parser';
|
|
@@ -176,7 +177,13 @@ export type {
|
|
|
176
177
|
C4TagEntry,
|
|
177
178
|
} from './c4/types';
|
|
178
179
|
|
|
179
|
-
export {
|
|
180
|
+
export {
|
|
181
|
+
layoutC4Context,
|
|
182
|
+
layoutC4Containers,
|
|
183
|
+
layoutC4Components,
|
|
184
|
+
layoutC4Deployment,
|
|
185
|
+
rollUpContextRelationships,
|
|
186
|
+
} from './c4/layout';
|
|
180
187
|
export type {
|
|
181
188
|
C4LayoutResult,
|
|
182
189
|
C4LayoutNode,
|
|
@@ -197,7 +204,10 @@ export {
|
|
|
197
204
|
renderC4DeploymentForExport,
|
|
198
205
|
} from './c4/renderer';
|
|
199
206
|
|
|
200
|
-
export {
|
|
207
|
+
export {
|
|
208
|
+
parseInitiativeStatus,
|
|
209
|
+
looksLikeInitiativeStatus,
|
|
210
|
+
} from './initiative-status/parser';
|
|
201
211
|
export type {
|
|
202
212
|
ParsedInitiativeStatus,
|
|
203
213
|
ISNode,
|
|
@@ -214,7 +224,10 @@ export type {
|
|
|
214
224
|
ISLayoutGroup,
|
|
215
225
|
} from './initiative-status/layout';
|
|
216
226
|
|
|
217
|
-
export {
|
|
227
|
+
export {
|
|
228
|
+
renderInitiativeStatus,
|
|
229
|
+
renderInitiativeStatusForExport,
|
|
230
|
+
} from './initiative-status/renderer';
|
|
218
231
|
export type { ISRenderOptions } from './initiative-status/renderer';
|
|
219
232
|
|
|
220
233
|
export { collapseInitiativeStatus } from './initiative-status/collapse';
|
|
@@ -247,16 +260,42 @@ export { collapseSitemapTree } from './sitemap/collapse';
|
|
|
247
260
|
|
|
248
261
|
// ── Infra Chart ────────────────────────────────────────────
|
|
249
262
|
export { parseInfra } from './infra/parser';
|
|
250
|
-
export type {
|
|
263
|
+
export type {
|
|
264
|
+
ParsedInfra,
|
|
265
|
+
InfraNode,
|
|
266
|
+
InfraEdge,
|
|
267
|
+
InfraGroup,
|
|
268
|
+
InfraTagGroup,
|
|
269
|
+
InfraProperty,
|
|
270
|
+
InfraDiagnostic,
|
|
271
|
+
InfraComputeParams,
|
|
272
|
+
InfraBehaviorKey,
|
|
273
|
+
} from './infra/types';
|
|
251
274
|
export { INFRA_BEHAVIOR_KEYS } from './infra/types';
|
|
252
275
|
export { computeInfra } from './infra/compute';
|
|
253
|
-
export type {
|
|
276
|
+
export type {
|
|
277
|
+
ComputedInfraModel,
|
|
278
|
+
ComputedInfraNode,
|
|
279
|
+
ComputedInfraEdge,
|
|
280
|
+
InfraLatencyPercentiles,
|
|
281
|
+
InfraAvailabilityPercentiles,
|
|
282
|
+
InfraCbState,
|
|
283
|
+
} from './infra/types';
|
|
254
284
|
export { validateInfra, validateComputed } from './infra/validation';
|
|
255
285
|
export { inferRoles, collectDiagramRoles } from './infra/roles';
|
|
256
286
|
export type { InfraRole } from './infra/roles';
|
|
257
287
|
export { layoutInfra } from './infra/layout';
|
|
258
|
-
export type {
|
|
259
|
-
|
|
288
|
+
export type {
|
|
289
|
+
InfraLayoutResult,
|
|
290
|
+
InfraLayoutNode,
|
|
291
|
+
InfraLayoutEdge,
|
|
292
|
+
InfraLayoutGroup,
|
|
293
|
+
} from './infra/layout';
|
|
294
|
+
export {
|
|
295
|
+
renderInfra,
|
|
296
|
+
parseAndLayoutInfra,
|
|
297
|
+
computeInfraLegendGroups,
|
|
298
|
+
} from './infra/renderer';
|
|
260
299
|
export type { InfraLegendGroup, InfraPlaybackState } from './infra/renderer';
|
|
261
300
|
export type { CollapsedSitemapResult } from './sitemap/collapse';
|
|
262
301
|
|
|
@@ -264,7 +303,13 @@ export type { CollapsedSitemapResult } from './sitemap/collapse';
|
|
|
264
303
|
export { parseGantt } from './gantt/parser';
|
|
265
304
|
export { calculateSchedule } from './gantt/calculator';
|
|
266
305
|
export { renderGantt, buildTagLaneRowList } from './gantt/renderer';
|
|
267
|
-
export type {
|
|
306
|
+
export type {
|
|
307
|
+
GanttInteractiveOptions,
|
|
308
|
+
GanttRow,
|
|
309
|
+
GanttGroupRow,
|
|
310
|
+
GanttTaskRow,
|
|
311
|
+
GanttLaneHeaderRow,
|
|
312
|
+
} from './gantt/renderer';
|
|
268
313
|
export { resolveTaskName, collectTasks } from './gantt/resolver';
|
|
269
314
|
export type {
|
|
270
315
|
ParsedGantt,
|
|
@@ -288,7 +333,11 @@ export { collapseOrgTree } from './org/collapse';
|
|
|
288
333
|
export type { CollapsedOrgResult } from './org/collapse';
|
|
289
334
|
|
|
290
335
|
export { resolveOrgImports } from './org/resolver';
|
|
291
|
-
export type {
|
|
336
|
+
export type {
|
|
337
|
+
ReadFileFn,
|
|
338
|
+
ResolveImportsResult,
|
|
339
|
+
ImportSource,
|
|
340
|
+
} from './org/resolver';
|
|
292
341
|
|
|
293
342
|
export { layoutGraph } from './graph/layout';
|
|
294
343
|
export type {
|
|
@@ -298,13 +347,23 @@ export type {
|
|
|
298
347
|
LayoutGroup,
|
|
299
348
|
} from './graph/layout';
|
|
300
349
|
|
|
301
|
-
export {
|
|
350
|
+
export {
|
|
351
|
+
renderFlowchart,
|
|
352
|
+
renderFlowchartForExport,
|
|
353
|
+
} from './graph/flowchart-renderer';
|
|
302
354
|
|
|
303
355
|
// ============================================================
|
|
304
356
|
// Config Builders (produce framework-specific config objects)
|
|
305
357
|
// ============================================================
|
|
306
358
|
|
|
307
|
-
export {
|
|
359
|
+
export {
|
|
360
|
+
buildExtendedChartOption,
|
|
361
|
+
buildSimpleChartOption,
|
|
362
|
+
renderExtendedChartForExport,
|
|
363
|
+
getExtendedChartLegendGroups,
|
|
364
|
+
getSimpleChartLegendGroups,
|
|
365
|
+
computeScatterLabelGraphics,
|
|
366
|
+
} from './echarts';
|
|
308
367
|
export type { ScatterLabelPoint } from './echarts';
|
|
309
368
|
export { renderLegendSvg, type LegendGroupData } from './utils/legend-svg';
|
|
310
369
|
export { LEGEND_HEIGHT } from './utils/legend-constants';
|
|
@@ -403,7 +462,13 @@ export {
|
|
|
403
462
|
PIPE_METADATA,
|
|
404
463
|
extractTagDeclarations,
|
|
405
464
|
} from './completion';
|
|
406
|
-
export type {
|
|
465
|
+
export type {
|
|
466
|
+
DiagramSymbols,
|
|
467
|
+
ExtractFn,
|
|
468
|
+
DirectiveSpec,
|
|
469
|
+
DirectiveValueSpec,
|
|
470
|
+
PipeKeySpec,
|
|
471
|
+
} from './completion';
|
|
407
472
|
|
|
408
473
|
export { parseFirstLine, ALL_CHART_TYPES } from './utils/parsing';
|
|
409
474
|
|