@diagrammo/dgmo 0.33.0 → 0.35.0

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.
Files changed (59) hide show
  1. package/.claude/commands/dgmo.md +17 -32
  2. package/.github/copilot-instructions.md +1 -1
  3. package/README.md +7 -1
  4. package/SKILL.md +1 -1
  5. package/dist/advanced.cjs +791 -614
  6. package/dist/advanced.d.cts +8 -51
  7. package/dist/advanced.d.ts +8 -51
  8. package/dist/advanced.js +791 -615
  9. package/dist/auto.cjs +793 -292
  10. package/dist/auto.js +95 -95
  11. package/dist/auto.mjs +793 -292
  12. package/dist/cli.cjs +145 -328
  13. package/dist/index.cjs +792 -291
  14. package/dist/index.js +792 -291
  15. package/docs/ai-integration.md +46 -26
  16. package/docs/language-reference.md +2 -2
  17. package/package.json +3 -3
  18. package/src/advanced.ts +0 -12
  19. package/src/boxes-and-lines/label-placement.ts +339 -0
  20. package/src/boxes-and-lines/layout-search.ts +16 -2
  21. package/src/boxes-and-lines/layout.ts +32 -7
  22. package/src/boxes-and-lines/renderer.ts +67 -139
  23. package/src/c4/parser.ts +15 -6
  24. package/src/chart.ts +1 -1
  25. package/src/class/parser.ts +6 -2
  26. package/src/cli-banner.ts +2 -3
  27. package/src/cli.ts +539 -1223
  28. package/src/cycle/parser.ts +4 -1
  29. package/src/dgmo-router.ts +16 -2
  30. package/src/diagnostics.ts +0 -0
  31. package/src/echarts.ts +5 -1
  32. package/src/er/parser.ts +5 -1
  33. package/src/gantt/parser.ts +13 -4
  34. package/src/graph/flowchart-parser.ts +5 -1
  35. package/src/graph/state-parser.ts +5 -1
  36. package/src/infra/parser.ts +10 -6
  37. package/src/journey-map/parser.ts +5 -2
  38. package/src/kanban/parser.ts +6 -2
  39. package/src/map/context-labels.ts +29 -19
  40. package/src/map/layout.ts +403 -108
  41. package/src/map/legend-band.ts +28 -0
  42. package/src/map/parser.ts +13 -4
  43. package/src/map/renderer.ts +74 -23
  44. package/src/map/resolver.ts +2 -2
  45. package/src/org/parser.ts +8 -2
  46. package/src/pyramid/parser.ts +4 -1
  47. package/src/raci/parser.ts +4 -1
  48. package/src/ring/parser.ts +4 -1
  49. package/src/sequence/parser.ts +6 -3
  50. package/src/sitemap/parser.ts +12 -3
  51. package/src/tech-radar/parser.ts +6 -3
  52. package/src/utils/parsing.ts +2 -2
  53. package/src/utils/tag-groups.ts +3 -3
  54. package/src/visualizations/parse.ts +9 -3
  55. package/src/migrate/data-comma.ts +0 -117
  56. package/src/migrate/embedded.ts +0 -238
  57. package/src/migrate/index.ts +0 -295
  58. package/src/migrate/line-classifier.ts +0 -128
  59. package/src/migrate/line-transformer.ts +0 -218
@@ -1,218 +0,0 @@
1
- // Single-line transformer for the `dgmo migrate` tool.
2
- //
3
- // Given a legacy line with a `|` metadata delimiter, emit the new
4
- // §1.4 same-line form (`Foo k: v, k: v` — no pipe). Chart-type-specific
5
- // bare-positional shapes (gantt `| 80%`, journey-map `| 4 Delighted`,
6
- // pyramid/ring `| description text`) are promoted to keyed metadata
7
- // per spec §13.8 / §22 / §23 / §24.
8
- //
9
- // Lines that the classifier flags as legacy but contain only invalid
10
- // content (e.g. `|` with nothing after) are returned verbatim with
11
- // `changed: false` — the legacy parser would have rejected them, the
12
- // new parser will too, and the migration tool's contract is "don't
13
- // repair pre-existing parse errors" (spec §"Migration Tool Contract").
14
-
15
- import { findUnsafePipePositions } from './line-classifier';
16
-
17
- /**
18
- * Rewrite every "unsafe" `|` (outside quotes / brace dropdowns /
19
- * arrow-label regions) inside `s` to a comma. Quoted, brace-nested,
20
- * and arrow-label pipes are left intact — this is the same scan the
21
- * classifier uses, applied as a substitution.
22
- */
23
- function replaceUnsafePipesWithCommas(s: string): string {
24
- const positions = findUnsafePipePositions(s);
25
- if (positions.length === 0) return s;
26
- const chars = s.split('');
27
- for (const pos of positions) {
28
- chars[pos] = ',';
29
- }
30
- return chars.join('');
31
- }
32
-
33
- export interface TransformResult {
34
- /** New line content (indent preserved); equal to input when `changed: false`. */
35
- readonly line: string;
36
- /** Whether the transformer mutated the line. */
37
- readonly changed: boolean;
38
- }
39
-
40
- // ============================================================
41
- // Chart-type-specific bare-positional promotions
42
- // ============================================================
43
-
44
- interface Promotion {
45
- /** Matches a single comma-tokenized bare meta segment. */
46
- readonly match: (token: string) => boolean;
47
- /** Returns a `key: value[, key: value]` string. */
48
- readonly promote: (token: string) => string;
49
- }
50
-
51
- // Gantt §13.8 — bare `<N>%` promotes to `progress: <N>`.
52
- const GANTT_PERCENT: Promotion = {
53
- match: (t) => /^\d+(?:\.\d+)?\s*%$/.test(t.trim()),
54
- promote: (t) => `progress: ${t.trim().replace(/\s*%$/, '')}`,
55
- };
56
-
57
- // Journey-map §22 — bare `<N>` or `<N> <Word>` promotes to
58
- // `score: <N>[, emotion: <Word>]`.
59
- const JOURNEY_SCORE: Promotion = {
60
- match: (t) => /^\d+(?:\s+[A-Za-z][A-Za-z0-9_-]*)?$/.test(t.trim()),
61
- promote: (t) => {
62
- const m = t.trim().match(/^(\d+)(?:\s+([A-Za-z][A-Za-z0-9_-]*))?$/);
63
- if (!m) return t;
64
- return m[2] ? `score: ${m[1]}, emotion: ${m[2]}` : `score: ${m[1]}`;
65
- },
66
- };
67
-
68
- const PROMOTIONS_BY_CHART: Record<string, readonly Promotion[]> = {
69
- gantt: [GANTT_PERCENT],
70
- 'journey-map': [JOURNEY_SCORE],
71
- };
72
-
73
- /**
74
- * Chart types whose meta region accepts a bare-text shorthand (`| Some
75
- * description text` with no `key:`) — promoted to `description: <text>`.
76
- * Only fires when the ENTIRE meta region contains no `:` at all.
77
- */
78
- const BARE_DESCRIPTION_CHARTS = new Set(['pyramid', 'ring']);
79
-
80
- // ============================================================
81
- // Meta region tokenization
82
- // ============================================================
83
- //
84
- // Split the meta region on commas, but respect quoted values so a
85
- // `description: "with, commas"` segment stays whole.
86
-
87
- function tokenizeMetaRegion(region: string): string[] {
88
- const tokens: string[] = [];
89
- let i = 0;
90
- let buf = '';
91
- let inQuote: '"' | "'" | null = null;
92
- while (i < region.length) {
93
- const ch = region[i]!;
94
- if (inQuote) {
95
- buf += ch;
96
- if (ch === inQuote) inQuote = null;
97
- i++;
98
- continue;
99
- }
100
- if (ch === '"' || ch === "'") {
101
- inQuote = ch as '"' | "'";
102
- buf += ch;
103
- i++;
104
- continue;
105
- }
106
- if (ch === ',') {
107
- const t = buf.trim();
108
- if (t) tokens.push(t);
109
- buf = '';
110
- i++;
111
- continue;
112
- }
113
- buf += ch;
114
- i++;
115
- }
116
- const tail = buf.trim();
117
- if (tail) tokens.push(tail);
118
- return tokens;
119
- }
120
-
121
- // ============================================================
122
- // Main transformer
123
- // ============================================================
124
-
125
- /**
126
- * Transform `line` from legacy `Foo | k: v, k: v` into the new §1.4
127
- * same-line form. `chartType` enables chart-type-specific bare-positional
128
- * promotions; pass `null` for the conservative generic transform.
129
- */
130
- export function transformLine(
131
- line: string,
132
- chartType: string | null
133
- ): TransformResult {
134
- // Preserve the exact leading indent (mix of tabs/spaces).
135
- const indentMatch = line.match(/^[ \t]*/);
136
- const indent = indentMatch ? indentMatch[0] : '';
137
- const body = line.substring(indent.length);
138
-
139
- const pipePositions = findUnsafePipePositions(body);
140
- if (pipePositions.length === 0) {
141
- return { line, changed: false };
142
- }
143
-
144
- // First unsafe `|` is the cut point. Legacy grammar nominally
145
- // disallowed multiple metadata pipes on a line (E_MULTIPLE_PIPES),
146
- // but the pattern `Foo | k: v | k: v` is common in user content —
147
- // authors treated `|` as an inter-key delimiter. Convert any
148
- // additional unsafe pipes in the meta region into commas so the
149
- // tokenizer sees one flat comma-separated key list.
150
- const cut = pipePositions[0]!;
151
- const nameRegion = body.substring(0, cut).trimEnd();
152
- let metaRegion = body.substring(cut + 1).trimStart();
153
- if (pipePositions.length > 1) {
154
- metaRegion = replaceUnsafePipesWithCommas(metaRegion);
155
- }
156
-
157
- // Pyramid/ring "bare description" — entire meta region carries no
158
- // `:` AND no unsafe-pipe (i.e. no further metadata segments). The
159
- // whole text becomes `description: <text>`. Commas in the source
160
- // text are preserved by wrapping in quotes when needed.
161
- if (
162
- chartType !== null &&
163
- BARE_DESCRIPTION_CHARTS.has(chartType) &&
164
- !metaRegion.includes(':')
165
- ) {
166
- const text = metaRegion.trim();
167
- if (!text) {
168
- // `Foo |` with nothing after — let the new parser surface
169
- // the issue (empty-meta or pipe-removed); strip the pipe but
170
- // emit no metadata.
171
- return {
172
- line: indent + nameRegion,
173
- changed: true,
174
- };
175
- }
176
- const value = text.includes(',') ? `"${text}"` : text;
177
- return {
178
- line: `${indent}${nameRegion} description: ${value}`,
179
- changed: true,
180
- };
181
- }
182
-
183
- const tokens = tokenizeMetaRegion(metaRegion);
184
- const promotions = chartType ? (PROMOTIONS_BY_CHART[chartType] ?? []) : [];
185
-
186
- const emitted: string[] = [];
187
- for (const raw of tokens) {
188
- if (raw.includes(':')) {
189
- // Already a `key: value` pair — emit verbatim. Whitespace
190
- // around the `:` is preserved as authored; the new parser
191
- // tolerates either form (`k:v`, `k: v`).
192
- emitted.push(raw);
193
- continue;
194
- }
195
- // Bare token — try chart-type-specific promotions.
196
- const promo = promotions.find((p) => p.match(raw));
197
- if (promo) {
198
- emitted.push(promo.promote(raw));
199
- continue;
200
- }
201
- // Unrecognized bare token. Carry through verbatim — the new
202
- // parser will surface a diagnostic. Don't drop silently; the
203
- // user needs to see what's left over.
204
- emitted.push(raw);
205
- }
206
-
207
- if (emitted.length === 0) {
208
- return {
209
- line: indent + nameRegion,
210
- changed: true,
211
- };
212
- }
213
-
214
- return {
215
- line: `${indent}${nameRegion} ${emitted.join(', ')}`,
216
- changed: true,
217
- };
218
- }