@diagrammo/dgmo 0.22.0 → 0.24.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 (51) hide show
  1. package/dist/advanced.cjs +372 -103
  2. package/dist/advanced.d.cts +52 -19
  3. package/dist/advanced.d.ts +52 -19
  4. package/dist/advanced.js +372 -103
  5. package/dist/auto.cjs +370 -97
  6. package/dist/auto.js +117 -117
  7. package/dist/auto.mjs +370 -97
  8. package/dist/cli.cjs +151 -151
  9. package/dist/editor.cjs +3 -0
  10. package/dist/editor.js +3 -0
  11. package/dist/highlight.cjs +3 -0
  12. package/dist/highlight.js +3 -0
  13. package/dist/index.cjs +498 -96
  14. package/dist/index.d.cts +37 -1
  15. package/dist/index.d.ts +37 -1
  16. package/dist/index.js +496 -96
  17. package/dist/internal.cjs +372 -103
  18. package/dist/internal.d.cts +52 -19
  19. package/dist/internal.d.ts +52 -19
  20. package/dist/internal.js +372 -103
  21. package/dist/map-data/PROVENANCE.json +1 -1
  22. package/dist/map-data/gazetteer.json +1 -1
  23. package/dist/map-data/mountain-ranges.json +1 -1
  24. package/dist/map-data/water-bodies.json +1 -1
  25. package/dist/map-data/world-coarse.json +1 -1
  26. package/dist/map-data/world-detail.json +1 -1
  27. package/docs/language-reference.md +38 -2
  28. package/gallery/fixtures/boxes-and-lines.dgmo +6 -4
  29. package/package.json +1 -1
  30. package/src/boxes-and-lines/parser.ts +39 -0
  31. package/src/boxes-and-lines/renderer.ts +219 -14
  32. package/src/boxes-and-lines/types.ts +9 -0
  33. package/src/completion.ts +4 -5
  34. package/src/d3.ts +26 -6
  35. package/src/editor/keywords.ts +3 -0
  36. package/src/index.ts +8 -0
  37. package/src/map/data/PROVENANCE.json +1 -1
  38. package/src/map/data/README.md +6 -0
  39. package/src/map/data/gazetteer.json +1 -1
  40. package/src/map/data/mountain-ranges.json +1 -1
  41. package/src/map/data/water-bodies.json +1 -1
  42. package/src/map/data/world-coarse.json +1 -1
  43. package/src/map/data/world-detail.json +1 -1
  44. package/src/map/dimensions.ts +21 -5
  45. package/src/map/layout.ts +167 -63
  46. package/src/map/legend-band.ts +99 -0
  47. package/src/map/renderer.ts +105 -32
  48. package/src/map/resolver.ts +43 -1
  49. package/src/map/types.ts +20 -0
  50. package/src/utils/reserved-key-registry.ts +5 -3
  51. package/src/utils/svg-embed.ts +193 -0
@@ -236,6 +236,28 @@ interface ParsedMap {
236
236
  readonly diagnostics: readonly DgmoError[];
237
237
  readonly error: string | null;
238
238
  }
239
+ /** Legend descriptor for a rendered map (a layout-stage output, re-exported from
240
+ * `layout.ts`). It lives here so the `legend-band` helper can consume it without
241
+ * importing `layout` — `layout` already value-imports `mapLegendBand`, so the
242
+ * reverse type import would form a layout↔legend-band cycle. */
243
+ interface MapLayoutLegend {
244
+ readonly tagGroups: ReadonlyArray<{
245
+ name: string;
246
+ entries: ReadonlyArray<{
247
+ value: string;
248
+ color: string;
249
+ }>;
250
+ }>;
251
+ readonly activeGroup: string | null;
252
+ readonly ramp?: {
253
+ metric?: string;
254
+ min: number;
255
+ max: number;
256
+ hue: string;
257
+ /** Low end of the ramp gradient (the land colour the fills blend from). */
258
+ base: string;
259
+ };
260
+ }
239
261
 
240
262
  /** A TopoJSON topology (world-coarse/world-detail keyed by ISO 3166-1 alpha-2;
241
263
  * us-states keyed by ISO 3166-2). Geometry feature `id` is the ISO code;
@@ -1568,6 +1590,7 @@ declare function renderForExport(content: string, theme: 'light' | 'dark' | 'tra
1568
1590
  tagGroup?: string;
1569
1591
  exportMode?: boolean;
1570
1592
  mapData?: MapData;
1593
+ mapAspect?: number;
1571
1594
  }): Promise<string>;
1572
1595
 
1573
1596
  /**
@@ -2500,6 +2523,9 @@ interface BLNode {
2500
2523
  readonly lineNumber: number;
2501
2524
  readonly metadata: Readonly<Record<string, string>>;
2502
2525
  readonly description?: readonly string[];
2526
+ /** Numeric measure lifted from `value: X` metadata (mirror of map's
2527
+ * `region.value`). Drives the value ramp / choropleth tinting. */
2528
+ readonly value?: number;
2503
2529
  }
2504
2530
  interface BLEdge {
2505
2531
  readonly source: string;
@@ -2527,6 +2553,12 @@ interface ParsedBoxesAndLines {
2527
2553
  readonly options: Readonly<Record<string, string>>;
2528
2554
  readonly initialHiddenTagValues: ReadonlyMap<string, ReadonlySet<string>>;
2529
2555
  readonly direction: 'LR' | 'TB';
2556
+ /** `box-metric <label> [color]` — names the value-ramp dimension and
2557
+ * optionally sets its hue. Mirror of map's `region-metric`. */
2558
+ readonly boxMetric?: string;
2559
+ readonly boxMetricColor?: string;
2560
+ /** `show-values` — print each box's numeric value as text (opt-in). */
2561
+ readonly showValues?: boolean;
2530
2562
  readonly diagnostics: readonly DgmoError[];
2531
2563
  readonly error: string | null;
2532
2564
  }
@@ -4672,6 +4704,14 @@ interface MapLayoutRegion {
4672
4704
  /** The region's tag values keyed by group (lowercased) — emitted as
4673
4705
  * `data-tag-<group>` so the app can highlight on legend-entry hover. */
4674
4706
  readonly tags?: Readonly<Record<string, string>>;
4707
+ /** Area-weighted screen centroid (px) of the DRAWN geometry — emitted as
4708
+ * `data-label-x`/`data-label-y` so the app can anchor the hover label here
4709
+ * instead of the path's bounding-box centre. The bbox centre breaks for
4710
+ * antimeridian crossers (Russia's wrapped Chukotka sliver pins the box's left
4711
+ * edge to the far side of the map, dropping the centre into the Atlantic); the
4712
+ * area-weighted centroid stays on the body. Honours WORLD_LABEL_ANCHORS. */
4713
+ readonly labelX?: number;
4714
+ readonly labelY?: number;
4675
4715
  }
4676
4716
  /** A framed inset "cutout" (albers-usa AK/HI), in screen px. The frame is a
4677
4717
  * quad whose TOP edge is angled to ride just under the conus southern coast,
@@ -4822,24 +4862,7 @@ interface PlacedLabel {
4822
4862
  readonly clusterMember?: string;
4823
4863
  readonly lineNumber: number;
4824
4864
  }
4825
- interface MapLayoutLegend {
4826
- readonly tagGroups: ReadonlyArray<{
4827
- name: string;
4828
- entries: ReadonlyArray<{
4829
- value: string;
4830
- color: string;
4831
- }>;
4832
- }>;
4833
- readonly activeGroup: string | null;
4834
- readonly ramp?: {
4835
- metric?: string;
4836
- min: number;
4837
- max: number;
4838
- hue: string;
4839
- /** Low end of the ramp gradient (the land colour the fills blend from). */
4840
- base: string;
4841
- };
4842
- }
4865
+
4843
4866
  /** A drawn river centerline — an open stroked path (no fill). */
4844
4867
  interface MapLayoutRiver {
4845
4868
  readonly d: string;
@@ -4938,6 +4961,10 @@ interface LayoutOptions {
4938
4961
  * canvas away from the content aspect, so the off-aspect canvas doesn't
4939
4962
  * re-distort. The in-app preview pane leaves this unset (keeps stretch-fill). */
4940
4963
  readonly preferContain?: boolean;
4964
+ /** Which legend variant gets drawn — `'export'` shows only the active group,
4965
+ * `'preview'` keeps inactive pills. Used to size the reserved legend band so
4966
+ * the projected land starts below the legend. Defaults to `'preview'`. */
4967
+ readonly legendMode?: LegendMode;
4941
4968
  }
4942
4969
  interface Size {
4943
4970
  readonly width: number;
@@ -4990,7 +5017,13 @@ interface MapExportDimensions {
4990
5017
  readonly height: number;
4991
5018
  readonly preferContain: boolean;
4992
5019
  }
4993
- declare function mapExportDimensions(resolved: ResolvedMap, data: MapData, baseWidth?: number): MapExportDimensions;
5020
+ declare function mapExportDimensions(resolved: ResolvedMap, data: MapData, baseWidth?: number,
5021
+ /** WYSIWYG override (app export): the live preview pane's displayed aspect
5022
+ * (width / height). When provided, the canvas adopts it verbatim and
5023
+ * stretch-fills (no clamp, no contain) so the PNG matches exactly what's on
5024
+ * screen. Omitted by every headless consumer (CLI / MCP / SSG / Obsidian),
5025
+ * which keep the intrinsic-aspect sizing below. */
5026
+ aspectOverride?: number): MapExportDimensions;
4994
5027
 
4995
5028
  /** Nearest gazetteer city to a point: the real haversine distance, plus the
4996
5029
  * canonical name + ISO + (US-only) subdivision for token shaping. `lon`/`lat`
@@ -236,6 +236,28 @@ interface ParsedMap {
236
236
  readonly diagnostics: readonly DgmoError[];
237
237
  readonly error: string | null;
238
238
  }
239
+ /** Legend descriptor for a rendered map (a layout-stage output, re-exported from
240
+ * `layout.ts`). It lives here so the `legend-band` helper can consume it without
241
+ * importing `layout` — `layout` already value-imports `mapLegendBand`, so the
242
+ * reverse type import would form a layout↔legend-band cycle. */
243
+ interface MapLayoutLegend {
244
+ readonly tagGroups: ReadonlyArray<{
245
+ name: string;
246
+ entries: ReadonlyArray<{
247
+ value: string;
248
+ color: string;
249
+ }>;
250
+ }>;
251
+ readonly activeGroup: string | null;
252
+ readonly ramp?: {
253
+ metric?: string;
254
+ min: number;
255
+ max: number;
256
+ hue: string;
257
+ /** Low end of the ramp gradient (the land colour the fills blend from). */
258
+ base: string;
259
+ };
260
+ }
239
261
 
240
262
  /** A TopoJSON topology (world-coarse/world-detail keyed by ISO 3166-1 alpha-2;
241
263
  * us-states keyed by ISO 3166-2). Geometry feature `id` is the ISO code;
@@ -1568,6 +1590,7 @@ declare function renderForExport(content: string, theme: 'light' | 'dark' | 'tra
1568
1590
  tagGroup?: string;
1569
1591
  exportMode?: boolean;
1570
1592
  mapData?: MapData;
1593
+ mapAspect?: number;
1571
1594
  }): Promise<string>;
1572
1595
 
1573
1596
  /**
@@ -2500,6 +2523,9 @@ interface BLNode {
2500
2523
  readonly lineNumber: number;
2501
2524
  readonly metadata: Readonly<Record<string, string>>;
2502
2525
  readonly description?: readonly string[];
2526
+ /** Numeric measure lifted from `value: X` metadata (mirror of map's
2527
+ * `region.value`). Drives the value ramp / choropleth tinting. */
2528
+ readonly value?: number;
2503
2529
  }
2504
2530
  interface BLEdge {
2505
2531
  readonly source: string;
@@ -2527,6 +2553,12 @@ interface ParsedBoxesAndLines {
2527
2553
  readonly options: Readonly<Record<string, string>>;
2528
2554
  readonly initialHiddenTagValues: ReadonlyMap<string, ReadonlySet<string>>;
2529
2555
  readonly direction: 'LR' | 'TB';
2556
+ /** `box-metric <label> [color]` — names the value-ramp dimension and
2557
+ * optionally sets its hue. Mirror of map's `region-metric`. */
2558
+ readonly boxMetric?: string;
2559
+ readonly boxMetricColor?: string;
2560
+ /** `show-values` — print each box's numeric value as text (opt-in). */
2561
+ readonly showValues?: boolean;
2530
2562
  readonly diagnostics: readonly DgmoError[];
2531
2563
  readonly error: string | null;
2532
2564
  }
@@ -4672,6 +4704,14 @@ interface MapLayoutRegion {
4672
4704
  /** The region's tag values keyed by group (lowercased) — emitted as
4673
4705
  * `data-tag-<group>` so the app can highlight on legend-entry hover. */
4674
4706
  readonly tags?: Readonly<Record<string, string>>;
4707
+ /** Area-weighted screen centroid (px) of the DRAWN geometry — emitted as
4708
+ * `data-label-x`/`data-label-y` so the app can anchor the hover label here
4709
+ * instead of the path's bounding-box centre. The bbox centre breaks for
4710
+ * antimeridian crossers (Russia's wrapped Chukotka sliver pins the box's left
4711
+ * edge to the far side of the map, dropping the centre into the Atlantic); the
4712
+ * area-weighted centroid stays on the body. Honours WORLD_LABEL_ANCHORS. */
4713
+ readonly labelX?: number;
4714
+ readonly labelY?: number;
4675
4715
  }
4676
4716
  /** A framed inset "cutout" (albers-usa AK/HI), in screen px. The frame is a
4677
4717
  * quad whose TOP edge is angled to ride just under the conus southern coast,
@@ -4822,24 +4862,7 @@ interface PlacedLabel {
4822
4862
  readonly clusterMember?: string;
4823
4863
  readonly lineNumber: number;
4824
4864
  }
4825
- interface MapLayoutLegend {
4826
- readonly tagGroups: ReadonlyArray<{
4827
- name: string;
4828
- entries: ReadonlyArray<{
4829
- value: string;
4830
- color: string;
4831
- }>;
4832
- }>;
4833
- readonly activeGroup: string | null;
4834
- readonly ramp?: {
4835
- metric?: string;
4836
- min: number;
4837
- max: number;
4838
- hue: string;
4839
- /** Low end of the ramp gradient (the land colour the fills blend from). */
4840
- base: string;
4841
- };
4842
- }
4865
+
4843
4866
  /** A drawn river centerline — an open stroked path (no fill). */
4844
4867
  interface MapLayoutRiver {
4845
4868
  readonly d: string;
@@ -4938,6 +4961,10 @@ interface LayoutOptions {
4938
4961
  * canvas away from the content aspect, so the off-aspect canvas doesn't
4939
4962
  * re-distort. The in-app preview pane leaves this unset (keeps stretch-fill). */
4940
4963
  readonly preferContain?: boolean;
4964
+ /** Which legend variant gets drawn — `'export'` shows only the active group,
4965
+ * `'preview'` keeps inactive pills. Used to size the reserved legend band so
4966
+ * the projected land starts below the legend. Defaults to `'preview'`. */
4967
+ readonly legendMode?: LegendMode;
4941
4968
  }
4942
4969
  interface Size {
4943
4970
  readonly width: number;
@@ -4990,7 +5017,13 @@ interface MapExportDimensions {
4990
5017
  readonly height: number;
4991
5018
  readonly preferContain: boolean;
4992
5019
  }
4993
- declare function mapExportDimensions(resolved: ResolvedMap, data: MapData, baseWidth?: number): MapExportDimensions;
5020
+ declare function mapExportDimensions(resolved: ResolvedMap, data: MapData, baseWidth?: number,
5021
+ /** WYSIWYG override (app export): the live preview pane's displayed aspect
5022
+ * (width / height). When provided, the canvas adopts it verbatim and
5023
+ * stretch-fills (no clamp, no contain) so the PNG matches exactly what's on
5024
+ * screen. Omitted by every headless consumer (CLI / MCP / SSG / Obsidian),
5025
+ * which keep the intrinsic-aspect sizing below. */
5026
+ aspectOverride?: number): MapExportDimensions;
4994
5027
 
4995
5028
  /** Nearest gazetteer city to a point: the real haversine distance, plus the
4996
5029
  * canonical name + ISO + (US-only) subdivision for token shaping. `lon`/`lat`