@diagrammo/dgmo 0.25.5 → 0.27.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.
- package/README.md +3 -3
- package/dist/advanced.cjs +4255 -2756
- package/dist/advanced.d.cts +285 -59
- package/dist/advanced.d.ts +285 -59
- package/dist/advanced.js +4253 -2750
- package/dist/auto.cjs +4051 -2589
- package/dist/auto.js +124 -122
- package/dist/auto.mjs +4051 -2589
- package/dist/cli.cjs +172 -170
- package/dist/editor.cjs +4 -0
- package/dist/editor.js +4 -0
- package/dist/highlight.cjs +4 -0
- package/dist/highlight.js +4 -0
- package/dist/index.cjs +4076 -2591
- package/dist/index.d.cts +33 -8
- package/dist/index.d.ts +33 -8
- package/dist/index.js +4076 -2591
- package/dist/internal.cjs +4255 -2756
- package/dist/internal.d.cts +285 -59
- package/dist/internal.d.ts +285 -59
- package/dist/internal.js +4253 -2750
- package/dist/map-data/PROVENANCE.json +1 -1
- package/dist/map-data/airport-collisions.json +1 -0
- package/dist/map-data/airports.json +1 -0
- package/docs/language-reference.md +68 -18
- package/gallery/fixtures/boxes-and-lines-diverging.dgmo +15 -0
- package/gallery/fixtures/map-choropleth-diverging.dgmo +9 -0
- package/gallery/fixtures/map-region-values.dgmo +13 -0
- package/gallery/fixtures/map-subnational-zoom.dgmo +12 -0
- package/gallery/fixtures/map-tagged-legs.dgmo +16 -0
- package/gallery/fixtures/map-undirected-edges.dgmo +12 -0
- package/package.json +1 -1
- package/src/advanced.ts +3 -6
- package/src/auto/index.ts +1 -1
- package/src/boxes-and-lines/layout.ts +146 -26
- package/src/boxes-and-lines/parser.ts +43 -8
- package/src/boxes-and-lines/renderer.ts +223 -96
- package/src/boxes-and-lines/types.ts +9 -2
- package/src/c4/layout.ts +14 -32
- package/src/c4/parser.ts +9 -5
- package/src/c4/renderer.ts +34 -39
- package/src/class/layout.ts +118 -18
- package/src/class/parser.ts +35 -1
- package/src/class/renderer.ts +58 -2
- package/src/class/types.ts +3 -0
- package/src/cli.ts +4 -4
- package/src/completion-types.ts +0 -1
- package/src/completion.ts +106 -51
- package/src/cycle/layout.ts +55 -72
- package/src/cycle/renderer.ts +11 -6
- package/src/d3.ts +78 -117
- package/src/diagnostics.ts +16 -0
- package/src/echarts.ts +46 -33
- package/src/editor/keywords.ts +4 -0
- package/src/er/layout.ts +114 -22
- package/src/er/parser.ts +28 -1
- package/src/er/renderer.ts +55 -2
- package/src/er/types.ts +3 -0
- package/src/gantt/renderer.ts +46 -38
- package/src/gantt/resolver.ts +9 -2
- package/src/graph/edge-spline.ts +29 -0
- package/src/graph/flowchart-parser.ts +35 -2
- package/src/graph/flowchart-renderer.ts +80 -52
- package/src/graph/layout.ts +206 -23
- package/src/graph/notes.ts +21 -0
- package/src/graph/state-parser.ts +26 -1
- package/src/graph/state-renderer.ts +80 -52
- package/src/graph/types.ts +13 -0
- package/src/index.ts +1 -1
- package/src/infra/layout.ts +46 -26
- package/src/infra/parser.ts +1 -1
- package/src/infra/renderer.ts +16 -7
- package/src/journey-map/layout.ts +38 -49
- package/src/journey-map/renderer.ts +22 -45
- package/src/kanban/renderer.ts +15 -6
- package/src/label-layout.ts +3 -3
- package/src/map/completion.ts +77 -22
- package/src/map/context-labels.ts +57 -12
- package/src/map/data/PROVENANCE.json +1 -1
- package/src/map/data/airport-collisions.json +1 -0
- package/src/map/data/airports.json +1 -0
- package/src/map/data/types.ts +19 -0
- package/src/map/layout.ts +1196 -90
- package/src/map/legend-band.ts +2 -2
- package/src/map/load-data.ts +10 -1
- package/src/map/parser.ts +61 -32
- package/src/map/renderer.ts +284 -12
- package/src/map/resolved-types.ts +15 -1
- package/src/map/resolver.ts +132 -12
- package/src/map/types.ts +28 -8
- package/src/migrate/embedded.ts +9 -7
- package/src/mindmap/text-wrap.ts +13 -14
- package/src/org/layout.ts +19 -17
- package/src/org/renderer.ts +11 -4
- package/src/palettes/color-utils.ts +82 -21
- package/src/palettes/index.ts +0 -19
- package/src/palettes/registry.ts +1 -1
- package/src/palettes/types.ts +2 -2
- package/src/pert/layout.ts +48 -40
- package/src/pert/parser.ts +0 -14
- package/src/pert/renderer.ts +30 -43
- package/src/pyramid/renderer.ts +4 -5
- package/src/raci/renderer.ts +42 -70
- package/src/render.ts +1 -1
- package/src/ring/renderer.ts +1 -2
- package/src/sequence/parser.ts +100 -22
- package/src/sequence/renderer.ts +75 -50
- package/src/sitemap/layout.ts +27 -19
- package/src/sitemap/renderer.ts +12 -5
- package/src/tech-radar/renderer.ts +11 -35
- package/src/utils/arrow-markers.ts +51 -0
- package/src/utils/fit-canvas.ts +64 -0
- package/src/utils/legend-constants.ts +8 -54
- package/src/utils/legend-d3.ts +10 -7
- package/src/utils/legend-layout.ts +7 -4
- package/src/utils/legend-types.ts +10 -4
- package/src/utils/note-box/constants.ts +25 -0
- package/src/utils/note-box/index.ts +11 -0
- package/src/utils/note-box/metrics.ts +90 -0
- package/src/utils/note-box/svg.ts +331 -0
- package/src/utils/notes/bounds.ts +30 -0
- package/src/utils/notes/build.ts +131 -0
- package/src/utils/notes/index.ts +18 -0
- package/src/utils/notes/model.ts +19 -0
- package/src/utils/notes/parse.ts +131 -0
- package/src/utils/notes/place.ts +177 -0
- package/src/utils/notes/resolve.ts +88 -0
- package/src/utils/number-format.ts +36 -0
- package/src/utils/parsing.ts +41 -0
- package/src/utils/reserved-key-registry.ts +4 -0
- package/src/utils/text-measure.ts +122 -0
- package/src/wireframe/layout.ts +4 -2
- package/src/wireframe/renderer.ts +8 -6
- package/src/palettes/dracula.ts +0 -68
- package/src/palettes/gruvbox.ts +0 -85
- package/src/palettes/monokai.ts +0 -68
- package/src/palettes/one-dark.ts +0 -70
- package/src/palettes/rose-pine.ts +0 -84
- package/src/palettes/solarized.ts +0 -77
package/src/map/legend-band.ts
CHANGED
package/src/map/load-data.ts
CHANGED
|
@@ -18,7 +18,12 @@
|
|
|
18
18
|
// `await import('jsdom')` seam in render.ts. The web build injects `MapData` via
|
|
19
19
|
// DI and never calls `loadMapData`, so the dynamic import only runs in Node.
|
|
20
20
|
import type { MapData } from './resolved-types';
|
|
21
|
-
import type {
|
|
21
|
+
import type {
|
|
22
|
+
BoundaryTopology,
|
|
23
|
+
Gazetteer,
|
|
24
|
+
WaterBodies,
|
|
25
|
+
AirportData,
|
|
26
|
+
} from './data/types';
|
|
22
27
|
|
|
23
28
|
type NodeBuiltins = {
|
|
24
29
|
readFile: typeof import('node:fs/promises').readFile;
|
|
@@ -47,6 +52,7 @@ const FILES = {
|
|
|
47
52
|
naLand: 'na-land.json',
|
|
48
53
|
naLakes: 'na-lakes.json',
|
|
49
54
|
waterBodies: 'water-bodies.json',
|
|
55
|
+
airports: 'airports.json',
|
|
50
56
|
gazetteer: 'gazetteer.json',
|
|
51
57
|
} as const;
|
|
52
58
|
|
|
@@ -137,6 +143,7 @@ export function loadMapData(): Promise<MapData> {
|
|
|
137
143
|
naLand,
|
|
138
144
|
naLakes,
|
|
139
145
|
waterBodies,
|
|
146
|
+
airports,
|
|
140
147
|
gazetteer,
|
|
141
148
|
] = await Promise.all([
|
|
142
149
|
// worldCoarse (110m) is LOAD-BEARING but NOT a render source: the world
|
|
@@ -155,6 +162,7 @@ export function loadMapData(): Promise<MapData> {
|
|
|
155
162
|
readJson<BoundaryTopology>(nb, dir, FILES.naLand).catch(() => undefined),
|
|
156
163
|
readJson<BoundaryTopology>(nb, dir, FILES.naLakes).catch(() => undefined),
|
|
157
164
|
readJson<WaterBodies>(nb, dir, FILES.waterBodies).catch(() => undefined),
|
|
165
|
+
readJson<AirportData>(nb, dir, FILES.airports).catch(() => undefined),
|
|
158
166
|
readJson<Gazetteer>(nb, dir, FILES.gazetteer),
|
|
159
167
|
]);
|
|
160
168
|
return validate({
|
|
@@ -168,6 +176,7 @@ export function loadMapData(): Promise<MapData> {
|
|
|
168
176
|
...(naLand && { naLand }),
|
|
169
177
|
...(naLakes && { naLakes }),
|
|
170
178
|
...(waterBodies && { waterBodies }),
|
|
179
|
+
...(airports && { airports }),
|
|
171
180
|
});
|
|
172
181
|
})().catch((e: unknown) => {
|
|
173
182
|
cache = undefined; // don't poison future calls with a rejected promise
|
package/src/map/parser.ts
CHANGED
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
import { makeDgmoError, formatDgmoError } from '../diagnostics';
|
|
6
6
|
import type { DgmoError } from '../diagnostics';
|
|
7
7
|
import type { Writable } from '../utils/brand';
|
|
8
|
+
import type { PaletteColors } from '../palettes/types';
|
|
8
9
|
import {
|
|
9
10
|
measureIndent,
|
|
10
11
|
splitNameAndMeta,
|
|
11
12
|
extractColor,
|
|
12
|
-
|
|
13
|
+
peelRampColors,
|
|
13
14
|
} from '../utils/parsing';
|
|
14
15
|
import {
|
|
15
16
|
MAP_REGISTRY,
|
|
@@ -40,10 +41,14 @@ const NUMERIC_LEAD_RE = /^[+-]?\d/; // a name region that starts like a number
|
|
|
40
41
|
const SCOPE_RE = /^[A-Z]{2}(?:-[A-Z0-9]{1,3})?$/;
|
|
41
42
|
// Arrow tokens (longest-match first); only recognized with surrounding
|
|
42
43
|
// whitespace, so hyphens inside names (`office-east`) and `foo-bar` are safe.
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
// Drop the trailing `>` to drop the arrowhead: `--`/`-label-` are undirected
|
|
45
|
+
// straight, `~~`/`~label~` undirected arc. `[^>]` excludes `>` so an undirected
|
|
46
|
+
// branch can never swallow a directed token; directed branches are listed first.
|
|
47
|
+
const ARROW_TOKENS = '-[^>]*?->|->|~[^>]*?~>|~>|-[^>]*?-|~[^>]*?~';
|
|
48
|
+
const ARROW_SPLIT = new RegExp(`\\s+(${ARROW_TOKENS})\\s+`);
|
|
49
|
+
const HUB_RE = new RegExp(`^(${ARROW_TOKENS})\\s+(.+)$`);
|
|
45
50
|
// A route leg line: an optional leading arrow (with in-arrow label) + a destination.
|
|
46
|
-
const LEG_ARROW_RE =
|
|
51
|
+
const LEG_ARROW_RE = new RegExp(`^(${ARROW_TOKENS})\\s+(.+)$`);
|
|
47
52
|
const AT_RE = /(^|[\s,])at\s*:/i; // the removed `at:` coord form (§24B.9)
|
|
48
53
|
|
|
49
54
|
// The 14 map-specific directives (§24B.2): 6 irreducible-intent + 8 `no-*`
|
|
@@ -63,8 +68,10 @@ const DIRECTIVE_SET: ReadonlySet<string> = new Set([
|
|
|
63
68
|
'no-relief',
|
|
64
69
|
'no-context-labels',
|
|
65
70
|
'no-region-labels',
|
|
71
|
+
'no-region-value',
|
|
66
72
|
'no-poi-labels',
|
|
67
73
|
'no-colorize',
|
|
74
|
+
'no-cities',
|
|
68
75
|
'no-cluster-pois',
|
|
69
76
|
]);
|
|
70
77
|
|
|
@@ -86,7 +93,7 @@ function stripInlineComment(line: string): string {
|
|
|
86
93
|
.replace(/\s+$/, '');
|
|
87
94
|
}
|
|
88
95
|
|
|
89
|
-
export function parseMap(content: string): ParsedMap {
|
|
96
|
+
export function parseMap(content: string, palette?: PaletteColors): ParsedMap {
|
|
90
97
|
const result: Writable<ParsedMap> = {
|
|
91
98
|
title: null,
|
|
92
99
|
titleLineNumber: null,
|
|
@@ -197,12 +204,17 @@ export function parseMap(content: string): ParsedMap {
|
|
|
197
204
|
if (hub) {
|
|
198
205
|
const src = open.poi.poi.alias ?? poiName(open.poi.poi.pos);
|
|
199
206
|
if (src) {
|
|
207
|
+
const arr = classifyArrow(hub[1]!, lineNumber);
|
|
208
|
+
const hubSplit = splitNameAndMeta(hub[2]!, registry(), aliasMap);
|
|
209
|
+
const { tags, meta } = partitionMeta(hubSplit.meta, tagGroupNames());
|
|
200
210
|
edges.push({
|
|
201
211
|
from: src,
|
|
202
|
-
to:
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
212
|
+
to: hubSplit.name.trim(),
|
|
213
|
+
...(arr.label !== undefined && { label: arr.label }),
|
|
214
|
+
directed: arr.directed,
|
|
215
|
+
style: arr.style,
|
|
216
|
+
meta,
|
|
217
|
+
tags,
|
|
206
218
|
lineNumber,
|
|
207
219
|
});
|
|
208
220
|
}
|
|
@@ -287,12 +299,18 @@ export function parseMap(content: string): ParsedMap {
|
|
|
287
299
|
switch (key) {
|
|
288
300
|
case 'region-metric': {
|
|
289
301
|
dup(d.regionMetric);
|
|
290
|
-
//
|
|
291
|
-
//
|
|
292
|
-
|
|
293
|
-
|
|
302
|
+
// Up to two trailing colors name the choropleth ramp endpoints
|
|
303
|
+
// (§24B.3): one ⇒ high hue over a neutral low; two ⇒ `low high`. The
|
|
304
|
+
// label keeps the rest. `region-metric Sales ($M) green red` →
|
|
305
|
+
// green→red ramp.
|
|
306
|
+
const {
|
|
307
|
+
label: rmLabel,
|
|
308
|
+
low: rmLow,
|
|
309
|
+
high: rmHigh,
|
|
310
|
+
} = peelRampColors(value);
|
|
294
311
|
d.regionMetric = rmLabel;
|
|
295
|
-
if (
|
|
312
|
+
if (rmHigh) d.regionMetricColor = rmHigh;
|
|
313
|
+
if (rmLow) d.regionMetricLowColor = rmLow;
|
|
296
314
|
break;
|
|
297
315
|
}
|
|
298
316
|
case 'poi-metric':
|
|
@@ -335,12 +353,18 @@ export function parseMap(content: string): ParsedMap {
|
|
|
335
353
|
case 'no-region-labels':
|
|
336
354
|
d.noRegionLabels = true;
|
|
337
355
|
break;
|
|
356
|
+
case 'no-region-value':
|
|
357
|
+
d.noRegionValue = true;
|
|
358
|
+
break;
|
|
338
359
|
case 'no-poi-labels':
|
|
339
360
|
d.noPoiLabels = true;
|
|
340
361
|
break;
|
|
341
362
|
case 'no-colorize':
|
|
342
363
|
d.noColorize = true;
|
|
343
364
|
break;
|
|
365
|
+
case 'no-cities':
|
|
366
|
+
d.noCities = true;
|
|
367
|
+
break;
|
|
344
368
|
case 'no-cluster-pois':
|
|
345
369
|
d.noClusterPois = true;
|
|
346
370
|
break;
|
|
@@ -376,7 +400,7 @@ export function parseMap(content: string): ParsedMap {
|
|
|
376
400
|
line: number
|
|
377
401
|
): void {
|
|
378
402
|
const { text: clean, isDefault } = stripDefaultModifier(text);
|
|
379
|
-
const { label, color } = extractColor(clean,
|
|
403
|
+
const { label, color } = extractColor(clean, palette, diagnostics, line);
|
|
380
404
|
if (!color) {
|
|
381
405
|
pushError(line, `Expected 'Value color' in tag group '${group.name}'`);
|
|
382
406
|
return;
|
|
@@ -507,7 +531,8 @@ export function parseMap(content: string): ParsedMap {
|
|
|
507
531
|
|
|
508
532
|
/** Parse one route body line into a leg: `[-label->] <destination> [keys]`.
|
|
509
533
|
* The arrow (if any) gives the leg label + shape; `value:` is leg thickness;
|
|
510
|
-
* a tag
|
|
534
|
+
* a tag colours the LINE (§24B.6); `label:`/`as` name the destination stop.
|
|
535
|
+
* Bare `<dest>` = plain leg. */
|
|
511
536
|
function parseLeg(
|
|
512
537
|
trimmed: string,
|
|
513
538
|
line: number,
|
|
@@ -549,7 +574,7 @@ export function parseMap(content: string): ParsedMap {
|
|
|
549
574
|
dest: pos,
|
|
550
575
|
...(split.alias !== undefined && { destAlias: split.alias }),
|
|
551
576
|
...(destLabel !== undefined && { destLabel }),
|
|
552
|
-
|
|
577
|
+
tags, // colour the LINE (§24B.6); stop tags go on the poi line
|
|
553
578
|
lineNumber: line,
|
|
554
579
|
};
|
|
555
580
|
}
|
|
@@ -572,13 +597,18 @@ export function parseMap(content: string): ParsedMap {
|
|
|
572
597
|
else links.push(classifyArrow(parts[k]!, line));
|
|
573
598
|
}
|
|
574
599
|
// Trailing metadata rides on the final endpoint only (R5), and attaches to
|
|
575
|
-
// the FINAL leg only — not broadcast to every leg of a chain (#7).
|
|
600
|
+
// the FINAL leg only — not broadcast to every leg of a chain (#7). A tag on
|
|
601
|
+
// the line colours the LINE (§24B.6), so peel tags out of the meta here.
|
|
576
602
|
const lastSplit = splitNameAndMeta(
|
|
577
603
|
endpoints[endpoints.length - 1]!,
|
|
578
604
|
registry(),
|
|
579
605
|
aliasMap
|
|
580
606
|
);
|
|
581
607
|
endpoints[endpoints.length - 1] = lastSplit.name;
|
|
608
|
+
const { tags: lastTags, meta: lastMeta } = partitionMeta(
|
|
609
|
+
lastSplit.meta,
|
|
610
|
+
tagGroupNames()
|
|
611
|
+
);
|
|
582
612
|
for (let k = 0; k < links.length; k++) {
|
|
583
613
|
const from = endpoints[k]!;
|
|
584
614
|
const to = endpoints[k + 1]!;
|
|
@@ -587,7 +617,8 @@ export function parseMap(content: string): ParsedMap {
|
|
|
587
617
|
continue;
|
|
588
618
|
}
|
|
589
619
|
const isLast = k === links.length - 1;
|
|
590
|
-
const meta = isLast ?
|
|
620
|
+
const meta = isLast ? lastMeta : {};
|
|
621
|
+
const tags = isLast ? lastTags : {};
|
|
591
622
|
// Edge shape comes only from the arrow token (surface parsing removed).
|
|
592
623
|
const style: 'straight' | 'arc' =
|
|
593
624
|
links[k]!.style === 'arc' ? 'arc' : 'straight';
|
|
@@ -598,6 +629,7 @@ export function parseMap(content: string): ParsedMap {
|
|
|
598
629
|
directed: links[k]!.directed,
|
|
599
630
|
style,
|
|
600
631
|
meta,
|
|
632
|
+
tags,
|
|
601
633
|
lineNumber: line,
|
|
602
634
|
});
|
|
603
635
|
}
|
|
@@ -608,24 +640,21 @@ export function parseMap(content: string): ParsedMap {
|
|
|
608
640
|
line: number
|
|
609
641
|
): { label?: string; directed: boolean; style: 'straight' | 'arc' } {
|
|
610
642
|
if (tok === '--') return { directed: false, style: 'straight' };
|
|
643
|
+
if (tok === '~~') return { directed: false, style: 'arc' };
|
|
611
644
|
if (tok === '->') return { directed: true, style: 'straight' };
|
|
612
645
|
if (tok === '~>') return { directed: true, style: 'arc' };
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
};
|
|
621
|
-
}
|
|
622
|
-
// directed labeled `-…->`
|
|
623
|
-
const lbl = parseInArrowLabel(tok.slice(1, -2), line);
|
|
646
|
+
// Labeled form: arrowhead iff it ends in `>`, arc iff it starts with `~`.
|
|
647
|
+
// The label sits between the delimiters — drop 2 trailing chars for the
|
|
648
|
+
// directed `…->`/`…~>`, 1 for the undirected `…-`/`…~`.
|
|
649
|
+
const directed = tok.endsWith('>');
|
|
650
|
+
const style: 'straight' | 'arc' = tok.startsWith('~') ? 'arc' : 'straight';
|
|
651
|
+
const inner = directed ? tok.slice(1, -2) : tok.slice(1, -1);
|
|
652
|
+
const lbl = parseInArrowLabel(inner, line);
|
|
624
653
|
lbl.diagnostics.forEach((d) => diagnostics.push(d));
|
|
625
654
|
return {
|
|
626
655
|
...(lbl.label !== undefined && { label: lbl.label }),
|
|
627
|
-
directed
|
|
628
|
-
style
|
|
656
|
+
directed,
|
|
657
|
+
style,
|
|
629
658
|
};
|
|
630
659
|
}
|
|
631
660
|
|