@diagrammo/dgmo 0.47.0 → 0.48.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 (319) hide show
  1. package/dist/auto.js +1 -1
  2. package/dist/auto.mjs +1 -1
  3. package/dist/element.js +1 -1
  4. package/dist/element.mjs +1 -1
  5. package/package.json +19 -70
  6. package/dist/advanced.cjs +0 -71648
  7. package/dist/advanced.d.cts +0 -5719
  8. package/dist/auto.cjs +0 -70648
  9. package/dist/auto.d.cts +0 -54
  10. package/dist/block.cjs +0 -70208
  11. package/dist/block.d.cts +0 -115
  12. package/dist/editor.cjs +0 -526
  13. package/dist/editor.d.cts +0 -26
  14. package/dist/element.cjs +0 -70530
  15. package/dist/element.d.cts +0 -62
  16. package/dist/highlight.cjs +0 -852
  17. package/dist/highlight.d.cts +0 -49
  18. package/dist/index.cjs +0 -70491
  19. package/dist/index.d.cts +0 -160
  20. package/dist/pert.cjs +0 -325
  21. package/dist/pert.d.cts +0 -559
  22. package/dist/themes-1-CuKpeH.d.cts +0 -908
  23. package/src/advanced.ts +0 -873
  24. package/src/arc/parser.ts +0 -15
  25. package/src/arc/renderer.ts +0 -633
  26. package/src/auto/index.ts +0 -621
  27. package/src/auto/shared.ts +0 -370
  28. package/src/auto/styles.ts +0 -73
  29. package/src/block/layout.ts +0 -198
  30. package/src/block/parser.ts +0 -427
  31. package/src/block/renderer.ts +0 -484
  32. package/src/block/types.ts +0 -67
  33. package/src/boxes-and-lines/collapse.ts +0 -96
  34. package/src/boxes-and-lines/focus.ts +0 -257
  35. package/src/boxes-and-lines/label-placement.ts +0 -339
  36. package/src/boxes-and-lines/layout-grouped.ts +0 -912
  37. package/src/boxes-and-lines/layout-layered.ts +0 -722
  38. package/src/boxes-and-lines/layout-search.ts +0 -1678
  39. package/src/boxes-and-lines/layout.ts +0 -398
  40. package/src/boxes-and-lines/parser.ts +0 -1181
  41. package/src/boxes-and-lines/renderer.ts +0 -1465
  42. package/src/boxes-and-lines/types.ts +0 -66
  43. package/src/c4/layout.ts +0 -2441
  44. package/src/c4/parser.ts +0 -1158
  45. package/src/c4/renderer.ts +0 -2008
  46. package/src/c4/types.ts +0 -89
  47. package/src/chart-type-registry.ts +0 -529
  48. package/src/chart-types.ts +0 -225
  49. package/src/chart.ts +0 -685
  50. package/src/charts-d3/bar.ts +0 -338
  51. package/src/charts-d3/chord.ts +0 -140
  52. package/src/charts-d3/function.ts +0 -147
  53. package/src/charts-d3/funnel.ts +0 -104
  54. package/src/charts-d3/heatmap.ts +0 -145
  55. package/src/charts-d3/index.ts +0 -337
  56. package/src/charts-d3/interactions.ts +0 -477
  57. package/src/charts-d3/line.ts +0 -344
  58. package/src/charts-d3/mount.ts +0 -151
  59. package/src/charts-d3/pie.ts +0 -117
  60. package/src/charts-d3/polar.ts +0 -89
  61. package/src/charts-d3/radar.ts +0 -0
  62. package/src/charts-d3/sankey.ts +0 -0
  63. package/src/charts-d3/scatter.ts +0 -185
  64. package/src/charts-d3/shared.ts +0 -208
  65. package/src/class/layout.ts +0 -326
  66. package/src/class/parser.ts +0 -635
  67. package/src/class/renderer.ts +0 -793
  68. package/src/class/types.ts +0 -58
  69. package/src/cli-banner.ts +0 -106
  70. package/src/cli.ts +0 -1080
  71. package/src/colors-diagnostics.ts +0 -35
  72. package/src/colors.ts +0 -379
  73. package/src/completion-types.ts +0 -27
  74. package/src/completion.ts +0 -2668
  75. package/src/cycle/layout.ts +0 -1026
  76. package/src/cycle/parser.ts +0 -387
  77. package/src/cycle/renderer.ts +0 -653
  78. package/src/cycle/types.ts +0 -101
  79. package/src/d3.ts +0 -1434
  80. package/src/data-chart-parser.ts +0 -1007
  81. package/src/dgmo-router.ts +0 -296
  82. package/src/diagnostics-registry.ts +0 -108
  83. package/src/diagnostics.ts +0 -0
  84. package/src/dimensions.ts +0 -20
  85. package/src/directives-registry.ts +0 -396
  86. package/src/editor/dgmo.grammar +0 -76
  87. package/src/editor/dgmo.grammar.d.ts +0 -2
  88. package/src/editor/dgmo.grammar.js +0 -18
  89. package/src/editor/dgmo.grammar.terms.d.ts +0 -5
  90. package/src/editor/dgmo.grammar.terms.js +0 -35
  91. package/src/editor/highlight-api.ts +0 -596
  92. package/src/editor/highlight.ts +0 -36
  93. package/src/editor/index.ts +0 -27
  94. package/src/editor/keywords.ts +0 -128
  95. package/src/editor/tokens.ts +0 -30
  96. package/src/element/index.ts +0 -432
  97. package/src/embed/css.ts +0 -312
  98. package/src/embed/escape.ts +0 -15
  99. package/src/embed/index.ts +0 -280
  100. package/src/er/classify.ts +0 -228
  101. package/src/er/layout.ts +0 -530
  102. package/src/er/parser.ts +0 -750
  103. package/src/er/renderer.ts +0 -725
  104. package/src/er/types.ts +0 -52
  105. package/src/error-card.ts +0 -269
  106. package/src/event-line/diagnostics.ts +0 -117
  107. package/src/event-line/parser.ts +0 -643
  108. package/src/event-line/renderer.ts +0 -1742
  109. package/src/event-line/types.ts +0 -74
  110. package/src/fonts.ts +0 -3
  111. package/src/gantt/calculator.ts +0 -979
  112. package/src/gantt/parser.ts +0 -1641
  113. package/src/gantt/renderer.ts +0 -3787
  114. package/src/gantt/resolver.ts +0 -172
  115. package/src/gantt/types.ts +0 -206
  116. package/src/graph/diagnostics.ts +0 -64
  117. package/src/graph/edge-spline.ts +0 -29
  118. package/src/graph/flowchart-parser.ts +0 -759
  119. package/src/graph/flowchart-renderer.ts +0 -817
  120. package/src/graph/layout.ts +0 -472
  121. package/src/graph/notes.ts +0 -21
  122. package/src/graph/state-collapse.ts +0 -78
  123. package/src/graph/state-parser.ts +0 -574
  124. package/src/graph/state-renderer.ts +0 -653
  125. package/src/graph/types.ts +0 -65
  126. package/src/index.ts +0 -261
  127. package/src/infra/compute.ts +0 -1385
  128. package/src/infra/layout.ts +0 -888
  129. package/src/infra/parser.ts +0 -1234
  130. package/src/infra/renderer.ts +0 -2534
  131. package/src/infra/roles.ts +0 -75
  132. package/src/infra/types.ts +0 -216
  133. package/src/infra/validation.ts +0 -201
  134. package/src/journey-map/layout.ts +0 -490
  135. package/src/journey-map/parser.ts +0 -557
  136. package/src/journey-map/renderer.ts +0 -1580
  137. package/src/journey-map/types.ts +0 -47
  138. package/src/kanban/mutations.ts +0 -175
  139. package/src/kanban/parser.ts +0 -509
  140. package/src/kanban/renderer.ts +0 -1449
  141. package/src/kanban/types.ts +0 -39
  142. package/src/label-layout.ts +0 -368
  143. package/src/map/colorize.ts +0 -54
  144. package/src/map/completion.ts +0 -316
  145. package/src/map/context-labels.ts +0 -609
  146. package/src/map/data/PROVENANCE.json +0 -1
  147. package/src/map/data/README.md +0 -40
  148. package/src/map/data/airport-collisions.json +0 -1
  149. package/src/map/data/airports.json +0 -1
  150. package/src/map/data/gazetteer.json +0 -1
  151. package/src/map/data/lakes.json +0 -1
  152. package/src/map/data/mountain-ranges.json +0 -1
  153. package/src/map/data/na-lakes.json +0 -1
  154. package/src/map/data/na-land.json +0 -1
  155. package/src/map/data/region-names.json +0 -1
  156. package/src/map/data/rivers.json +0 -1
  157. package/src/map/data/types.ts +0 -121
  158. package/src/map/data/us-states.json +0 -1
  159. package/src/map/data/water-bodies.json +0 -1
  160. package/src/map/data/world-coarse.json +0 -1
  161. package/src/map/data/world-detail.json +0 -1
  162. package/src/map/diagnostics.ts +0 -134
  163. package/src/map/dimensions.ts +0 -150
  164. package/src/map/geo-query.ts +0 -295
  165. package/src/map/geo.ts +0 -438
  166. package/src/map/invert.ts +0 -111
  167. package/src/map/layout.ts +0 -5069
  168. package/src/map/legend-band.ts +0 -127
  169. package/src/map/load-data.ts +0 -186
  170. package/src/map/parser.ts +0 -783
  171. package/src/map/renderer.ts +0 -1445
  172. package/src/map/resolved-types.ts +0 -160
  173. package/src/map/resolver.ts +0 -1146
  174. package/src/map/types.ts +0 -194
  175. package/src/mindmap/collapse.ts +0 -67
  176. package/src/mindmap/layout.ts +0 -649
  177. package/src/mindmap/parser.ts +0 -430
  178. package/src/mindmap/renderer.ts +0 -637
  179. package/src/mindmap/text-wrap.ts +0 -218
  180. package/src/mindmap/types.ts +0 -56
  181. package/src/org/collapse.ts +0 -151
  182. package/src/org/layout.ts +0 -1262
  183. package/src/org/parser.ts +0 -519
  184. package/src/org/renderer.ts +0 -866
  185. package/src/org/resolver.ts +0 -636
  186. package/src/palettes/atlas.ts +0 -77
  187. package/src/palettes/blueprint.ts +0 -73
  188. package/src/palettes/catppuccin.ts +0 -84
  189. package/src/palettes/color-utils.ts +0 -443
  190. package/src/palettes/index.ts +0 -67
  191. package/src/palettes/nord.ts +0 -67
  192. package/src/palettes/registry.ts +0 -114
  193. package/src/palettes/slate.ts +0 -73
  194. package/src/palettes/tidewater.ts +0 -73
  195. package/src/palettes/tokyo-night.ts +0 -86
  196. package/src/palettes/types.ts +0 -88
  197. package/src/pert/analyzer.ts +0 -1183
  198. package/src/pert/diagnostics.ts +0 -110
  199. package/src/pert/index.ts +0 -43
  200. package/src/pert/internal.ts +0 -252
  201. package/src/pert/layout.ts +0 -971
  202. package/src/pert/monte-carlo.ts +0 -446
  203. package/src/pert/parser.ts +0 -1606
  204. package/src/pert/renderer.ts +0 -4009
  205. package/src/pert/share-normalize.ts +0 -62
  206. package/src/pert/types.ts +0 -604
  207. package/src/pyramid/parser.ts +0 -185
  208. package/src/pyramid/renderer.ts +0 -768
  209. package/src/pyramid/types.ts +0 -28
  210. package/src/quadrant/parser.ts +0 -18
  211. package/src/quadrant/renderer.ts +0 -638
  212. package/src/raci/diagnostics.ts +0 -213
  213. package/src/raci/index.ts +0 -23
  214. package/src/raci/mutations.ts +0 -321
  215. package/src/raci/parser.ts +0 -699
  216. package/src/raci/renderer.ts +0 -1627
  217. package/src/raci/types.ts +0 -82
  218. package/src/raci/variants.ts +0 -320
  219. package/src/render.ts +0 -268
  220. package/src/ring/parser.ts +0 -212
  221. package/src/ring/renderer.ts +0 -490
  222. package/src/ring/types.ts +0 -27
  223. package/src/sequence/collapse.ts +0 -174
  224. package/src/sequence/parser.ts +0 -1596
  225. package/src/sequence/participant-inference.ts +0 -152
  226. package/src/sequence/renderer.ts +0 -3168
  227. package/src/sequence/tag-resolution.ts +0 -164
  228. package/src/sharing.ts +0 -211
  229. package/src/sitemap/collapse.ts +0 -100
  230. package/src/sitemap/layout.ts +0 -925
  231. package/src/sitemap/parser.ts +0 -755
  232. package/src/sitemap/renderer.ts +0 -828
  233. package/src/sitemap/types.ts +0 -42
  234. package/src/slope/parser.ts +0 -18
  235. package/src/slope/renderer.ts +0 -378
  236. package/src/swimlane/diagnostics.ts +0 -94
  237. package/src/swimlane/layout.ts +0 -597
  238. package/src/swimlane/parser.ts +0 -613
  239. package/src/swimlane/renderer.ts +0 -681
  240. package/src/swimlane/types.ts +0 -151
  241. package/src/tech-radar/interactive.ts +0 -1129
  242. package/src/tech-radar/layout.ts +0 -197
  243. package/src/tech-radar/parser.ts +0 -436
  244. package/src/tech-radar/renderer.ts +0 -1239
  245. package/src/tech-radar/shared.ts +0 -151
  246. package/src/tech-radar/types.ts +0 -86
  247. package/src/themes.ts +0 -22
  248. package/src/timeline/parser.ts +0 -472
  249. package/src/timeline/renderer.ts +0 -3024
  250. package/src/timeline/types.ts +0 -33
  251. package/src/timeline/viz-parser.ts +0 -21
  252. package/src/treemap/diagnostics.ts +0 -62
  253. package/src/treemap/layout-radial.ts +0 -233
  254. package/src/treemap/layout.ts +0 -189
  255. package/src/treemap/parser.ts +0 -463
  256. package/src/treemap/renderer-radial.ts +0 -438
  257. package/src/treemap/renderer.ts +0 -572
  258. package/src/treemap/treemap-shared.ts +0 -309
  259. package/src/treemap/types.ts +0 -60
  260. package/src/utils/arrow-markers.ts +0 -51
  261. package/src/utils/arrows-diagnostics.ts +0 -62
  262. package/src/utils/arrows.ts +0 -227
  263. package/src/utils/brand.ts +0 -61
  264. package/src/utils/card.ts +0 -183
  265. package/src/utils/collapse-engine/tree-edges.ts +0 -115
  266. package/src/utils/collapse-engine/tree.ts +0 -117
  267. package/src/utils/d3-helpers.ts +0 -219
  268. package/src/utils/d3-types.ts +0 -9
  269. package/src/utils/description-helpers.ts +0 -38
  270. package/src/utils/duration.ts +0 -312
  271. package/src/utils/export-container.ts +0 -41
  272. package/src/utils/expr-eval.ts +0 -27
  273. package/src/utils/fit-canvas.ts +0 -64
  274. package/src/utils/hover-styles.ts +0 -673
  275. package/src/utils/inline-markdown.ts +0 -96
  276. package/src/utils/legend-constants.ts +0 -48
  277. package/src/utils/legend-d3.ts +0 -618
  278. package/src/utils/legend-integration.ts +0 -107
  279. package/src/utils/legend-layout.ts +0 -776
  280. package/src/utils/legend-svg.ts +0 -214
  281. package/src/utils/legend-types.ts +0 -272
  282. package/src/utils/name-normalize.ts +0 -163
  283. package/src/utils/note-box/constants.ts +0 -25
  284. package/src/utils/note-box/index.ts +0 -11
  285. package/src/utils/note-box/metrics.ts +0 -90
  286. package/src/utils/note-box/svg.ts +0 -331
  287. package/src/utils/notes/bounds.ts +0 -30
  288. package/src/utils/notes/build.ts +0 -131
  289. package/src/utils/notes/index.ts +0 -18
  290. package/src/utils/notes/model.ts +0 -19
  291. package/src/utils/notes/parse.ts +0 -131
  292. package/src/utils/notes/place.ts +0 -177
  293. package/src/utils/notes/resolve.ts +0 -88
  294. package/src/utils/number-format.ts +0 -36
  295. package/src/utils/parsing.ts +0 -953
  296. package/src/utils/reserved-key-registry.ts +0 -239
  297. package/src/utils/safe-href.ts +0 -38
  298. package/src/utils/scaling.ts +0 -97
  299. package/src/utils/svg-embed.ts +0 -251
  300. package/src/utils/tag-groups.ts +0 -607
  301. package/src/utils/text-measure.ts +0 -122
  302. package/src/utils/time-ticks.ts +0 -253
  303. package/src/utils/title-constants.ts +0 -24
  304. package/src/utils/visual-conventions.ts +0 -61
  305. package/src/utils/wrapped-desc.ts +0 -87
  306. package/src/venn/parser.ts +0 -18
  307. package/src/venn/renderer.ts +0 -1047
  308. package/src/version-control/diagnostics.ts +0 -67
  309. package/src/version-control/parser.ts +0 -544
  310. package/src/version-control/renderer.ts +0 -724
  311. package/src/version-control/types.ts +0 -100
  312. package/src/visualizations/parse.ts +0 -1560
  313. package/src/visualizations/types.ts +0 -262
  314. package/src/wireframe/layout.ts +0 -479
  315. package/src/wireframe/parser.ts +0 -1114
  316. package/src/wireframe/renderer.ts +0 -1318
  317. package/src/wireframe/types.ts +0 -110
  318. package/src/wordcloud/parser.ts +0 -18
  319. 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);