@diagrammo/dgmo 0.8.1 → 0.8.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/dist/cli.cjs +189 -194
- package/dist/index.cjs +450 -596
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -6
- package/dist/index.d.ts +7 -6
- package/dist/index.js +450 -596
- package/dist/index.js.map +1 -1
- package/docs/language-reference.md +821 -1060
- package/package.json +1 -1
- package/src/c4/parser.ts +19 -13
- package/src/chart.ts +69 -47
- package/src/class/parser.ts +46 -19
- package/src/class/renderer.ts +2 -2
- package/src/cli.ts +11 -16
- package/src/completion.ts +29 -25
- package/src/d3.ts +173 -174
- package/src/dgmo-router.ts +1 -1
- package/src/echarts.ts +42 -22
- package/src/er/parser.ts +9 -17
- package/src/gantt/parser.ts +108 -40
- package/src/graph/flowchart-parser.ts +7 -55
- package/src/graph/state-parser.ts +7 -10
- package/src/infra/parser.ts +6 -126
- package/src/infra/types.ts +0 -1
- package/src/initiative-status/parser.ts +7 -13
- package/src/kanban/parser.ts +4 -7
- package/src/org/parser.ts +5 -8
- package/src/org/resolver.ts +3 -3
- package/src/render.ts +1 -2
- package/src/sequence/parser.ts +22 -45
- package/src/sitemap/parser.ts +10 -17
- package/src/utils/parsing.ts +9 -43
- package/src/utils/tag-groups.ts +4 -41
- package/src/infra/serialize.ts +0 -67
package/src/utils/parsing.ts
CHANGED
|
@@ -49,9 +49,6 @@ export function extractColor(
|
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
/** @deprecated Matches `chart: <type>` header lines. Remove after all parsers migrate. */
|
|
53
|
-
export const CHART_TYPE_RE = /^chart\s*:\s*(.+)/i;
|
|
54
|
-
|
|
55
52
|
/** @deprecated Matches `title: <text>` header lines. Remove after all parsers migrate. */
|
|
56
53
|
export const TITLE_RE = /^title\s*:\s*(.+)/i;
|
|
57
54
|
|
|
@@ -61,11 +58,6 @@ export const OPTION_RE = /^([a-z][a-z0-9-]*)\s*:\s*(.+)$/i;
|
|
|
61
58
|
/** Matches `option value` header lines (space-separated, no colon). */
|
|
62
59
|
export const OPTION_NOCOLON_RE = /^([a-z][a-z0-9-]*)\s+(.+)$/i;
|
|
63
60
|
|
|
64
|
-
/** Matches `# GroupName` lines — alternate group notation. */
|
|
65
|
-
export const GROUP_HASH_RE = /^#\s+(.+)$/;
|
|
66
|
-
|
|
67
|
-
/** Matches `## ...` lines — parse error with helpful hint. */
|
|
68
|
-
export const DOUBLE_HASH_RE = /^##\s/;
|
|
69
61
|
|
|
70
62
|
// ── New shared utilities ─────────────────────────────────────
|
|
71
63
|
|
|
@@ -81,24 +73,7 @@ export function parseFirstLine(
|
|
|
81
73
|
const trimmed = line.trim();
|
|
82
74
|
if (!trimmed || trimmed.startsWith('//')) return null;
|
|
83
75
|
|
|
84
|
-
//
|
|
85
|
-
const oldMatch = trimmed.match(CHART_TYPE_RE);
|
|
86
|
-
if (oldMatch) {
|
|
87
|
-
const parts = oldMatch[1].trim();
|
|
88
|
-
// Could be `chart: gantt My Title` — first token is type
|
|
89
|
-
const spaceIdx = parts.indexOf(' ');
|
|
90
|
-
if (spaceIdx === -1) {
|
|
91
|
-
const ct = parts.toLowerCase();
|
|
92
|
-
return ALL_CHART_TYPES.has(ct) ? { chartType: ct, title: undefined } : null;
|
|
93
|
-
}
|
|
94
|
-
const ct = parts.substring(0, spaceIdx).toLowerCase();
|
|
95
|
-
if (ALL_CHART_TYPES.has(ct)) {
|
|
96
|
-
return { chartType: ct, title: parts.substring(spaceIdx + 1).trim() || undefined };
|
|
97
|
-
}
|
|
98
|
-
return null;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// New-style: first token is chart type, rest is title
|
|
76
|
+
// First token is chart type, rest is title
|
|
102
77
|
const spaceIdx = trimmed.indexOf(' ');
|
|
103
78
|
if (spaceIdx === -1) {
|
|
104
79
|
const ct = trimmed.toLowerCase();
|
|
@@ -330,17 +305,7 @@ export function parseSeriesNames(
|
|
|
330
305
|
return { series, names, nameColors, nameLineNumbers, newIndex };
|
|
331
306
|
}
|
|
332
307
|
|
|
333
|
-
|
|
334
|
-
* Normalize a direction/orientation value to canonical form ('LR' | 'TB').
|
|
335
|
-
* Accepts 'lr', 'tb', 'horizontal', 'vertical' (case-insensitive).
|
|
336
|
-
* Returns null if the value is not recognized.
|
|
337
|
-
*/
|
|
338
|
-
export function normalizeDirection(value: string): 'LR' | 'TB' | null {
|
|
339
|
-
const v = value.trim().toLowerCase();
|
|
340
|
-
if (v === 'lr' || v === 'horizontal') return 'LR';
|
|
341
|
-
if (v === 'tb' || v === 'vertical') return 'TB';
|
|
342
|
-
return null;
|
|
343
|
-
}
|
|
308
|
+
|
|
344
309
|
|
|
345
310
|
/**
|
|
346
311
|
* Infer arrow color from label text.
|
|
@@ -358,22 +323,23 @@ export function inferArrowColor(label: string): string | undefined {
|
|
|
358
323
|
return undefined;
|
|
359
324
|
}
|
|
360
325
|
|
|
361
|
-
/**
|
|
362
|
-
export const
|
|
326
|
+
/** Error message for multiple pipes on a single line. */
|
|
327
|
+
export const MULTIPLE_PIPE_ERROR =
|
|
363
328
|
'Use a single "|" to start metadata, then separate items with commas.';
|
|
364
329
|
|
|
365
330
|
/**
|
|
366
331
|
* Parse metadata from segments after the first (name) segment.
|
|
367
332
|
* A single `|` separates the label from metadata; items after the pipe are comma-delimited.
|
|
368
|
-
* Multiple pipes
|
|
333
|
+
* Multiple pipes produce an error.
|
|
369
334
|
*/
|
|
370
335
|
export function parsePipeMetadata(
|
|
371
336
|
segments: string[],
|
|
372
337
|
aliasMap: Map<string, string> = new Map(),
|
|
373
|
-
|
|
338
|
+
errorMultiplePipes?: () => void,
|
|
374
339
|
): Record<string, string> {
|
|
375
|
-
if (segments.length > 2
|
|
376
|
-
|
|
340
|
+
if (segments.length > 2) {
|
|
341
|
+
if (errorMultiplePipes) errorMultiplePipes();
|
|
342
|
+
return {};
|
|
377
343
|
}
|
|
378
344
|
const metadata: Record<string, string> = {};
|
|
379
345
|
const raw = segments.slice(1).join(',');
|
package/src/utils/tag-groups.ts
CHANGED
|
@@ -26,25 +26,15 @@ export interface TagBlockMatch {
|
|
|
26
26
|
name: string;
|
|
27
27
|
alias: string | undefined;
|
|
28
28
|
colorHint: string | undefined;
|
|
29
|
-
/** true when the heading used `## …` (deprecated) */
|
|
30
|
-
deprecated: boolean;
|
|
31
29
|
/** Inline tag values parsed from single-line form (e.g., `tag Priority p High(red), Low(blue)`) */
|
|
32
30
|
inlineValues?: string[];
|
|
33
31
|
}
|
|
34
32
|
|
|
35
33
|
// ── Regexes ─────────────────────────────────────────────────
|
|
36
34
|
|
|
37
|
-
/**
|
|
38
|
-
export const TAG_BLOCK_RE =
|
|
39
|
-
/^tag:\s+(.+?)(?:\s+alias\s+(\w+))?(?:\s*\(([^)]+)\))?\s*$/i;
|
|
40
|
-
|
|
41
|
-
/** New canonical syntax: line starting with `tag` keyword (no colon). */
|
|
35
|
+
/** Canonical syntax: line starting with `tag` keyword (no colon). */
|
|
42
36
|
export const TAG_BLOCK_NOCOLON_RE = /^tag\s+/i;
|
|
43
37
|
|
|
44
|
-
/** @deprecated Legacy syntax: `## GroupName [alias X] [(color)]` */
|
|
45
|
-
export const GROUP_HEADING_RE =
|
|
46
|
-
/^##\s+(.+?)(?:\s+alias\s+(\w+))?(?:\s*\(([^)]+)\))?\s*$/;
|
|
47
|
-
|
|
48
38
|
// ── Alias Inference ─────────────────────────────────────────
|
|
49
39
|
|
|
50
40
|
/** Returns true if the token looks like an alias: 1-4 lowercase ASCII characters. */
|
|
@@ -54,9 +44,9 @@ function isAliasToken(token: string): boolean {
|
|
|
54
44
|
|
|
55
45
|
// ── Matchers ────────────────────────────────────────────────
|
|
56
46
|
|
|
57
|
-
/** Returns true if `trimmed` is a tag block heading
|
|
47
|
+
/** Returns true if `trimmed` is a tag block heading. */
|
|
58
48
|
export function isTagBlockHeading(trimmed: string): boolean {
|
|
59
|
-
return TAG_BLOCK_NOCOLON_RE.test(trimmed)
|
|
49
|
+
return TAG_BLOCK_NOCOLON_RE.test(trimmed);
|
|
60
50
|
}
|
|
61
51
|
|
|
62
52
|
/**
|
|
@@ -173,7 +163,6 @@ export function parseTagDeclaration(line: string): TagBlockMatch | null {
|
|
|
173
163
|
name,
|
|
174
164
|
alias,
|
|
175
165
|
colorHint,
|
|
176
|
-
deprecated: false,
|
|
177
166
|
inlineValues: inlineValues && inlineValues.length > 0 ? inlineValues : undefined,
|
|
178
167
|
};
|
|
179
168
|
}
|
|
@@ -310,31 +299,5 @@ export function injectDefaultTagMetadata(
|
|
|
310
299
|
// ── Matchers ────────────────────────────────────────────────
|
|
311
300
|
|
|
312
301
|
export function matchTagBlockHeading(trimmed: string): TagBlockMatch | null {
|
|
313
|
-
|
|
314
|
-
const nocolonResult = parseTagDeclaration(trimmed);
|
|
315
|
-
if (nocolonResult) return nocolonResult;
|
|
316
|
-
|
|
317
|
-
// Try old colon syntax: `tag: GroupName [alias X] [(color)]`
|
|
318
|
-
const tagMatch = trimmed.match(TAG_BLOCK_RE);
|
|
319
|
-
if (tagMatch) {
|
|
320
|
-
return {
|
|
321
|
-
name: tagMatch[1].trim(),
|
|
322
|
-
alias: tagMatch[2] || undefined,
|
|
323
|
-
colorHint: tagMatch[3] || undefined,
|
|
324
|
-
deprecated: false,
|
|
325
|
-
};
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
// Fall back to legacy ## syntax
|
|
329
|
-
const groupMatch = trimmed.match(GROUP_HEADING_RE);
|
|
330
|
-
if (groupMatch) {
|
|
331
|
-
return {
|
|
332
|
-
name: groupMatch[1].trim(),
|
|
333
|
-
alias: groupMatch[2] || undefined,
|
|
334
|
-
colorHint: groupMatch[3] || undefined,
|
|
335
|
-
deprecated: true,
|
|
336
|
-
};
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
return null;
|
|
302
|
+
return parseTagDeclaration(trimmed);
|
|
340
303
|
}
|
package/src/infra/serialize.ts
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
// ============================================================
|
|
2
|
-
// Infra Scenario Serializer
|
|
3
|
-
// ============================================================
|
|
4
|
-
//
|
|
5
|
-
// Converts interactive overrides into a `scenario:` DSL block.
|
|
6
|
-
// Only includes properties that differ from the base diagram.
|
|
7
|
-
|
|
8
|
-
import type { ParsedInfra, InfraComputeParams } from './types';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Serialize interactive overrides as a DSL `scenario:` block.
|
|
12
|
-
* Returns an empty string if nothing differs from the base diagram.
|
|
13
|
-
*/
|
|
14
|
-
export function serializeScenario(name: string, parsed: ParsedInfra, overrides: InfraComputeParams): string {
|
|
15
|
-
const lines: string[] = [];
|
|
16
|
-
|
|
17
|
-
// Edge RPS override
|
|
18
|
-
const edgeNode = parsed.nodes.find((n) => n.isEdge);
|
|
19
|
-
if (edgeNode && overrides.rps != null) {
|
|
20
|
-
const baseRps = edgeNode.properties.find((p) => p.key === 'rps');
|
|
21
|
-
const baseVal = baseRps ? (typeof baseRps.value === 'number' ? baseRps.value : parseFloat(String(baseRps.value)) || 0) : 0;
|
|
22
|
-
if (overrides.rps !== baseVal) {
|
|
23
|
-
lines.push(` ${edgeNode.id}`);
|
|
24
|
-
lines.push(` rps: ${overrides.rps}`);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Instance overrides and property overrides per node
|
|
29
|
-
const instanceOv = overrides.instanceOverrides ?? {};
|
|
30
|
-
const propOv = overrides.propertyOverrides ?? {};
|
|
31
|
-
|
|
32
|
-
for (const node of parsed.nodes) {
|
|
33
|
-
if (node.isEdge) continue;
|
|
34
|
-
|
|
35
|
-
const nodeLines: string[] = [];
|
|
36
|
-
|
|
37
|
-
// Instance override
|
|
38
|
-
if (instanceOv[node.id] != null) {
|
|
39
|
-
const baseProp = node.properties.find((p) => p.key === 'instances');
|
|
40
|
-
const baseVal = baseProp ? (typeof baseProp.value === 'number' ? baseProp.value : parseFloat(String(baseProp.value)) || 1) : 1;
|
|
41
|
-
if (instanceOv[node.id] !== baseVal) {
|
|
42
|
-
nodeLines.push(` instances: ${instanceOv[node.id]}`);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Property overrides
|
|
47
|
-
const nodePropOv = propOv[node.id];
|
|
48
|
-
if (nodePropOv) {
|
|
49
|
-
for (const [key, val] of Object.entries(nodePropOv)) {
|
|
50
|
-
const baseProp = node.properties.find((p) => p.key === key);
|
|
51
|
-
const baseVal = baseProp ? (typeof baseProp.value === 'number' ? baseProp.value : parseFloat(String(baseProp.value)) || 0) : 0;
|
|
52
|
-
if (val !== baseVal) {
|
|
53
|
-
nodeLines.push(` ${key}: ${val}`);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (nodeLines.length > 0) {
|
|
59
|
-
lines.push(` ${node.id}`);
|
|
60
|
-
lines.push(...nodeLines);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (lines.length === 0) return '';
|
|
65
|
-
|
|
66
|
-
return `scenario: ${name}\n${lines.join('\n')}\n`;
|
|
67
|
-
}
|