@diagrammo/dgmo 0.47.0 → 0.48.1

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 (345) hide show
  1. package/dist/advanced.js +11 -11
  2. package/dist/auto.js +16 -16
  3. package/dist/auto.mjs +41 -12
  4. package/dist/block.js +4 -4
  5. package/dist/{chunk-FNB3PNGF.js → chunk-7DTWEFUE.js} +3 -3
  6. package/dist/{chunk-2DXMZRWJ.js → chunk-B65G5DNL.js} +8 -1
  7. package/dist/{chunk-RZCF2VVM.js → chunk-B7JUCQUA.js} +3 -1
  8. package/dist/{chunk-DU7W62N5.js → chunk-FANX6UJR.js} +3 -3
  9. package/dist/{chunk-6FZYCKXB.js → chunk-HSH73DP6.js} +2 -2
  10. package/dist/{chunk-P4RH4OSP.js → chunk-ILKORZ3H.js} +2 -2
  11. package/dist/{chunk-Y5QGVTVC.js → chunk-JTSMEYIZ.js} +7 -3
  12. package/dist/{chunk-RCERWOJR.js → chunk-ODZVHU3R.js} +1 -2
  13. package/dist/{chunk-DZAQBW35.js → chunk-SGZYXELT.js} +3 -7
  14. package/dist/{chunk-CUVHQHZ7.js → chunk-THXCFRTU.js} +3 -3
  15. package/dist/{chunk-IH6ZMVQ5.js → chunk-UC7TFHUM.js} +29 -11
  16. package/dist/{chunk-EMS2SK26.js → chunk-ZBWMSD5N.js} +3 -1
  17. package/dist/cli.cjs +15 -15
  18. package/dist/{dgmo-router-DZCIDUO5.js → dgmo-router-X35VLZLM.js} +3 -3
  19. package/dist/element.js +16 -16
  20. package/dist/element.mjs +41 -12
  21. package/dist/{flowchart-renderer-ZAEOL4DX.js → flowchart-renderer-SNDSII4D.js} +2 -2
  22. package/dist/index.d.ts +4 -2
  23. package/dist/index.js +4 -4
  24. package/dist/{parser-FUSKFGZN.js → parser-2EWECDSA.js} +2 -2
  25. package/dist/{renderer-UWA5XS74.js → renderer-4JHRUBE6.js} +3 -3
  26. package/dist/{renderer-WZRREQ2P.js → renderer-5MYBMBYO.js} +2 -2
  27. package/dist/{renderer-TOCOVLHS.js → renderer-B2OMQIQG.js} +3 -3
  28. package/dist/{renderer-2XQQQ6QR.js → renderer-N43WR5GV.js} +3 -3
  29. package/dist/{renderer-T7YKC5VP.js → renderer-ZRNG54CW.js} +3 -3
  30. package/dist/{state-renderer-RFYHSP4K.js → state-renderer-B4DQBM6M.js} +2 -2
  31. package/package.json +23 -71
  32. package/dist/advanced.cjs +0 -71648
  33. package/dist/advanced.d.cts +0 -5719
  34. package/dist/auto.cjs +0 -70648
  35. package/dist/auto.d.cts +0 -54
  36. package/dist/block.cjs +0 -70208
  37. package/dist/block.d.cts +0 -115
  38. package/dist/editor.cjs +0 -526
  39. package/dist/editor.d.cts +0 -26
  40. package/dist/element.cjs +0 -70530
  41. package/dist/element.d.cts +0 -62
  42. package/dist/highlight.cjs +0 -852
  43. package/dist/highlight.d.cts +0 -49
  44. package/dist/index.cjs +0 -70491
  45. package/dist/index.d.cts +0 -160
  46. package/dist/pert.cjs +0 -325
  47. package/dist/pert.d.cts +0 -559
  48. package/dist/themes-1-CuKpeH.d.cts +0 -908
  49. package/src/advanced.ts +0 -873
  50. package/src/arc/parser.ts +0 -15
  51. package/src/arc/renderer.ts +0 -633
  52. package/src/auto/index.ts +0 -621
  53. package/src/auto/shared.ts +0 -370
  54. package/src/auto/styles.ts +0 -73
  55. package/src/block/layout.ts +0 -198
  56. package/src/block/parser.ts +0 -427
  57. package/src/block/renderer.ts +0 -484
  58. package/src/block/types.ts +0 -67
  59. package/src/boxes-and-lines/collapse.ts +0 -96
  60. package/src/boxes-and-lines/focus.ts +0 -257
  61. package/src/boxes-and-lines/label-placement.ts +0 -339
  62. package/src/boxes-and-lines/layout-grouped.ts +0 -912
  63. package/src/boxes-and-lines/layout-layered.ts +0 -722
  64. package/src/boxes-and-lines/layout-search.ts +0 -1678
  65. package/src/boxes-and-lines/layout.ts +0 -398
  66. package/src/boxes-and-lines/parser.ts +0 -1181
  67. package/src/boxes-and-lines/renderer.ts +0 -1465
  68. package/src/boxes-and-lines/types.ts +0 -66
  69. package/src/c4/layout.ts +0 -2441
  70. package/src/c4/parser.ts +0 -1158
  71. package/src/c4/renderer.ts +0 -2008
  72. package/src/c4/types.ts +0 -89
  73. package/src/chart-type-registry.ts +0 -529
  74. package/src/chart-types.ts +0 -225
  75. package/src/chart.ts +0 -685
  76. package/src/charts-d3/bar.ts +0 -338
  77. package/src/charts-d3/chord.ts +0 -140
  78. package/src/charts-d3/function.ts +0 -147
  79. package/src/charts-d3/funnel.ts +0 -104
  80. package/src/charts-d3/heatmap.ts +0 -145
  81. package/src/charts-d3/index.ts +0 -337
  82. package/src/charts-d3/interactions.ts +0 -477
  83. package/src/charts-d3/line.ts +0 -344
  84. package/src/charts-d3/mount.ts +0 -151
  85. package/src/charts-d3/pie.ts +0 -117
  86. package/src/charts-d3/polar.ts +0 -89
  87. package/src/charts-d3/radar.ts +0 -0
  88. package/src/charts-d3/sankey.ts +0 -0
  89. package/src/charts-d3/scatter.ts +0 -185
  90. package/src/charts-d3/shared.ts +0 -208
  91. package/src/class/layout.ts +0 -326
  92. package/src/class/parser.ts +0 -635
  93. package/src/class/renderer.ts +0 -793
  94. package/src/class/types.ts +0 -58
  95. package/src/cli-banner.ts +0 -106
  96. package/src/cli.ts +0 -1080
  97. package/src/colors-diagnostics.ts +0 -35
  98. package/src/colors.ts +0 -379
  99. package/src/completion-types.ts +0 -27
  100. package/src/completion.ts +0 -2668
  101. package/src/cycle/layout.ts +0 -1026
  102. package/src/cycle/parser.ts +0 -387
  103. package/src/cycle/renderer.ts +0 -653
  104. package/src/cycle/types.ts +0 -101
  105. package/src/d3.ts +0 -1434
  106. package/src/data-chart-parser.ts +0 -1007
  107. package/src/dgmo-router.ts +0 -296
  108. package/src/diagnostics-registry.ts +0 -108
  109. package/src/diagnostics.ts +0 -0
  110. package/src/dimensions.ts +0 -20
  111. package/src/directives-registry.ts +0 -396
  112. package/src/editor/dgmo.grammar +0 -76
  113. package/src/editor/dgmo.grammar.d.ts +0 -2
  114. package/src/editor/dgmo.grammar.js +0 -18
  115. package/src/editor/dgmo.grammar.terms.d.ts +0 -5
  116. package/src/editor/dgmo.grammar.terms.js +0 -35
  117. package/src/editor/highlight-api.ts +0 -596
  118. package/src/editor/highlight.ts +0 -36
  119. package/src/editor/index.ts +0 -27
  120. package/src/editor/keywords.ts +0 -128
  121. package/src/editor/tokens.ts +0 -30
  122. package/src/element/index.ts +0 -432
  123. package/src/embed/css.ts +0 -312
  124. package/src/embed/escape.ts +0 -15
  125. package/src/embed/index.ts +0 -280
  126. package/src/er/classify.ts +0 -228
  127. package/src/er/layout.ts +0 -530
  128. package/src/er/parser.ts +0 -750
  129. package/src/er/renderer.ts +0 -725
  130. package/src/er/types.ts +0 -52
  131. package/src/error-card.ts +0 -269
  132. package/src/event-line/diagnostics.ts +0 -117
  133. package/src/event-line/parser.ts +0 -643
  134. package/src/event-line/renderer.ts +0 -1742
  135. package/src/event-line/types.ts +0 -74
  136. package/src/fonts.ts +0 -3
  137. package/src/gantt/calculator.ts +0 -979
  138. package/src/gantt/parser.ts +0 -1641
  139. package/src/gantt/renderer.ts +0 -3787
  140. package/src/gantt/resolver.ts +0 -172
  141. package/src/gantt/types.ts +0 -206
  142. package/src/graph/diagnostics.ts +0 -64
  143. package/src/graph/edge-spline.ts +0 -29
  144. package/src/graph/flowchart-parser.ts +0 -759
  145. package/src/graph/flowchart-renderer.ts +0 -817
  146. package/src/graph/layout.ts +0 -472
  147. package/src/graph/notes.ts +0 -21
  148. package/src/graph/state-collapse.ts +0 -78
  149. package/src/graph/state-parser.ts +0 -574
  150. package/src/graph/state-renderer.ts +0 -653
  151. package/src/graph/types.ts +0 -65
  152. package/src/index.ts +0 -261
  153. package/src/infra/compute.ts +0 -1385
  154. package/src/infra/layout.ts +0 -888
  155. package/src/infra/parser.ts +0 -1234
  156. package/src/infra/renderer.ts +0 -2534
  157. package/src/infra/roles.ts +0 -75
  158. package/src/infra/types.ts +0 -216
  159. package/src/infra/validation.ts +0 -201
  160. package/src/journey-map/layout.ts +0 -490
  161. package/src/journey-map/parser.ts +0 -557
  162. package/src/journey-map/renderer.ts +0 -1580
  163. package/src/journey-map/types.ts +0 -47
  164. package/src/kanban/mutations.ts +0 -175
  165. package/src/kanban/parser.ts +0 -509
  166. package/src/kanban/renderer.ts +0 -1449
  167. package/src/kanban/types.ts +0 -39
  168. package/src/label-layout.ts +0 -368
  169. package/src/map/colorize.ts +0 -54
  170. package/src/map/completion.ts +0 -316
  171. package/src/map/context-labels.ts +0 -609
  172. package/src/map/data/PROVENANCE.json +0 -1
  173. package/src/map/data/README.md +0 -40
  174. package/src/map/data/airport-collisions.json +0 -1
  175. package/src/map/data/airports.json +0 -1
  176. package/src/map/data/gazetteer.json +0 -1
  177. package/src/map/data/lakes.json +0 -1
  178. package/src/map/data/mountain-ranges.json +0 -1
  179. package/src/map/data/na-lakes.json +0 -1
  180. package/src/map/data/na-land.json +0 -1
  181. package/src/map/data/region-names.json +0 -1
  182. package/src/map/data/rivers.json +0 -1
  183. package/src/map/data/types.ts +0 -121
  184. package/src/map/data/us-states.json +0 -1
  185. package/src/map/data/water-bodies.json +0 -1
  186. package/src/map/data/world-coarse.json +0 -1
  187. package/src/map/data/world-detail.json +0 -1
  188. package/src/map/diagnostics.ts +0 -134
  189. package/src/map/dimensions.ts +0 -150
  190. package/src/map/geo-query.ts +0 -295
  191. package/src/map/geo.ts +0 -438
  192. package/src/map/invert.ts +0 -111
  193. package/src/map/layout.ts +0 -5069
  194. package/src/map/legend-band.ts +0 -127
  195. package/src/map/load-data.ts +0 -186
  196. package/src/map/parser.ts +0 -783
  197. package/src/map/renderer.ts +0 -1445
  198. package/src/map/resolved-types.ts +0 -160
  199. package/src/map/resolver.ts +0 -1146
  200. package/src/map/types.ts +0 -194
  201. package/src/mindmap/collapse.ts +0 -67
  202. package/src/mindmap/layout.ts +0 -649
  203. package/src/mindmap/parser.ts +0 -430
  204. package/src/mindmap/renderer.ts +0 -637
  205. package/src/mindmap/text-wrap.ts +0 -218
  206. package/src/mindmap/types.ts +0 -56
  207. package/src/org/collapse.ts +0 -151
  208. package/src/org/layout.ts +0 -1262
  209. package/src/org/parser.ts +0 -519
  210. package/src/org/renderer.ts +0 -866
  211. package/src/org/resolver.ts +0 -636
  212. package/src/palettes/atlas.ts +0 -77
  213. package/src/palettes/blueprint.ts +0 -73
  214. package/src/palettes/catppuccin.ts +0 -84
  215. package/src/palettes/color-utils.ts +0 -443
  216. package/src/palettes/index.ts +0 -67
  217. package/src/palettes/nord.ts +0 -67
  218. package/src/palettes/registry.ts +0 -114
  219. package/src/palettes/slate.ts +0 -73
  220. package/src/palettes/tidewater.ts +0 -73
  221. package/src/palettes/tokyo-night.ts +0 -86
  222. package/src/palettes/types.ts +0 -88
  223. package/src/pert/analyzer.ts +0 -1183
  224. package/src/pert/diagnostics.ts +0 -110
  225. package/src/pert/index.ts +0 -43
  226. package/src/pert/internal.ts +0 -252
  227. package/src/pert/layout.ts +0 -971
  228. package/src/pert/monte-carlo.ts +0 -446
  229. package/src/pert/parser.ts +0 -1606
  230. package/src/pert/renderer.ts +0 -4009
  231. package/src/pert/share-normalize.ts +0 -62
  232. package/src/pert/types.ts +0 -604
  233. package/src/pyramid/parser.ts +0 -185
  234. package/src/pyramid/renderer.ts +0 -768
  235. package/src/pyramid/types.ts +0 -28
  236. package/src/quadrant/parser.ts +0 -18
  237. package/src/quadrant/renderer.ts +0 -638
  238. package/src/raci/diagnostics.ts +0 -213
  239. package/src/raci/index.ts +0 -23
  240. package/src/raci/mutations.ts +0 -321
  241. package/src/raci/parser.ts +0 -699
  242. package/src/raci/renderer.ts +0 -1627
  243. package/src/raci/types.ts +0 -82
  244. package/src/raci/variants.ts +0 -320
  245. package/src/render.ts +0 -268
  246. package/src/ring/parser.ts +0 -212
  247. package/src/ring/renderer.ts +0 -490
  248. package/src/ring/types.ts +0 -27
  249. package/src/sequence/collapse.ts +0 -174
  250. package/src/sequence/parser.ts +0 -1596
  251. package/src/sequence/participant-inference.ts +0 -152
  252. package/src/sequence/renderer.ts +0 -3168
  253. package/src/sequence/tag-resolution.ts +0 -164
  254. package/src/sharing.ts +0 -211
  255. package/src/sitemap/collapse.ts +0 -100
  256. package/src/sitemap/layout.ts +0 -925
  257. package/src/sitemap/parser.ts +0 -755
  258. package/src/sitemap/renderer.ts +0 -828
  259. package/src/sitemap/types.ts +0 -42
  260. package/src/slope/parser.ts +0 -18
  261. package/src/slope/renderer.ts +0 -378
  262. package/src/swimlane/diagnostics.ts +0 -94
  263. package/src/swimlane/layout.ts +0 -597
  264. package/src/swimlane/parser.ts +0 -613
  265. package/src/swimlane/renderer.ts +0 -681
  266. package/src/swimlane/types.ts +0 -151
  267. package/src/tech-radar/interactive.ts +0 -1129
  268. package/src/tech-radar/layout.ts +0 -197
  269. package/src/tech-radar/parser.ts +0 -436
  270. package/src/tech-radar/renderer.ts +0 -1239
  271. package/src/tech-radar/shared.ts +0 -151
  272. package/src/tech-radar/types.ts +0 -86
  273. package/src/themes.ts +0 -22
  274. package/src/timeline/parser.ts +0 -472
  275. package/src/timeline/renderer.ts +0 -3024
  276. package/src/timeline/types.ts +0 -33
  277. package/src/timeline/viz-parser.ts +0 -21
  278. package/src/treemap/diagnostics.ts +0 -62
  279. package/src/treemap/layout-radial.ts +0 -233
  280. package/src/treemap/layout.ts +0 -189
  281. package/src/treemap/parser.ts +0 -463
  282. package/src/treemap/renderer-radial.ts +0 -438
  283. package/src/treemap/renderer.ts +0 -572
  284. package/src/treemap/treemap-shared.ts +0 -309
  285. package/src/treemap/types.ts +0 -60
  286. package/src/utils/arrow-markers.ts +0 -51
  287. package/src/utils/arrows-diagnostics.ts +0 -62
  288. package/src/utils/arrows.ts +0 -227
  289. package/src/utils/brand.ts +0 -61
  290. package/src/utils/card.ts +0 -183
  291. package/src/utils/collapse-engine/tree-edges.ts +0 -115
  292. package/src/utils/collapse-engine/tree.ts +0 -117
  293. package/src/utils/d3-helpers.ts +0 -219
  294. package/src/utils/d3-types.ts +0 -9
  295. package/src/utils/description-helpers.ts +0 -38
  296. package/src/utils/duration.ts +0 -312
  297. package/src/utils/export-container.ts +0 -41
  298. package/src/utils/expr-eval.ts +0 -27
  299. package/src/utils/fit-canvas.ts +0 -64
  300. package/src/utils/hover-styles.ts +0 -673
  301. package/src/utils/inline-markdown.ts +0 -96
  302. package/src/utils/legend-constants.ts +0 -48
  303. package/src/utils/legend-d3.ts +0 -618
  304. package/src/utils/legend-integration.ts +0 -107
  305. package/src/utils/legend-layout.ts +0 -776
  306. package/src/utils/legend-svg.ts +0 -214
  307. package/src/utils/legend-types.ts +0 -272
  308. package/src/utils/name-normalize.ts +0 -163
  309. package/src/utils/note-box/constants.ts +0 -25
  310. package/src/utils/note-box/index.ts +0 -11
  311. package/src/utils/note-box/metrics.ts +0 -90
  312. package/src/utils/note-box/svg.ts +0 -331
  313. package/src/utils/notes/bounds.ts +0 -30
  314. package/src/utils/notes/build.ts +0 -131
  315. package/src/utils/notes/index.ts +0 -18
  316. package/src/utils/notes/model.ts +0 -19
  317. package/src/utils/notes/parse.ts +0 -131
  318. package/src/utils/notes/place.ts +0 -177
  319. package/src/utils/notes/resolve.ts +0 -88
  320. package/src/utils/number-format.ts +0 -36
  321. package/src/utils/parsing.ts +0 -953
  322. package/src/utils/reserved-key-registry.ts +0 -239
  323. package/src/utils/safe-href.ts +0 -38
  324. package/src/utils/scaling.ts +0 -97
  325. package/src/utils/svg-embed.ts +0 -251
  326. package/src/utils/tag-groups.ts +0 -607
  327. package/src/utils/text-measure.ts +0 -122
  328. package/src/utils/time-ticks.ts +0 -253
  329. package/src/utils/title-constants.ts +0 -24
  330. package/src/utils/visual-conventions.ts +0 -61
  331. package/src/utils/wrapped-desc.ts +0 -87
  332. package/src/venn/parser.ts +0 -18
  333. package/src/venn/renderer.ts +0 -1047
  334. package/src/version-control/diagnostics.ts +0 -67
  335. package/src/version-control/parser.ts +0 -544
  336. package/src/version-control/renderer.ts +0 -724
  337. package/src/version-control/types.ts +0 -100
  338. package/src/visualizations/parse.ts +0 -1560
  339. package/src/visualizations/types.ts +0 -262
  340. package/src/wireframe/layout.ts +0 -479
  341. package/src/wireframe/parser.ts +0 -1114
  342. package/src/wireframe/renderer.ts +0 -1318
  343. package/src/wireframe/types.ts +0 -110
  344. package/src/wordcloud/parser.ts +0 -18
  345. package/src/wordcloud/renderer.ts +0 -357
@@ -1,636 +0,0 @@
1
- import type { DgmoError } from '../diagnostics';
2
- import { makeDgmoError } from '../diagnostics';
3
- import { isTagBlockHeading, matchTagBlockHeading } from '../utils/tag-groups';
4
-
5
- // ============================================================
6
- // Types
7
- // ============================================================
8
-
9
- /**
10
- * Async or sync file reader. Receives an absolute path, returns content.
11
- * Throwing means "file not found".
12
- */
13
- export type ReadFileFn = (path: string) => string | Promise<string>;
14
-
15
- /** Tracks the original source file and line for an imported line. */
16
- export interface ImportSource {
17
- /** Absolute path of the file this line originates from */
18
- filePath: string;
19
- /** 1-based line number in the original (pre-resolution) source file */
20
- sourceLine: number;
21
- }
22
-
23
- export interface ResolveImportsResult {
24
- content: string;
25
- diagnostics: DgmoError[];
26
- /** resolvedLine (1-based index) → originalLine (1-based) or null for inserted lines */
27
- lineMap: (number | null)[];
28
- /** resolvedLine (1-based index) → import source info or null for non-imported lines */
29
- importSourceMap: (ImportSource | null)[];
30
- }
31
-
32
- // ============================================================
33
- // Constants
34
- // ============================================================
35
-
36
- const MAX_DEPTH = 10;
37
- const IMPORT_RE = /^(\s+)import:?\s+(.+\.dgmo)\s*$/i;
38
- const TAGS_RE = /^tags:?\s+(.+\.dgmo)\s*$/i;
39
- /** Matches new-style first line: `org ...` or `kanban ...` or `title: ...` */
40
- const HEADER_RE = /^(org|kanban|title\s*:)/i;
41
- /**
42
- * Known option keys that can appear in org chart headers (space-separated).
43
- * Only these are stripped from imported files — avoids eating content like "Alice Chen".
44
- * MUST stay in sync with `KNOWN_OPTIONS` + `KNOWN_BOOLEANS` in `parser.ts`; otherwise
45
- * an unknown header keyword causes the resolver to misidentify body-start, which
46
- * pushes downstream `tags` / `import` directives into the body as garbage.
47
- */
48
- const KNOWN_HEADER_OPTIONS = new Set([
49
- 'direction-tb',
50
- 'sub-node-label',
51
- 'hide',
52
- 'show-sub-node-count',
53
- 'color-off',
54
- 'solid-fill',
55
- 'active-tag',
56
- ]);
57
-
58
- // ============================================================
59
- // Path Helpers (pure string ops — no Node `path` dependency)
60
- // ============================================================
61
-
62
- function dirname(filePath: string): string {
63
- const last = filePath.lastIndexOf('/');
64
- return last > 0 ? filePath.substring(0, last) : '/';
65
- }
66
-
67
- function resolvePath(base: string, relative: string): string {
68
- const parts = dirname(base).split('/');
69
- for (const seg of relative.split('/')) {
70
- if (seg === '..') {
71
- if (parts.length > 1) parts.pop();
72
- } else if (seg !== '.' && seg !== '') {
73
- parts.push(seg);
74
- }
75
- }
76
- return parts.join('/') || '/';
77
- }
78
-
79
- // ============================================================
80
- // Tag Group Extraction
81
- // ============================================================
82
-
83
- interface TagGroupBlock {
84
- name: string; // lowercased for comparison
85
- lines: string[]; // raw lines including heading + entries
86
- }
87
-
88
- /**
89
- * Extract ## tag group blocks from content lines.
90
- * Returns blocks in order, each with its heading + indented entries.
91
- */
92
- function extractTagGroups(lines: string[]): TagGroupBlock[] {
93
- const blocks: TagGroupBlock[] = [];
94
- let current: TagGroupBlock | null = null;
95
-
96
- for (const line of lines) {
97
- const trimmed = line.trim();
98
- const headingMatch = matchTagBlockHeading(trimmed);
99
- if (headingMatch) {
100
- const name = headingMatch.name.toLowerCase();
101
- current = { name, lines: [line] };
102
- blocks.push(current);
103
- } else if (current) {
104
- if (trimmed === '' || trimmed.startsWith('//')) {
105
- // Blank line or comment ends the tag group
106
- current = null;
107
- } else if (line.match(/^\s+/)) {
108
- // Indented = tag entry
109
- current.lines.push(line);
110
- } else {
111
- // Non-indented non-heading = end of tag group
112
- current = null;
113
- }
114
- }
115
- }
116
-
117
- return blocks;
118
- }
119
-
120
- // ============================================================
121
- // Header Stripping
122
- // ============================================================
123
-
124
- interface ParsedHeader {
125
- /** Lines that are NOT header/tags/tag-groups — the "content" body */
126
- contentLines: string[];
127
- /** For each contentLine, its 0-based index in the input lines[] array */
128
- contentLineIndices: number[];
129
- tagGroups: TagGroupBlock[];
130
- tagsDirective: string | null;
131
- }
132
-
133
- /**
134
- * Separate an imported file into header (stripped) and content body.
135
- * Also extracts tag groups and tags directive for merging.
136
- */
137
- function parseFileHeader(lines: string[]): ParsedHeader {
138
- const tagGroups = extractTagGroups(lines);
139
- const tagGroupLineSet = new Set<number>();
140
- for (const group of tagGroups) {
141
- // Find where this group starts in lines
142
- for (let i = 0; i < lines.length; i++) {
143
- if (lines[i] === group.lines[0]) {
144
- for (let j = 0; j < group.lines.length; j++) {
145
- tagGroupLineSet.add(i + j);
146
- }
147
- break;
148
- }
149
- }
150
- }
151
-
152
- let tagsDirective: string | null = null;
153
- const contentLines: string[] = [];
154
- const contentLineIndices: number[] = [];
155
- let headerDone = false;
156
-
157
- for (let i = 0; i < lines.length; i++) {
158
- // Skip tag group lines
159
- if (tagGroupLineSet.has(i)) continue;
160
-
161
- // In-bounds by loop guard.
162
- const rawLine = lines[i]!;
163
- const trimmed = rawLine.trim();
164
-
165
- // Skip blank/comment lines in header region
166
- if (!headerDone && (trimmed === '' || trimmed.startsWith('//'))) continue;
167
-
168
- // Header lines
169
- if (!headerDone) {
170
- if (HEADER_RE.test(trimmed)) continue;
171
-
172
- const tagsMatch = trimmed.match(TAGS_RE);
173
- if (tagsMatch) {
174
- // Capture group 1 guaranteed by TAGS_RE match.
175
- tagsDirective = tagsMatch[1]!.trim();
176
- continue;
177
- }
178
-
179
- // Known option header lines (space-separated `key value` or bare boolean)
180
- if (
181
- !rawLine.match(/^\s/) &&
182
- !isTagBlockHeading(trimmed) &&
183
- !trimmed.includes('|')
184
- ) {
185
- // String.split always returns at least one element.
186
- const firstToken = trimmed.split(/\s/)[0]!.toLowerCase();
187
- if (KNOWN_HEADER_OPTIONS.has(firstToken)) {
188
- continue;
189
- }
190
- }
191
-
192
- headerDone = true;
193
- }
194
-
195
- contentLines.push(rawLine);
196
- contentLineIndices.push(i);
197
- }
198
-
199
- return { contentLines, contentLineIndices, tagGroups, tagsDirective };
200
- }
201
-
202
- // ============================================================
203
- // Main Resolver
204
- // ============================================================
205
-
206
- /**
207
- * Pre-processes org chart content, resolving `tags` and `import` directives.
208
- *
209
- * @param content - Raw .dgmo file content
210
- * @param filePath - Absolute path of the file (for relative path resolution)
211
- * @param readFileFn - Function to read files (sync or async)
212
- * @returns Merged content with all imports resolved + diagnostics
213
- */
214
- export async function resolveOrgImports(
215
- content: string,
216
- filePath: string,
217
- readFileFn: ReadFileFn
218
- ): Promise<ResolveImportsResult> {
219
- const diagnostics: DgmoError[] = [];
220
- const result = await resolveFile(
221
- content,
222
- filePath,
223
- readFileFn,
224
- diagnostics,
225
- new Set([filePath]),
226
- 0
227
- );
228
- return {
229
- content: result.content,
230
- diagnostics,
231
- lineMap: result.lineMap,
232
- importSourceMap: result.importSourceMap,
233
- };
234
- }
235
-
236
- async function resolveFile(
237
- content: string,
238
- filePath: string,
239
- readFileFn: ReadFileFn,
240
- diagnostics: DgmoError[],
241
- ancestorChain: Set<string>,
242
- depth: number
243
- ): Promise<{
244
- content: string;
245
- lineMap: (number | null)[];
246
- importSourceMap: (ImportSource | null)[];
247
- }> {
248
- const lines = content.split('\n');
249
-
250
- // ---- Step 1: Identify header, tags directive, inline tag groups ----
251
- const headerLines: { text: string; originalLine: number }[] = [];
252
- let tagsDirective: string | null = null;
253
- const inlineTagGroups = extractTagGroups(lines);
254
- const bodyStartIndex = findBodyStart(lines);
255
-
256
- // Collect header lines (chart:, title:, options, tags:)
257
- let tagsLineNumber = 0; // 1-based line number of the tags directive
258
- for (let i = 0; i < bodyStartIndex; i++) {
259
- // In-bounds: bodyStartIndex <= lines.length by construction.
260
- const rawLine = lines[i]!;
261
- const trimmed = rawLine.trim();
262
- if (trimmed === '' || trimmed.startsWith('//')) {
263
- headerLines.push({ text: rawLine, originalLine: i + 1 });
264
- continue;
265
- }
266
- if (isTagBlockHeading(trimmed)) continue; // skip inline tag group headings
267
- if (/^\s/.test(rawLine)) continue; // skip tag group entries (indented lines)
268
-
269
- const tagsMatch = trimmed.match(TAGS_RE);
270
- if (tagsMatch) {
271
- // Capture group 1 guaranteed by TAGS_RE match.
272
- tagsDirective = tagsMatch[1]!.trim();
273
- tagsLineNumber = i + 1; // 1-based
274
- continue;
275
- }
276
-
277
- headerLines.push({ text: rawLine, originalLine: i + 1 });
278
- }
279
-
280
- // ---- Step 2: Resolve tags directive ----
281
- let tagsFileGroups: TagGroupBlock[] = [];
282
- if (tagsDirective) {
283
- const tagsPath = resolvePath(filePath, tagsDirective);
284
- try {
285
- const tagsContent = await readFileFn(tagsPath);
286
- const tagsLines = tagsContent.split('\n');
287
- tagsFileGroups = extractTagGroups(tagsLines);
288
- } catch {
289
- diagnostics.push(
290
- makeDgmoError(tagsLineNumber, `Tags file not found: ${tagsDirective}`)
291
- );
292
- }
293
- }
294
-
295
- // ---- Step 3: Resolve import directives in body ----
296
- const bodyLines = lines.slice(bodyStartIndex);
297
- const resolvedBodyLines: {
298
- text: string;
299
- originalLine: number | null;
300
- importSource: ImportSource | null;
301
- }[] = [];
302
- const importedTagGroups: TagGroupBlock[] = [];
303
-
304
- for (let i = 0; i < bodyLines.length; i++) {
305
- // In-bounds by loop guard.
306
- const line = bodyLines[i]!;
307
- const lineNumber = bodyStartIndex + i + 1; // 1-based for diagnostics
308
- const importMatch = line.match(IMPORT_RE);
309
-
310
- if (!importMatch) {
311
- // Pass through — skip inline tag group lines (already extracted above)
312
- const trimmed = line.trim();
313
- if (
314
- isTagBlockHeading(trimmed) ||
315
- (inlineTagGroups.length > 0 && isTagGroupEntry(line, bodyLines, i))
316
- ) {
317
- continue;
318
- }
319
- resolvedBodyLines.push({
320
- text: line,
321
- originalLine: lineNumber,
322
- importSource: null,
323
- });
324
- continue;
325
- }
326
-
327
- // Capture groups 1 and 2 guaranteed by IMPORT_RE match.
328
- const indent = importMatch[1]!;
329
- const importRelPath = importMatch[2]!.trim();
330
- const importAbsPath = resolvePath(filePath, importRelPath);
331
-
332
- // Depth check
333
- if (depth >= MAX_DEPTH) {
334
- diagnostics.push(
335
- makeDgmoError(
336
- lineNumber,
337
- `Import depth limit exceeded (${MAX_DEPTH}): ${importRelPath}`
338
- )
339
- );
340
- continue;
341
- }
342
-
343
- // Circular check
344
- if (ancestorChain.has(importAbsPath)) {
345
- const chain = [...ancestorChain, importAbsPath]
346
- .map((p) => p.split('/').pop())
347
- .join(' -> ');
348
- diagnostics.push(
349
- makeDgmoError(lineNumber, `Circular import detected: ${chain}`)
350
- );
351
- continue;
352
- }
353
-
354
- // Read imported file
355
- let importedContent: string;
356
- try {
357
- importedContent = await readFileFn(importAbsPath);
358
- } catch {
359
- diagnostics.push(
360
- makeDgmoError(lineNumber, `Import file not found: ${importRelPath}`)
361
- );
362
- continue;
363
- }
364
-
365
- // Recurse to resolve nested imports
366
- const nestedChain = new Set(ancestorChain);
367
- nestedChain.add(importAbsPath);
368
- const resolved = await resolveFile(
369
- importedContent,
370
- importAbsPath,
371
- readFileFn,
372
- diagnostics,
373
- nestedChain,
374
- depth + 1
375
- );
376
-
377
- // Strip header, extract tag groups from resolved content
378
- const resolvedLines = resolved.content.split('\n');
379
- const parsed = parseFileHeader(resolvedLines);
380
-
381
- // Collect tag groups from imported file (lowest priority)
382
- for (const group of parsed.tagGroups) {
383
- importedTagGroups.push(group);
384
- }
385
-
386
- // Re-indent and insert content lines, computing import source for each
387
- const importedContentLines: { text: string; index: number }[] = [];
388
- for (let j = 0; j < parsed.contentLines.length; j++) {
389
- // In-bounds by loop guard; contentLineIndices is parallel by construction.
390
- const cText = parsed.contentLines[j]!;
391
- const cIndex = parsed.contentLineIndices[j]!;
392
- if (cText.trim() !== '') {
393
- importedContentLines.push({
394
- text: cText,
395
- index: cIndex,
396
- });
397
- }
398
- }
399
-
400
- // Trim trailing empty lines but keep internal structure
401
- let lastNonEmpty = importedContentLines.length - 1;
402
- while (
403
- lastNonEmpty >= 0 &&
404
- importedContentLines[lastNonEmpty]!.text.trim() === ''
405
- ) {
406
- lastNonEmpty--;
407
- }
408
- const trimmedImported = importedContentLines.slice(0, lastNonEmpty + 1);
409
-
410
- for (const entry of trimmedImported) {
411
- // Compute import source: which file and line does this content originate from?
412
- // entry.index is the 0-based index in resolved.content.split('\n')
413
- const resolvedLineNum = entry.index + 1; // 1-based line in the resolved imported content
414
-
415
- // Check if this line itself came from a deeper import
416
- let importSource: ImportSource | null = null;
417
- if (resolved.importSourceMap[resolvedLineNum]) {
418
- // Nested import — use the deepest source
419
- importSource = resolved.importSourceMap[resolvedLineNum];
420
- } else {
421
- // Direct content from this imported file
422
- const origLine = resolved.lineMap[resolvedLineNum];
423
- if (origLine != null) {
424
- importSource = { filePath: importAbsPath, sourceLine: origLine };
425
- }
426
- }
427
-
428
- if (entry.text.trim() === '') {
429
- resolvedBodyLines.push({
430
- text: '',
431
- originalLine: lineNumber,
432
- importSource,
433
- });
434
- } else {
435
- resolvedBodyLines.push({
436
- text: indent + entry.text,
437
- originalLine: lineNumber,
438
- importSource,
439
- });
440
- }
441
- }
442
- }
443
-
444
- // ---- Step 4: Merge tag groups with precedence ----
445
- // Priority: inline > tags file > imported files
446
- const mergedGroups = mergeTagGroups(
447
- inlineTagGroups,
448
- tagsFileGroups,
449
- importedTagGroups
450
- );
451
-
452
- // ---- Step 5: Rebuild output ----
453
- const outputLines: string[] = [];
454
- // lineMap[i] maps resolved line i (1-based) to original line (1-based) or null
455
- // importSourceMap[i] maps resolved line i (1-based) to import source or null
456
- // Index 0 is unused padding so indices align with 1-based line numbers
457
- const lineMap: (number | null)[] = [null];
458
- const importSourceMap: (ImportSource | null)[] = [null];
459
-
460
- // Header lines (chart:, title:, options — no tags or tag groups)
461
- for (const entry of headerLines) {
462
- outputLines.push(entry.text);
463
- lineMap.push(entry.originalLine);
464
- importSourceMap.push(null);
465
- }
466
-
467
- // Merged tag groups
468
- if (mergedGroups.length > 0) {
469
- // Ensure blank line before tag groups if header has content
470
- if (
471
- outputLines.length > 0 &&
472
- // In-bounds by length guard.
473
- outputLines[outputLines.length - 1]!.trim() !== ''
474
- ) {
475
- outputLines.push('');
476
- lineMap.push(null);
477
- importSourceMap.push(null);
478
- }
479
- for (const group of mergedGroups) {
480
- // Find original line for inline tag groups, null for external
481
- const inlineMatch = inlineTagGroups.find((g) => g.name === group.name);
482
- for (const line of group.lines) {
483
- outputLines.push(line);
484
- // Inline tag groups map to their original line, external ones map to null
485
- if (inlineMatch) {
486
- // Find the original line index of this tag group in the source
487
- const srcIdx = lines.indexOf(line);
488
- lineMap.push(srcIdx >= 0 ? srcIdx + 1 : null);
489
- } else {
490
- lineMap.push(null);
491
- }
492
- importSourceMap.push(null);
493
- }
494
- outputLines.push(''); // blank line between groups
495
- lineMap.push(null);
496
- importSourceMap.push(null);
497
- }
498
- }
499
-
500
- // Body content
501
- // Ensure blank line separator
502
- if (
503
- resolvedBodyLines.length > 0 &&
504
- outputLines.length > 0 &&
505
- // In-bounds by length guard.
506
- outputLines[outputLines.length - 1]!.trim() !== ''
507
- ) {
508
- outputLines.push('');
509
- lineMap.push(null);
510
- importSourceMap.push(null);
511
- }
512
- for (const entry of resolvedBodyLines) {
513
- outputLines.push(entry.text);
514
- lineMap.push(entry.originalLine);
515
- importSourceMap.push(entry.importSource);
516
- }
517
-
518
- return { content: outputLines.join('\n'), lineMap, importSourceMap };
519
- }
520
-
521
- // ============================================================
522
- // Helpers
523
- // ============================================================
524
-
525
- /**
526
- * Find the index where the body (non-header, non-tag-group content) starts.
527
- */
528
- function findBodyStart(lines: string[]): number {
529
- let inTagGroup = false;
530
-
531
- for (let i = 0; i < lines.length; i++) {
532
- // In-bounds by loop guard.
533
- const rawLine = lines[i]!;
534
- const trimmed = rawLine.trim();
535
-
536
- if (trimmed === '' || trimmed.startsWith('//')) {
537
- if (inTagGroup) inTagGroup = false;
538
- continue;
539
- }
540
-
541
- // Tag group heading
542
- if (isTagBlockHeading(trimmed)) {
543
- inTagGroup = true;
544
- continue;
545
- }
546
-
547
- // Tag group entry (indented under heading)
548
- if (inTagGroup && rawLine.match(/^\s+/)) {
549
- continue;
550
- }
551
-
552
- if (inTagGroup) {
553
- inTagGroup = false;
554
- }
555
-
556
- // Header directives
557
- if (HEADER_RE.test(trimmed)) continue;
558
- if (TAGS_RE.test(trimmed)) continue;
559
-
560
- // Known option lines (space-separated `key value` or bare boolean before content)
561
- if (
562
- !rawLine.match(/^\s/) &&
563
- !trimmed.includes('|') &&
564
- !isTagBlockHeading(trimmed)
565
- ) {
566
- // String.split always returns at least one element.
567
- const firstToken = trimmed.split(/\s/)[0]!.toLowerCase();
568
- if (KNOWN_HEADER_OPTIONS.has(firstToken)) {
569
- continue;
570
- }
571
- }
572
-
573
- // This is the first body line
574
- return i;
575
- }
576
-
577
- return lines.length;
578
- }
579
-
580
- /**
581
- * Check if a line is a tag group entry (indented line under a tag block heading).
582
- */
583
- function isTagGroupEntry(
584
- line: string,
585
- allLines: string[],
586
- index: number
587
- ): boolean {
588
- if (!line.match(/^\s+/)) return false;
589
- // Walk backwards to find the nearest non-blank, non-comment, non-entry line
590
- for (let i = index - 1; i >= 0; i--) {
591
- // In-bounds by reverse-for loop guard.
592
- const prevRaw = allLines[i]!;
593
- const prev = prevRaw.trim();
594
- if (prev === '' || prev.startsWith('//')) continue;
595
- if (isTagBlockHeading(prev)) return true;
596
- if (prevRaw.match(/^\s+/)) continue; // another entry
597
- return false;
598
- }
599
- return false;
600
- }
601
-
602
- /**
603
- * Merge tag groups from three sources with priority:
604
- * inline (highest) > tags file > imported files (lowest).
605
- *
606
- * On name conflict (case-insensitive), higher priority wins.
607
- * New groups from lower priority are added.
608
- */
609
- function mergeTagGroups(
610
- inline: TagGroupBlock[],
611
- tagsFile: TagGroupBlock[],
612
- imported: TagGroupBlock[]
613
- ): TagGroupBlock[] {
614
- const seen = new Map<string, TagGroupBlock>();
615
-
616
- // Inline first (highest priority)
617
- for (const group of inline) {
618
- seen.set(group.name, group);
619
- }
620
-
621
- // Tags file (medium priority — only add if not overridden)
622
- for (const group of tagsFile) {
623
- if (!seen.has(group.name)) {
624
- seen.set(group.name, group);
625
- }
626
- }
627
-
628
- // Imported files (lowest priority — only add if not present)
629
- for (const group of imported) {
630
- if (!seen.has(group.name)) {
631
- seen.set(group.name, group);
632
- }
633
- }
634
-
635
- return Array.from(seen.values());
636
- }
@@ -1,77 +0,0 @@
1
- import type { PaletteConfig } from './types';
2
- import { registerPalette } from './registry';
3
-
4
- // ============================================================
5
- // Atlas Palette Definition
6
- // ============================================================
7
- //
8
- // Inspired by vintage classroom pull-down maps and school atlases:
9
- // soft, slightly-aged political fills on warm manila paper, sepia ink
10
- // borders, and a muted steel-blue "pull-down map ocean". The accent
11
- // rotation is the classic set of pastels cartographers use to keep
12
- // adjacent regions distinct without shouting.
13
- //
14
- // Light mode is the star (paper-and-ink). Dark mode shifts the ground to
15
- // deep-ocean navy — the "map at night / globe" register — and brightens
16
- // the same pastels so they read on the darker field.
17
-
18
- export const atlasPalette: PaletteConfig = {
19
- id: 'atlas',
20
- name: 'Atlas',
21
- light: {
22
- bg: '#f3ead3', // warm manila / parchment
23
- surface: '#ece0c0', // deeper paper (cards, panels)
24
- overlay: '#e8dab8', // popovers, dropdowns
25
- border: '#bcaa86', // muted sepia rule line
26
- text: '#463a26', // aged sepia-brown ink
27
- textMuted: '#7a6a4f', // faded annotation ink
28
- textOnFillLight: '#f7f1de', // parchment (light text on dark fills)
29
- textOnFillDark: '#3a2e1c', // deep ink (dark text on light fills)
30
- primary: '#5b7a99', // pull-down map ocean (steel-blue)
31
- secondary: '#7e9a6f', // lowland sage / celadon
32
- accent: '#b07f7c', // dusty rose
33
- destructive: '#b25a45', // brick / terracotta
34
- colors: {
35
- red: '#bf6a52', // terracotta brick
36
- orange: '#cf9a5c', // map tan / ochre
37
- yellow: '#cdb35e', // straw / muted lemon
38
- green: '#7e9a6f', // sage / celadon lowland
39
- blue: '#5b7a99', // steel-blue ocean
40
- purple: '#9a7fa6', // dusty lilac / mauve
41
- teal: '#6fa094', // muted seafoam
42
- cyan: '#79a7b5', // shallow-water blue
43
- gray: '#8a7d68', // warm taupe
44
- black: '#463a26', // ink
45
- white: '#ece0c0', // paper
46
- },
47
- },
48
- dark: {
49
- bg: '#1e2a33', // deep map ocean (night globe)
50
- surface: '#27353f', // raised ocean
51
- overlay: '#2e3d48', // popovers, dropdowns
52
- border: '#3d4f5c', // depth-contour line
53
- text: '#e8dcc0', // parchment ink, inverted
54
- textMuted: '#a89a7d', // faded label
55
- textOnFillLight: '#f7f1de', // parchment
56
- textOnFillDark: '#1a242c', // deep ocean ink
57
- primary: '#7ba0bf', // brighter ocean
58
- secondary: '#9bb588', // sage, lifted
59
- accent: '#cf9a96', // dusty rose, lifted
60
- destructive: '#c9745c', // brick, lifted
61
- colors: {
62
- red: '#cf7a60', // terracotta
63
- orange: '#d9a96a', // tan / ochre
64
- yellow: '#d8c074', // straw
65
- green: '#9bb588', // sage lowland
66
- blue: '#7ba0bf', // ocean
67
- purple: '#b59ac0', // lilac / mauve
68
- teal: '#85b3a6', // seafoam
69
- cyan: '#92bccb', // shallow-water blue
70
- gray: '#9a8d76', // warm taupe
71
- black: '#27353f', // raised ocean
72
- white: '#e8dcc0', // parchment
73
- },
74
- },
75
- };
76
-
77
- registerPalette(atlasPalette);