@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.
- package/dist/advanced.js +11 -11
- package/dist/auto.js +16 -16
- package/dist/auto.mjs +41 -12
- package/dist/block.js +4 -4
- package/dist/{chunk-FNB3PNGF.js → chunk-7DTWEFUE.js} +3 -3
- package/dist/{chunk-2DXMZRWJ.js → chunk-B65G5DNL.js} +8 -1
- package/dist/{chunk-RZCF2VVM.js → chunk-B7JUCQUA.js} +3 -1
- package/dist/{chunk-DU7W62N5.js → chunk-FANX6UJR.js} +3 -3
- package/dist/{chunk-6FZYCKXB.js → chunk-HSH73DP6.js} +2 -2
- package/dist/{chunk-P4RH4OSP.js → chunk-ILKORZ3H.js} +2 -2
- package/dist/{chunk-Y5QGVTVC.js → chunk-JTSMEYIZ.js} +7 -3
- package/dist/{chunk-RCERWOJR.js → chunk-ODZVHU3R.js} +1 -2
- package/dist/{chunk-DZAQBW35.js → chunk-SGZYXELT.js} +3 -7
- package/dist/{chunk-CUVHQHZ7.js → chunk-THXCFRTU.js} +3 -3
- package/dist/{chunk-IH6ZMVQ5.js → chunk-UC7TFHUM.js} +29 -11
- package/dist/{chunk-EMS2SK26.js → chunk-ZBWMSD5N.js} +3 -1
- package/dist/cli.cjs +15 -15
- package/dist/{dgmo-router-DZCIDUO5.js → dgmo-router-X35VLZLM.js} +3 -3
- package/dist/element.js +16 -16
- package/dist/element.mjs +41 -12
- package/dist/{flowchart-renderer-ZAEOL4DX.js → flowchart-renderer-SNDSII4D.js} +2 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +4 -4
- package/dist/{parser-FUSKFGZN.js → parser-2EWECDSA.js} +2 -2
- package/dist/{renderer-UWA5XS74.js → renderer-4JHRUBE6.js} +3 -3
- package/dist/{renderer-WZRREQ2P.js → renderer-5MYBMBYO.js} +2 -2
- package/dist/{renderer-TOCOVLHS.js → renderer-B2OMQIQG.js} +3 -3
- package/dist/{renderer-2XQQQ6QR.js → renderer-N43WR5GV.js} +3 -3
- package/dist/{renderer-T7YKC5VP.js → renderer-ZRNG54CW.js} +3 -3
- package/dist/{state-renderer-RFYHSP4K.js → state-renderer-B4DQBM6M.js} +2 -2
- package/package.json +23 -71
- package/dist/advanced.cjs +0 -71648
- package/dist/advanced.d.cts +0 -5719
- package/dist/auto.cjs +0 -70648
- package/dist/auto.d.cts +0 -54
- package/dist/block.cjs +0 -70208
- package/dist/block.d.cts +0 -115
- package/dist/editor.cjs +0 -526
- package/dist/editor.d.cts +0 -26
- package/dist/element.cjs +0 -70530
- package/dist/element.d.cts +0 -62
- package/dist/highlight.cjs +0 -852
- package/dist/highlight.d.cts +0 -49
- package/dist/index.cjs +0 -70491
- package/dist/index.d.cts +0 -160
- package/dist/pert.cjs +0 -325
- package/dist/pert.d.cts +0 -559
- package/dist/themes-1-CuKpeH.d.cts +0 -908
- package/src/advanced.ts +0 -873
- package/src/arc/parser.ts +0 -15
- package/src/arc/renderer.ts +0 -633
- package/src/auto/index.ts +0 -621
- package/src/auto/shared.ts +0 -370
- package/src/auto/styles.ts +0 -73
- package/src/block/layout.ts +0 -198
- package/src/block/parser.ts +0 -427
- package/src/block/renderer.ts +0 -484
- package/src/block/types.ts +0 -67
- package/src/boxes-and-lines/collapse.ts +0 -96
- package/src/boxes-and-lines/focus.ts +0 -257
- package/src/boxes-and-lines/label-placement.ts +0 -339
- package/src/boxes-and-lines/layout-grouped.ts +0 -912
- package/src/boxes-and-lines/layout-layered.ts +0 -722
- package/src/boxes-and-lines/layout-search.ts +0 -1678
- package/src/boxes-and-lines/layout.ts +0 -398
- package/src/boxes-and-lines/parser.ts +0 -1181
- package/src/boxes-and-lines/renderer.ts +0 -1465
- package/src/boxes-and-lines/types.ts +0 -66
- package/src/c4/layout.ts +0 -2441
- package/src/c4/parser.ts +0 -1158
- package/src/c4/renderer.ts +0 -2008
- package/src/c4/types.ts +0 -89
- package/src/chart-type-registry.ts +0 -529
- package/src/chart-types.ts +0 -225
- package/src/chart.ts +0 -685
- package/src/charts-d3/bar.ts +0 -338
- package/src/charts-d3/chord.ts +0 -140
- package/src/charts-d3/function.ts +0 -147
- package/src/charts-d3/funnel.ts +0 -104
- package/src/charts-d3/heatmap.ts +0 -145
- package/src/charts-d3/index.ts +0 -337
- package/src/charts-d3/interactions.ts +0 -477
- package/src/charts-d3/line.ts +0 -344
- package/src/charts-d3/mount.ts +0 -151
- package/src/charts-d3/pie.ts +0 -117
- package/src/charts-d3/polar.ts +0 -89
- package/src/charts-d3/radar.ts +0 -0
- package/src/charts-d3/sankey.ts +0 -0
- package/src/charts-d3/scatter.ts +0 -185
- package/src/charts-d3/shared.ts +0 -208
- package/src/class/layout.ts +0 -326
- package/src/class/parser.ts +0 -635
- package/src/class/renderer.ts +0 -793
- package/src/class/types.ts +0 -58
- package/src/cli-banner.ts +0 -106
- package/src/cli.ts +0 -1080
- package/src/colors-diagnostics.ts +0 -35
- package/src/colors.ts +0 -379
- package/src/completion-types.ts +0 -27
- package/src/completion.ts +0 -2668
- package/src/cycle/layout.ts +0 -1026
- package/src/cycle/parser.ts +0 -387
- package/src/cycle/renderer.ts +0 -653
- package/src/cycle/types.ts +0 -101
- package/src/d3.ts +0 -1434
- package/src/data-chart-parser.ts +0 -1007
- package/src/dgmo-router.ts +0 -296
- package/src/diagnostics-registry.ts +0 -108
- package/src/diagnostics.ts +0 -0
- package/src/dimensions.ts +0 -20
- package/src/directives-registry.ts +0 -396
- package/src/editor/dgmo.grammar +0 -76
- package/src/editor/dgmo.grammar.d.ts +0 -2
- package/src/editor/dgmo.grammar.js +0 -18
- package/src/editor/dgmo.grammar.terms.d.ts +0 -5
- package/src/editor/dgmo.grammar.terms.js +0 -35
- package/src/editor/highlight-api.ts +0 -596
- package/src/editor/highlight.ts +0 -36
- package/src/editor/index.ts +0 -27
- package/src/editor/keywords.ts +0 -128
- package/src/editor/tokens.ts +0 -30
- package/src/element/index.ts +0 -432
- package/src/embed/css.ts +0 -312
- package/src/embed/escape.ts +0 -15
- package/src/embed/index.ts +0 -280
- package/src/er/classify.ts +0 -228
- package/src/er/layout.ts +0 -530
- package/src/er/parser.ts +0 -750
- package/src/er/renderer.ts +0 -725
- package/src/er/types.ts +0 -52
- package/src/error-card.ts +0 -269
- package/src/event-line/diagnostics.ts +0 -117
- package/src/event-line/parser.ts +0 -643
- package/src/event-line/renderer.ts +0 -1742
- package/src/event-line/types.ts +0 -74
- package/src/fonts.ts +0 -3
- package/src/gantt/calculator.ts +0 -979
- package/src/gantt/parser.ts +0 -1641
- package/src/gantt/renderer.ts +0 -3787
- package/src/gantt/resolver.ts +0 -172
- package/src/gantt/types.ts +0 -206
- package/src/graph/diagnostics.ts +0 -64
- package/src/graph/edge-spline.ts +0 -29
- package/src/graph/flowchart-parser.ts +0 -759
- package/src/graph/flowchart-renderer.ts +0 -817
- package/src/graph/layout.ts +0 -472
- package/src/graph/notes.ts +0 -21
- package/src/graph/state-collapse.ts +0 -78
- package/src/graph/state-parser.ts +0 -574
- package/src/graph/state-renderer.ts +0 -653
- package/src/graph/types.ts +0 -65
- package/src/index.ts +0 -261
- package/src/infra/compute.ts +0 -1385
- package/src/infra/layout.ts +0 -888
- package/src/infra/parser.ts +0 -1234
- package/src/infra/renderer.ts +0 -2534
- package/src/infra/roles.ts +0 -75
- package/src/infra/types.ts +0 -216
- package/src/infra/validation.ts +0 -201
- package/src/journey-map/layout.ts +0 -490
- package/src/journey-map/parser.ts +0 -557
- package/src/journey-map/renderer.ts +0 -1580
- package/src/journey-map/types.ts +0 -47
- package/src/kanban/mutations.ts +0 -175
- package/src/kanban/parser.ts +0 -509
- package/src/kanban/renderer.ts +0 -1449
- package/src/kanban/types.ts +0 -39
- package/src/label-layout.ts +0 -368
- package/src/map/colorize.ts +0 -54
- package/src/map/completion.ts +0 -316
- package/src/map/context-labels.ts +0 -609
- package/src/map/data/PROVENANCE.json +0 -1
- package/src/map/data/README.md +0 -40
- package/src/map/data/airport-collisions.json +0 -1
- package/src/map/data/airports.json +0 -1
- package/src/map/data/gazetteer.json +0 -1
- package/src/map/data/lakes.json +0 -1
- package/src/map/data/mountain-ranges.json +0 -1
- package/src/map/data/na-lakes.json +0 -1
- package/src/map/data/na-land.json +0 -1
- package/src/map/data/region-names.json +0 -1
- package/src/map/data/rivers.json +0 -1
- package/src/map/data/types.ts +0 -121
- package/src/map/data/us-states.json +0 -1
- package/src/map/data/water-bodies.json +0 -1
- package/src/map/data/world-coarse.json +0 -1
- package/src/map/data/world-detail.json +0 -1
- package/src/map/diagnostics.ts +0 -134
- package/src/map/dimensions.ts +0 -150
- package/src/map/geo-query.ts +0 -295
- package/src/map/geo.ts +0 -438
- package/src/map/invert.ts +0 -111
- package/src/map/layout.ts +0 -5069
- package/src/map/legend-band.ts +0 -127
- package/src/map/load-data.ts +0 -186
- package/src/map/parser.ts +0 -783
- package/src/map/renderer.ts +0 -1445
- package/src/map/resolved-types.ts +0 -160
- package/src/map/resolver.ts +0 -1146
- package/src/map/types.ts +0 -194
- package/src/mindmap/collapse.ts +0 -67
- package/src/mindmap/layout.ts +0 -649
- package/src/mindmap/parser.ts +0 -430
- package/src/mindmap/renderer.ts +0 -637
- package/src/mindmap/text-wrap.ts +0 -218
- package/src/mindmap/types.ts +0 -56
- package/src/org/collapse.ts +0 -151
- package/src/org/layout.ts +0 -1262
- package/src/org/parser.ts +0 -519
- package/src/org/renderer.ts +0 -866
- package/src/org/resolver.ts +0 -636
- package/src/palettes/atlas.ts +0 -77
- package/src/palettes/blueprint.ts +0 -73
- package/src/palettes/catppuccin.ts +0 -84
- package/src/palettes/color-utils.ts +0 -443
- package/src/palettes/index.ts +0 -67
- package/src/palettes/nord.ts +0 -67
- package/src/palettes/registry.ts +0 -114
- package/src/palettes/slate.ts +0 -73
- package/src/palettes/tidewater.ts +0 -73
- package/src/palettes/tokyo-night.ts +0 -86
- package/src/palettes/types.ts +0 -88
- package/src/pert/analyzer.ts +0 -1183
- package/src/pert/diagnostics.ts +0 -110
- package/src/pert/index.ts +0 -43
- package/src/pert/internal.ts +0 -252
- package/src/pert/layout.ts +0 -971
- package/src/pert/monte-carlo.ts +0 -446
- package/src/pert/parser.ts +0 -1606
- package/src/pert/renderer.ts +0 -4009
- package/src/pert/share-normalize.ts +0 -62
- package/src/pert/types.ts +0 -604
- package/src/pyramid/parser.ts +0 -185
- package/src/pyramid/renderer.ts +0 -768
- package/src/pyramid/types.ts +0 -28
- package/src/quadrant/parser.ts +0 -18
- package/src/quadrant/renderer.ts +0 -638
- package/src/raci/diagnostics.ts +0 -213
- package/src/raci/index.ts +0 -23
- package/src/raci/mutations.ts +0 -321
- package/src/raci/parser.ts +0 -699
- package/src/raci/renderer.ts +0 -1627
- package/src/raci/types.ts +0 -82
- package/src/raci/variants.ts +0 -320
- package/src/render.ts +0 -268
- package/src/ring/parser.ts +0 -212
- package/src/ring/renderer.ts +0 -490
- package/src/ring/types.ts +0 -27
- package/src/sequence/collapse.ts +0 -174
- package/src/sequence/parser.ts +0 -1596
- package/src/sequence/participant-inference.ts +0 -152
- package/src/sequence/renderer.ts +0 -3168
- package/src/sequence/tag-resolution.ts +0 -164
- package/src/sharing.ts +0 -211
- package/src/sitemap/collapse.ts +0 -100
- package/src/sitemap/layout.ts +0 -925
- package/src/sitemap/parser.ts +0 -755
- package/src/sitemap/renderer.ts +0 -828
- package/src/sitemap/types.ts +0 -42
- package/src/slope/parser.ts +0 -18
- package/src/slope/renderer.ts +0 -378
- package/src/swimlane/diagnostics.ts +0 -94
- package/src/swimlane/layout.ts +0 -597
- package/src/swimlane/parser.ts +0 -613
- package/src/swimlane/renderer.ts +0 -681
- package/src/swimlane/types.ts +0 -151
- package/src/tech-radar/interactive.ts +0 -1129
- package/src/tech-radar/layout.ts +0 -197
- package/src/tech-radar/parser.ts +0 -436
- package/src/tech-radar/renderer.ts +0 -1239
- package/src/tech-radar/shared.ts +0 -151
- package/src/tech-radar/types.ts +0 -86
- package/src/themes.ts +0 -22
- package/src/timeline/parser.ts +0 -472
- package/src/timeline/renderer.ts +0 -3024
- package/src/timeline/types.ts +0 -33
- package/src/timeline/viz-parser.ts +0 -21
- package/src/treemap/diagnostics.ts +0 -62
- package/src/treemap/layout-radial.ts +0 -233
- package/src/treemap/layout.ts +0 -189
- package/src/treemap/parser.ts +0 -463
- package/src/treemap/renderer-radial.ts +0 -438
- package/src/treemap/renderer.ts +0 -572
- package/src/treemap/treemap-shared.ts +0 -309
- package/src/treemap/types.ts +0 -60
- package/src/utils/arrow-markers.ts +0 -51
- package/src/utils/arrows-diagnostics.ts +0 -62
- package/src/utils/arrows.ts +0 -227
- package/src/utils/brand.ts +0 -61
- package/src/utils/card.ts +0 -183
- package/src/utils/collapse-engine/tree-edges.ts +0 -115
- package/src/utils/collapse-engine/tree.ts +0 -117
- package/src/utils/d3-helpers.ts +0 -219
- package/src/utils/d3-types.ts +0 -9
- package/src/utils/description-helpers.ts +0 -38
- package/src/utils/duration.ts +0 -312
- package/src/utils/export-container.ts +0 -41
- package/src/utils/expr-eval.ts +0 -27
- package/src/utils/fit-canvas.ts +0 -64
- package/src/utils/hover-styles.ts +0 -673
- package/src/utils/inline-markdown.ts +0 -96
- package/src/utils/legend-constants.ts +0 -48
- package/src/utils/legend-d3.ts +0 -618
- package/src/utils/legend-integration.ts +0 -107
- package/src/utils/legend-layout.ts +0 -776
- package/src/utils/legend-svg.ts +0 -214
- package/src/utils/legend-types.ts +0 -272
- package/src/utils/name-normalize.ts +0 -163
- package/src/utils/note-box/constants.ts +0 -25
- package/src/utils/note-box/index.ts +0 -11
- package/src/utils/note-box/metrics.ts +0 -90
- package/src/utils/note-box/svg.ts +0 -331
- package/src/utils/notes/bounds.ts +0 -30
- package/src/utils/notes/build.ts +0 -131
- package/src/utils/notes/index.ts +0 -18
- package/src/utils/notes/model.ts +0 -19
- package/src/utils/notes/parse.ts +0 -131
- package/src/utils/notes/place.ts +0 -177
- package/src/utils/notes/resolve.ts +0 -88
- package/src/utils/number-format.ts +0 -36
- package/src/utils/parsing.ts +0 -953
- package/src/utils/reserved-key-registry.ts +0 -239
- package/src/utils/safe-href.ts +0 -38
- package/src/utils/scaling.ts +0 -97
- package/src/utils/svg-embed.ts +0 -251
- package/src/utils/tag-groups.ts +0 -607
- package/src/utils/text-measure.ts +0 -122
- package/src/utils/time-ticks.ts +0 -253
- package/src/utils/title-constants.ts +0 -24
- package/src/utils/visual-conventions.ts +0 -61
- package/src/utils/wrapped-desc.ts +0 -87
- package/src/venn/parser.ts +0 -18
- package/src/venn/renderer.ts +0 -1047
- package/src/version-control/diagnostics.ts +0 -67
- package/src/version-control/parser.ts +0 -544
- package/src/version-control/renderer.ts +0 -724
- package/src/version-control/types.ts +0 -100
- package/src/visualizations/parse.ts +0 -1560
- package/src/visualizations/types.ts +0 -262
- package/src/wireframe/layout.ts +0 -479
- package/src/wireframe/parser.ts +0 -1114
- package/src/wireframe/renderer.ts +0 -1318
- package/src/wireframe/types.ts +0 -110
- package/src/wordcloud/parser.ts +0 -18
- package/src/wordcloud/renderer.ts +0 -357
package/src/org/resolver.ts
DELETED
|
@@ -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
|
-
}
|
package/src/palettes/atlas.ts
DELETED
|
@@ -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);
|