@diagrammo/dgmo 0.21.1 → 0.23.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 (87) hide show
  1. package/README.md +16 -6
  2. package/dist/advanced.cjs +2230 -503
  3. package/dist/advanced.d.cts +5731 -0
  4. package/dist/advanced.d.ts +5731 -0
  5. package/dist/advanced.js +2226 -503
  6. package/dist/auto.cjs +2272 -479
  7. package/dist/auto.d.cts +39 -0
  8. package/dist/auto.d.ts +39 -0
  9. package/dist/auto.js +124 -124
  10. package/dist/auto.mjs +2274 -480
  11. package/dist/cli.cjs +170 -170
  12. package/dist/editor.cjs +16 -16
  13. package/dist/editor.js +16 -16
  14. package/dist/highlight.cjs +18 -13
  15. package/dist/highlight.js +18 -13
  16. package/dist/index.cjs +2253 -465
  17. package/dist/index.d.cts +339 -0
  18. package/dist/index.d.ts +339 -0
  19. package/dist/index.js +2255 -466
  20. package/dist/internal.cjs +2230 -503
  21. package/dist/internal.d.cts +5731 -0
  22. package/dist/internal.d.ts +5731 -0
  23. package/dist/internal.js +2226 -503
  24. package/dist/map-data/PROVENANCE.json +1 -1
  25. package/dist/map-data/gazetteer.json +1 -1
  26. package/dist/map-data/mountain-ranges.json +1 -1
  27. package/dist/map-data/water-bodies.json +1 -0
  28. package/dist/map-data/world-coarse.json +1 -1
  29. package/dist/map-data/world-detail.json +1 -1
  30. package/docs/language-reference.md +55 -9
  31. package/gallery/fixtures/boxes-and-lines.dgmo +6 -4
  32. package/gallery/fixtures/map-categorical-world.dgmo +16 -0
  33. package/gallery/fixtures/map-categorical.dgmo +0 -1
  34. package/gallery/fixtures/map-choropleth.dgmo +0 -1
  35. package/gallery/fixtures/map-coastline.dgmo +7 -0
  36. package/gallery/fixtures/map-colorize.dgmo +11 -0
  37. package/gallery/fixtures/map-direct-color.dgmo +0 -1
  38. package/gallery/fixtures/map-reference-world.dgmo +11 -0
  39. package/gallery/fixtures/map-region-scope.dgmo +0 -3
  40. package/gallery/fixtures/map-route.dgmo +0 -1
  41. package/package.json +1 -1
  42. package/src/advanced.ts +12 -1
  43. package/src/boxes-and-lines/parser.ts +39 -0
  44. package/src/boxes-and-lines/renderer.ts +205 -20
  45. package/src/boxes-and-lines/types.ts +9 -0
  46. package/src/cli.ts +1 -1
  47. package/src/completion.ts +36 -30
  48. package/src/cycle/renderer.ts +14 -1
  49. package/src/d3.ts +20 -6
  50. package/src/editor/highlight-api.ts +4 -0
  51. package/src/editor/keywords.ts +16 -16
  52. package/src/infra/renderer.ts +35 -7
  53. package/src/map/colorize.ts +54 -0
  54. package/src/map/context-labels.ts +429 -0
  55. package/src/map/data/PROVENANCE.json +1 -1
  56. package/src/map/data/README.md +6 -0
  57. package/src/map/data/gazetteer.json +1 -1
  58. package/src/map/data/mountain-ranges.json +1 -1
  59. package/src/map/data/types.ts +34 -0
  60. package/src/map/data/water-bodies.json +1 -0
  61. package/src/map/data/world-coarse.json +1 -1
  62. package/src/map/data/world-detail.json +1 -1
  63. package/src/map/dimensions.ts +117 -0
  64. package/src/map/geo-query.ts +21 -3
  65. package/src/map/geo.ts +47 -1
  66. package/src/map/layout.ts +1408 -266
  67. package/src/map/load-data.ts +10 -2
  68. package/src/map/parser.ts +42 -116
  69. package/src/map/renderer.ts +604 -14
  70. package/src/map/resolved-types.ts +16 -2
  71. package/src/map/resolver.ts +208 -59
  72. package/src/map/types.ts +30 -32
  73. package/src/mindmap/renderer.ts +10 -1
  74. package/src/palettes/atlas.ts +77 -0
  75. package/src/palettes/blueprint.ts +73 -0
  76. package/src/palettes/color-utils.ts +58 -1
  77. package/src/palettes/index.ts +12 -3
  78. package/src/palettes/slate.ts +73 -0
  79. package/src/palettes/tidewater.ts +73 -0
  80. package/src/render.ts +8 -1
  81. package/src/tech-radar/renderer.ts +3 -0
  82. package/src/tech-radar/types.ts +3 -0
  83. package/src/utils/d3-types.ts +5 -0
  84. package/src/utils/legend-layout.ts +21 -4
  85. package/src/utils/legend-types.ts +7 -0
  86. package/src/utils/reserved-key-registry.ts +8 -3
  87. package/src/palettes/bold.ts +0 -67
@@ -1469,12 +1469,47 @@ Indented shorthand also supports groups (place arrow directly after group header
1469
1469
  ### 13.6 Directives
1470
1470
 
1471
1471
  - `direction TB` — top-to-bottom layout (default: `LR`)
1472
+ - `box-metric <Label> [color]` — name a numeric value dimension (see §13.8); optional trailing color sets the ramp hue
1473
+ - `show-values` — print each box's numeric value as text (off by default)
1472
1474
 
1473
1475
  ### 13.7 Options
1474
1476
 
1475
1477
  - `active-tag GroupName` — set active tag group for coloring
1478
+ - `active-tag none` — suppress tag coloring
1479
+ - `active-tag <metric>` — make the value ramp the active dimension (see §13.8)
1476
1480
  - `hide team:Backend, team:Frontend` — hide nodes with matching tag values (colon syntax for tag:value)
1477
1481
 
1482
+ ### 13.8 Value metric (numeric ramp)
1483
+
1484
+ Boxes can carry a numeric measure that drives a continuous color ramp — a
1485
+ choropleth-style "value dimension" alongside the categorical tag groups.
1486
+
1487
+ ```
1488
+ boxes-and-lines Fleet Crews
1489
+ box-metric Crew blue
1490
+ show-values
1491
+
1492
+ Flagship value: 120
1493
+ Frigate value: 40
1494
+ Sloop value: 12
1495
+ Flagship -> Frigate
1496
+ Flagship -> Sloop
1497
+ ```
1498
+
1499
+ - `value: <number>` on any box records its measure (a reserved metadata key —
1500
+ lifted out, never rendered as a tag). Non-numeric values are an error.
1501
+ - `box-metric <Label> [color]` names the dimension and optionally sets the ramp
1502
+ hue (default: the palette's primary color).
1503
+ - The ramp anchors at `0` for all-non-negative data, else at the data minimum.
1504
+ - The value ramp is the resting-active dimension whenever any box has a
1505
+ `value:` (so value shading works in static export with no interaction).
1506
+ `active-tag <tag-group>` switches to a tag group; `active-tag none` suppresses
1507
+ tinting; `active-tag <metric>` forces the value ramp. On a name collision
1508
+ between a tag group and the metric label, the tag group wins.
1509
+ - When the value ramp is active, every box tints along the min→max ramp and the
1510
+ legend shows a gradient capsule; boxes without a `value:` get a neutral fill.
1511
+ - `show-values` additionally prints each box's number as text.
1512
+
1478
1513
  ---
1479
1514
 
1480
1515
  ## 15. Timeline Diagrams
@@ -2644,7 +2679,9 @@ Markers in cells are always **rendered in canonical alphabet order** (`R A C I`,
2644
2679
 
2645
2680
  Geographic concept maps: highlight/shade political subdivisions, drop points of interest (POIs), and connect them with routes or edges. For "share a concept" business maps, not cartography. Renders at a fixed, auto-fit position — no pan/zoom. Basemap and viewport are **inferred from the content you reference** — most maps need no directives. v1 boundaries: world countries + US states.
2646
2681
 
2647
- **How the map type is decided (inference):** the resolver takes the bounding box of everything referenced (valued/tagged regions + POIs + edge endpoints), pads it, and measures its span. Projection: `albers-usa` (US conic + AK/HI insets) when the map is US-only; else `equirectangular` snapped to the full Greenwich world when the span is world-scale (≥ ~90°); else `mercator` for a tight regional cluster; else `equirectangular`. The US-state mesh is added whenever you name a US state. Directives only matter to *override* this: `region us-states` forces the state mesh + US scoping (useful on a POI-only US map, redundant once you name a state); `projection …` forces the projection; **`region world` is currently inert** — world is already the default, so it changes nothing (the frame widens from a world-scale longitude span, not this directive).
2682
+ **The zero-config map is the good-looking map.** Type `map`, name some places, and you're done coastlines, mountain relief (on reference maps), region/POI labels, and orientation labels all render by default. There is no projection, scale, or label directive; the only knobs are the bare `no-*` opt-outs.
2683
+
2684
+ **How the map type is decided (inference):** the resolver takes the bounding box of everything referenced (valued/tagged regions + POIs + edge endpoints), pads it, and measures its span. Projection is **always inferred — never configured**: `albers-usa` (US conic + AK/HI insets) when the map is US-oriented; at world/multi-continent scale a **data** map (any region/POI carries `value:` or a tag) gets **Equal Earth** (equal-area — honest for thematic comparison) while a **dataless reference** map gets **natural-earth** (the prettier curved compromise); `mercator` for a tight regional or single-continent cluster. The US-state mesh is added whenever you name a US state (or the map is US-oriented).
2648
2685
 
2649
2686
  ### Declaration
2650
2687
 
@@ -2660,7 +2697,6 @@ A subdivision name on its own line with a `value:` fills with a single-hue tint
2660
2697
 
2661
2698
  ```
2662
2699
  map US Sales
2663
- region us-states
2664
2700
  region-metric Sales ($M)
2665
2701
 
2666
2702
  California value: 92
@@ -2668,7 +2704,8 @@ Texas value: 78
2668
2704
  Florida value: 51
2669
2705
  ```
2670
2706
 
2671
- - `region-metric <label>` labels the ramp in the legend; a trailing color on it sets the ramp hue (`region-metric Sales ($M) blue` → blue ramp, default red). `scale <min> <max>` overrides the auto anchors.
2707
+ - `region-metric <label>` labels the ramp in the legend; a trailing color on it sets the ramp hue (`region-metric Sales ($M) blue` → blue ramp, default red).
2708
+ - The ramp **auto-fits**: all-non-negative data anchors the low end at **0** (shared baseline); mixed-sign data fits data-min→data-max. There is no `scale` directive.
2672
2709
  - A subdivision with no `value:`/tag renders as the neutral base.
2673
2710
 
2674
2711
  ### Region fill — categorical (tags)
@@ -2677,7 +2714,6 @@ Uses the universal tag model (§1.3): declare a `tag` group and apply its alias
2677
2714
 
2678
2715
  ```
2679
2716
  map Global Presence
2680
- region world
2681
2717
 
2682
2718
  tag Market as m
2683
2719
  HQ blue
@@ -2734,18 +2770,28 @@ dcw # hub/star — indented edges share the source
2734
2770
  -> office-west
2735
2771
  ```
2736
2772
 
2737
- `~>` curves a single edge. No geographic path-finding — legs are straight or arced.
2773
+ `~>` curves a single edge. There is no geographic path-finding and no `surface:` — legs are plain straight or arced geometry (`style: arc` to bow one) and may cross land.
2774
+
2775
+ ```
2776
+ map Caribbean Cruise
2777
+
2778
+ route Miami style: arc
2779
+ -weigh anchor-> Havana
2780
+ -> Kingston
2781
+ -> Cartagena
2782
+ ```
2738
2783
 
2739
2784
  ### Labels, legend & chrome
2740
2785
 
2741
- - Title is the declaration line; `subtitle` / `caption` are directives.
2786
+ - Title is the declaration line; `caption` (data-source attribution, travels with the exported PNG) is the only chrome directive. There is no `subtitle`.
2742
2787
  - Legend auto-composes below the title: the value ramp + `region-metric` and each tag group are **selectable colouring groups** (collapse/activate to flip the fill); POI size (`poi-metric`) and edge thickness (`flow-metric`) are self-evident from scale and carry no legend key in v1. `no-legend` suppresses all of it.
2743
- - `region-labels full | abbrev | off` (default `off`); `poi-labels off | auto | all` (default `auto`). Labels render **on the map** (export-safe), escalating inline → leader line → numbered pin in dense clusters; markers never move.
2788
+ - **Region and POI labels are on by default.** Region labels auto-fit **full abbrev hide** (a US-state 2-letter abbreviation is tried when the full name doesn't fit; other regions degrade full → hide); POI labels are collision-managed. Labels render **on the map** (export-safe), escalating inline → leader line → numbered pin in dense clusters; markers never move. A wide map in a narrow column (< ~480px) prefers abbreviations and drops reference relief, as if zoomed out.
2789
+ - **Cosmetic features are on by default**; the only switches are bare `no-*` opt-outs (no positive opt-in flag): `no-coastline`, `no-relief`, `no-context-labels`, `no-region-labels`, `no-poi-labels`, `no-legend`. A plain look = the four basemap flags together.
2744
2790
 
2745
2791
  ### Name resolution
2746
2792
 
2747
2793
  - Admin units use **ISO 3166** (geometry keyed by code, so "United States" / "USA" / "US" resolve alike); cities use **GeoNames** (alias/accent matching, population ranking, did-you-mean).
2748
- - `default-country` / `default-state <ISO>` scopes bare city resolution (inferred from content if unset).
2794
+ - `locale <ISO>` scopes bare city resolution to a country (`locale US`) or subdivision (`locale US-GA`) — inferred from content if unset.
2749
2795
  - A bare ambiguous, undeclared name → most-populous in scope (info note).
2750
2796
  - **Disambiguate once:** trailing ISO code at first declaration — `San Jose CR` (country) or `Portland US-OR` (subdivision). Thereafter reference the bare name. Two same-named cities → `as <alias>` each.
2751
2797
  - **Region fills disambiguate the country-vs-state collision** (`Georgia` = country `GE` or US state `US-GA`) by ISO code or name + scope — pick whichever reads best:
@@ -2756,7 +2802,7 @@ dcw # hub/star — indented edges share the source
2756
2802
 
2757
2803
  ### Directives & reserved keys
2758
2804
 
2759
- Directives (no colon): `region` (world | us-states), `projection` (equirectangular | natural-earth | albers-usa | mercator), `region-metric`, `poi-metric`, `flow-metric`, `scale`, `region-labels`, `poi-labels`, `default-country`, `default-state`, `active-tag`, `no-legend`, `subtitle`, `caption`. Reserved metadata keys (need colons): `value`, `label`, `style` (`value` = the one numeric channel: region shade / POI size / edge thickness). A bare US state postal code resolves to that state (`poi Portland OR` → Oregon; `CA` = California). Coordinates are positional (no `at:` key). Projection is auto-picked by extent span (world equirectangular, full Greenwich frame; US → albers-usa with Alaska/Hawaii insets; tight regional → mercator) unless overridden.
2805
+ The directive set is **12, all colon-free**: six naming intent the renderer can't infer `region-metric`, `poi-metric`, `flow-metric`, `locale`, `active-tag`, `caption` — and six `no-*` cosmetic opt-outs — `no-legend`, `no-coastline`, `no-relief`, `no-context-labels`, `no-region-labels`, `no-poi-labels`. There is **no** `projection`, `scale`, `subtitle`, `surface`, `region`, or label-enum directive, and cosmetics have no positive opt-in form. Reserved metadata keys (need colons): `value`, `label`, `style` (`value` = the one numeric channel: region shade / POI size / edge thickness); `surface:` is no longer recognized. A bare US state postal code resolves to that state (`poi Portland OR` → Oregon; `CA` = California). Coordinates are positional (no `at:` key). Projection is inferred from extent + whether the map carries data (US → albers-usa; world data → Equal Earth; world reference → natural-earth; regional → mercator) and cannot be overridden.
2760
2806
 
2761
2807
  ---
2762
2808
 
@@ -6,28 +6,30 @@ tag Priority p High red, Medium orange, Low gray
6
6
  active-tag Team
7
7
  hide priority:Low
8
8
 
9
+ box-metric Load orange
10
+
9
11
  direction LR
10
12
 
11
13
  // --- Services ---
12
- API Gateway t: Backend
14
+ API Gateway t: Backend, value: 850
13
15
  Main entry point for all requests
14
16
  Routes to **backend services**
15
17
  -routes-> UserService
16
18
  -routes-> ProductService
17
19
  -routes-> OrderService
18
20
 
19
- UserService t: Backend
21
+ UserService t: Backend, value: 430
20
22
  Handles auth and profiles
21
23
  Uses `JWT` tokens for sessions
22
24
  -reads-> UserDB
23
25
  -checks-> SessionCache
24
26
 
25
- ProductService t: Frontend, description: Product catalog and search
27
+ ProductService t: Frontend, value: 620, description: Product catalog and search
26
28
  Supports *full-text* search
27
29
  -queries-> ProductDB
28
30
  -invalidates-> ProductCache
29
31
 
30
- OrderService t: Backend
32
+ OrderService t: Backend, value: 290
31
33
  Order processing pipeline
32
34
  Validates inventory before commit
33
35
  -writes-> OrderDB
@@ -0,0 +1,16 @@
1
+ map Global Market Presence
2
+
3
+ tag Market as m
4
+ HQ blue
5
+ Region teal
6
+ Prospect orange
7
+ active-tag Market
8
+
9
+ United States m: HQ
10
+ Germany m: Region
11
+ Japan m: Region
12
+ Brazil m: Prospect
13
+ India m: Region
14
+ Australia m: Prospect
15
+ South Africa m: Prospect
16
+ Indonesia m: Prospect
@@ -1,5 +1,4 @@
1
1
  map Global Market Presence
2
- region world
3
2
 
4
3
  tag Market as m
5
4
  HQ blue
@@ -1,5 +1,4 @@
1
1
  map US Sales by State
2
- region us-states
3
2
  region-metric Sales ($M)
4
3
 
5
4
  California value: 92
@@ -0,0 +1,7 @@
1
+ map Smuggler's Run
2
+
3
+ poi Havana value: 90
4
+ poi Kingston value: 120
5
+
6
+ route Havana style: arc
7
+ -run the blockade-> Kingston
@@ -0,0 +1,11 @@
1
+ map Privateer's Atlas
2
+
3
+ // Regions named, no value: or tags → colorize is the inferred dress: every
4
+ // state/country gets a distinct pastel and no two neighbours share a hue
5
+ // (4-colour political look). The named states aren't special — the whole drawn
6
+ // mesh colours, so it reads as one chart. `no-colorize` would force green-land.
7
+ California
8
+ Texas
9
+ Florida
10
+ New York
11
+ Washington
@@ -1,5 +1,4 @@
1
1
  map Regional Focus
2
- region us-states
3
2
  region-metric Sales ($M) blue
4
3
 
5
4
  California value: 92
@@ -0,0 +1,11 @@
1
+ map World Reference
2
+
3
+ // A dataless reference map (regions named, no value: or tags) — so the
4
+ // zero-config basemap shows its full dress: coastline water-lines, mountain
5
+ // relief, and orientation labels, on a natural-earth projection.
6
+ United States
7
+ Brazil
8
+ Egypt
9
+ India
10
+ Japan
11
+ Australia
@@ -1,8 +1,5 @@
1
1
  map Region Scope Disambiguation
2
- region us-states
3
2
  region-metric Sales ($M)
4
- region-labels abbrev
5
- subtitle Pin a country/state name clash by ISO code (US-GA) or name + scope (Georgia US)
6
3
 
7
4
  California value: 92
8
5
  Texas value: 78
@@ -1,5 +1,4 @@
1
1
  map Caribbean Cruise
2
- projection mercator
3
2
 
4
3
  route Miami style: arc
5
4
  -weigh anchor-> Havana
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diagrammo/dgmo",
3
- "version": "0.21.1",
3
+ "version": "0.23.0",
4
4
  "description": "DGMO diagram markup language — parser, renderer, and color system",
5
5
  "license": "MIT",
6
6
  "repository": {
package/src/advanced.ts CHANGED
@@ -540,6 +540,14 @@ export type {
540
540
  MapLayoutLegend,
541
541
  } from './map/layout';
542
542
  export { renderMap, renderMapForExport } from './map/renderer';
543
+ // Content-aware export dimensions — derive the canvas height from a map's intrinsic
544
+ // projected aspect so exports/embeds match the content's natural shape (no vertical
545
+ // stretch). Used by the CLI/MCP/SSG export path and by Obsidian's DI render.
546
+ export {
547
+ mapContentAspect,
548
+ mapExportDimensions,
549
+ type MapExportDimensions,
550
+ } from './map/dimensions';
543
551
  // Map geo-query (step-5 coordinate/location inspector) — a SEPARATE entry from
544
552
  // the renderer; takes `MapData` by DI so it's browser-safe (never calls the
545
553
  // Node-only `loadMapData`).
@@ -734,7 +742,10 @@ export {
734
742
  gruvboxPalette,
735
743
  tokyoNightPalette,
736
744
  oneDarkPalette,
737
- boldPalette,
745
+ atlasPalette,
746
+ blueprintPalette,
747
+ slatePalette,
748
+ tidewaterPalette,
738
749
  draculaPalette,
739
750
  monokaiPalette,
740
751
  } from './palettes';
@@ -26,6 +26,7 @@ import {
26
26
  extractColor,
27
27
  parseFirstLine,
28
28
  OPTION_NOCOLON_RE,
29
+ peelTrailingColorName,
29
30
  splitNameAndMeta,
30
31
  tryParseSharedOption,
31
32
  warnUnknownMetaKeys,
@@ -297,6 +298,26 @@ export function parseBoxesAndLines(content: string): ParsedBoxesAndLines {
297
298
  continue;
298
299
  }
299
300
 
301
+ // box-metric / show-values directives — pre-content only (like
302
+ // active-tag). Explicit regex branches: a bare flag and a
303
+ // `key value` form won't both match the active-tag OPTION codepath.
304
+ if (!contentStarted) {
305
+ const metricMatch = trimmed.match(/^box-metric\s+(.+)$/i);
306
+ if (metricMatch) {
307
+ // Regex capture group present after successful match.
308
+ const { label, colorName } = peelTrailingColorName(
309
+ metricMatch[1]!.trim()
310
+ );
311
+ result.boxMetric = label;
312
+ if (colorName !== undefined) result.boxMetricColor = colorName;
313
+ continue;
314
+ }
315
+ if (/^show-values$/i.test(trimmed)) {
316
+ result.showValues = true;
317
+ continue;
318
+ }
319
+ }
320
+
300
321
  // active-tag directive
301
322
  if (!contentStarted) {
302
323
  const optMatch = trimmed.match(OPTION_NOCOLON_RE);
@@ -784,6 +805,23 @@ function parseNodeLine(
784
805
  delete metadata['description'];
785
806
  }
786
807
 
808
+ // Lift `value: X` out of metadata into a typed numeric field (mirror of the
809
+ // map parser). Validate finite-numeric; delete from metadata so it never
810
+ // becomes a `data-tag-value` attribute.
811
+ let value: number | undefined;
812
+ if (metadata['value'] !== undefined) {
813
+ const raw = metadata['value'];
814
+ const num = Number(raw);
815
+ if (Number.isFinite(num)) {
816
+ value = num;
817
+ } else {
818
+ diagnostics.push(
819
+ makeDgmoError(lineNum, `value must be a number (got "${raw}")`, 'error')
820
+ );
821
+ }
822
+ delete metadata['value'];
823
+ }
824
+
787
825
  // TD-18 alias is now peeled by splitNameAndMeta — re-register if set.
788
826
  if (split.alias) {
789
827
  nameAliasMap?.set(normalizeName(split.alias), label);
@@ -796,6 +834,7 @@ function parseNodeLine(
796
834
  lineNumber: lineNum,
797
835
  metadata,
798
836
  ...(description !== undefined && { description }),
837
+ ...(value !== undefined && { value }),
799
838
  };
800
839
  }
801
840