@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/cycle/parser.ts
DELETED
|
@@ -1,387 +0,0 @@
|
|
|
1
|
-
// ============================================================
|
|
2
|
-
// Cycle Diagram — Parser
|
|
3
|
-
// ============================================================
|
|
4
|
-
|
|
5
|
-
import { makeDgmoError, makeFail } from '../diagnostics';
|
|
6
|
-
import {
|
|
7
|
-
measureIndent,
|
|
8
|
-
parseFirstLine,
|
|
9
|
-
splitNameAndMeta,
|
|
10
|
-
tryParseSharedOption,
|
|
11
|
-
warnUnknownMetaKeys,
|
|
12
|
-
} from '../utils/parsing';
|
|
13
|
-
import { CYCLE_REGISTRY } from '../utils/reserved-key-registry';
|
|
14
|
-
import type { Writable } from '../utils/brand';
|
|
15
|
-
import type { ParsedCycle, CycleNode, CycleEdge } from './types';
|
|
16
|
-
|
|
17
|
-
// ── Edge pattern: `->`, `-label->` with optional target tail ──
|
|
18
|
-
// Bare: `-> [Target] [meta]`
|
|
19
|
-
const BARE_EDGE_RE = /^->\s*(.*)?$/;
|
|
20
|
-
// Labeled: `-Label-> [Target] [meta]`
|
|
21
|
-
const LABELED_EDGE_RE = /^-(.+?)->\s*(.*)?$/;
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Parse a `.dgmo` cycle diagram document.
|
|
25
|
-
*
|
|
26
|
-
* Syntax (§1.4 unified metadata grammar):
|
|
27
|
-
* ```
|
|
28
|
-
* cycle Title
|
|
29
|
-
*
|
|
30
|
-
* direction-counterclockwise
|
|
31
|
-
*
|
|
32
|
-
* NodeLabel color: blue, span: 3
|
|
33
|
-
* Description line (indented under node)
|
|
34
|
-
* -Label-> color: red, width: 6
|
|
35
|
-
* Edge description (indented under edge)
|
|
36
|
-
* ```
|
|
37
|
-
*/
|
|
38
|
-
export function parseCycle(content: string): ParsedCycle {
|
|
39
|
-
const options: Record<string, string> = {};
|
|
40
|
-
const result: Writable<ParsedCycle> = {
|
|
41
|
-
type: 'cycle',
|
|
42
|
-
title: '',
|
|
43
|
-
titleLineNumber: 0,
|
|
44
|
-
nodes: [],
|
|
45
|
-
edges: [],
|
|
46
|
-
direction: 'clockwise',
|
|
47
|
-
options,
|
|
48
|
-
diagnostics: [],
|
|
49
|
-
error: null,
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
const lines = content.split('\n');
|
|
53
|
-
let headerParsed = false;
|
|
54
|
-
|
|
55
|
-
// State machine
|
|
56
|
-
type State = 'top' | 'node' | 'edge';
|
|
57
|
-
let state: State = 'top';
|
|
58
|
-
let currentNode: Writable<CycleNode> | null = null;
|
|
59
|
-
let currentEdge: Writable<CycleEdge> | null = null;
|
|
60
|
-
// nodeBaseIndent tracking removed — indent-based nesting not used in cycle
|
|
61
|
-
|
|
62
|
-
const fail = makeFail(result);
|
|
63
|
-
|
|
64
|
-
const warn = (
|
|
65
|
-
line: number,
|
|
66
|
-
message: string,
|
|
67
|
-
severity: 'warning' | 'error' = 'warning'
|
|
68
|
-
): void => {
|
|
69
|
-
result.diagnostics.push(makeDgmoError(line, message, severity));
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
const info = (line: number, message: string): void => {
|
|
73
|
-
result.diagnostics.push(makeDgmoError(line, message, 'warning'));
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
function flushEdge(): void {
|
|
77
|
-
if (currentEdge) {
|
|
78
|
-
result.edges.push(currentEdge);
|
|
79
|
-
currentEdge = null;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function flushNode(): void {
|
|
84
|
-
flushEdge();
|
|
85
|
-
if (currentNode) {
|
|
86
|
-
result.nodes.push(currentNode);
|
|
87
|
-
currentNode = null;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
for (let i = 0; i < lines.length; i++) {
|
|
92
|
-
const lineNum = i + 1;
|
|
93
|
-
// In-bounds by loop guard.
|
|
94
|
-
const raw = lines[i]!;
|
|
95
|
-
const trimmed = raw.trim();
|
|
96
|
-
|
|
97
|
-
// Skip blanks and comments
|
|
98
|
-
if (!trimmed || trimmed.startsWith('//')) continue;
|
|
99
|
-
|
|
100
|
-
const indent = measureIndent(raw);
|
|
101
|
-
|
|
102
|
-
// ── First line: chart type declaration ──
|
|
103
|
-
if (!headerParsed) {
|
|
104
|
-
const firstLineResult = parseFirstLine(trimmed);
|
|
105
|
-
if (firstLineResult?.chartType === 'cycle') {
|
|
106
|
-
result.title = firstLineResult.title ?? '';
|
|
107
|
-
result.titleLineNumber = lineNum;
|
|
108
|
-
headerParsed = true;
|
|
109
|
-
continue;
|
|
110
|
-
}
|
|
111
|
-
return fail(lineNum, 'Expected "cycle [Title]" as the first line.');
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// ── Directive: direction-counterclockwise ──
|
|
115
|
-
if (indent === 0 && trimmed === 'direction-counterclockwise') {
|
|
116
|
-
result.direction = 'counterclockwise';
|
|
117
|
-
continue;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (indent === 0 && trimmed.toLowerCase() === 'no-descriptions') {
|
|
121
|
-
warn(
|
|
122
|
-
lineNum,
|
|
123
|
-
'"no-descriptions" has been removed — delete description lines from your source instead.'
|
|
124
|
-
);
|
|
125
|
-
continue;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// ── Bare keyword: circle-nodes ──
|
|
129
|
-
if (indent === 0 && trimmed.toLowerCase() === 'circle-nodes') {
|
|
130
|
-
options['circle-nodes'] = 'true';
|
|
131
|
-
continue;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// ── Shared bare keyword: solid-fill ──
|
|
135
|
-
if (indent === 0 && tryParseSharedOption(trimmed, options)) {
|
|
136
|
-
continue;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// ── Top-level line (indent === 0): must be a node declaration ──
|
|
140
|
-
if (indent === 0) {
|
|
141
|
-
flushNode();
|
|
142
|
-
|
|
143
|
-
// Validate: node labels cannot contain -> or <-
|
|
144
|
-
if (trimmed.includes('->') || trimmed.includes('<-')) {
|
|
145
|
-
warn(
|
|
146
|
-
lineNum,
|
|
147
|
-
'Node labels cannot contain "->". Use indented lines for edges.',
|
|
148
|
-
'error'
|
|
149
|
-
);
|
|
150
|
-
continue;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// §1.4 unified metadata grammar — same-line cut.
|
|
154
|
-
const split = splitNameAndMeta(
|
|
155
|
-
trimmed,
|
|
156
|
-
CYCLE_REGISTRY,
|
|
157
|
-
new Map(),
|
|
158
|
-
undefined,
|
|
159
|
-
result.diagnostics,
|
|
160
|
-
lineNum
|
|
161
|
-
);
|
|
162
|
-
warnUnknownMetaKeys(
|
|
163
|
-
split.meta,
|
|
164
|
-
CYCLE_REGISTRY,
|
|
165
|
-
(msg) => warn(lineNum, msg),
|
|
166
|
-
split.name
|
|
167
|
-
);
|
|
168
|
-
const label = split.name;
|
|
169
|
-
const metadata: Record<string, string> = { ...split.meta };
|
|
170
|
-
if (split.color !== undefined) metadata['color'] = split.color;
|
|
171
|
-
|
|
172
|
-
if (!label) {
|
|
173
|
-
warn(lineNum, 'Empty node label.');
|
|
174
|
-
continue;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// Extract known keys from metadata
|
|
178
|
-
const color = metadata['color'];
|
|
179
|
-
const spanStr = metadata['span'];
|
|
180
|
-
let span = 1;
|
|
181
|
-
if (spanStr !== undefined) {
|
|
182
|
-
const spanVal = parseFloat(spanStr);
|
|
183
|
-
if (isNaN(spanVal) || spanVal <= 0) {
|
|
184
|
-
warn(
|
|
185
|
-
lineNum,
|
|
186
|
-
`span must be a positive number, got "${spanStr}".`,
|
|
187
|
-
'error'
|
|
188
|
-
);
|
|
189
|
-
continue;
|
|
190
|
-
}
|
|
191
|
-
span = spanVal;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const descFromPipe = metadata['description'];
|
|
195
|
-
const description: string[] = descFromPipe ? [descFromPipe] : [];
|
|
196
|
-
|
|
197
|
-
// Remove known keys from metadata passthrough
|
|
198
|
-
const restMeta = { ...metadata };
|
|
199
|
-
delete restMeta['color'];
|
|
200
|
-
delete restMeta['span'];
|
|
201
|
-
delete restMeta['description'];
|
|
202
|
-
|
|
203
|
-
currentNode = {
|
|
204
|
-
label,
|
|
205
|
-
lineNumber: lineNum,
|
|
206
|
-
...(color !== undefined && { color }),
|
|
207
|
-
span,
|
|
208
|
-
description,
|
|
209
|
-
metadata: restMeta,
|
|
210
|
-
};
|
|
211
|
-
state = 'node';
|
|
212
|
-
continue;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// ── Indented lines ──
|
|
216
|
-
if (indent > 0) {
|
|
217
|
-
// Check for edge pattern: -> or -label->
|
|
218
|
-
const bareMatch = trimmed.match(BARE_EDGE_RE);
|
|
219
|
-
const labeledMatch = !bareMatch ? trimmed.match(LABELED_EDGE_RE) : null;
|
|
220
|
-
const edgeMatch = bareMatch ?? labeledMatch;
|
|
221
|
-
if (edgeMatch) {
|
|
222
|
-
// Flush any previous edge
|
|
223
|
-
flushEdge();
|
|
224
|
-
|
|
225
|
-
if (!currentNode) {
|
|
226
|
-
warn(lineNum, 'Edge line found outside of a node context.');
|
|
227
|
-
continue;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
const edgeLabel = bareMatch
|
|
231
|
-
? undefined
|
|
232
|
-
: labeledMatch![1]?.trim() || undefined;
|
|
233
|
-
const rest = (
|
|
234
|
-
bareMatch ? (bareMatch[1] ?? '') : (labeledMatch![2] ?? '')
|
|
235
|
-
).trim();
|
|
236
|
-
|
|
237
|
-
// §1.4 unified metadata grammar — same-line cut on the edge
|
|
238
|
-
// tail. The "name" returned here is the explicit target (if
|
|
239
|
-
// any); cycle edges always wrap to the next node so the
|
|
240
|
-
// target text is only used for the diagnostic at post-parse.
|
|
241
|
-
const edgeSplit = splitNameAndMeta(
|
|
242
|
-
rest,
|
|
243
|
-
CYCLE_REGISTRY,
|
|
244
|
-
new Map(),
|
|
245
|
-
undefined,
|
|
246
|
-
result.diagnostics,
|
|
247
|
-
lineNum
|
|
248
|
-
);
|
|
249
|
-
warnUnknownMetaKeys(
|
|
250
|
-
edgeSplit.meta,
|
|
251
|
-
CYCLE_REGISTRY,
|
|
252
|
-
(msg) => warn(lineNum, msg),
|
|
253
|
-
edgeSplit.name
|
|
254
|
-
);
|
|
255
|
-
const explicitTarget = edgeSplit.name || undefined;
|
|
256
|
-
if (explicitTarget?.endsWith(':')) {
|
|
257
|
-
warn(
|
|
258
|
-
lineNum,
|
|
259
|
-
`Trailing colon is not valid — write '${explicitTarget.replace(/:$/, '')}' instead`,
|
|
260
|
-
'error'
|
|
261
|
-
);
|
|
262
|
-
continue;
|
|
263
|
-
}
|
|
264
|
-
const edgeMeta: Record<string, string> = { ...edgeSplit.meta };
|
|
265
|
-
if (edgeSplit.color !== undefined) edgeMeta['color'] = edgeSplit.color;
|
|
266
|
-
|
|
267
|
-
const edgeColor = edgeMeta['color'];
|
|
268
|
-
const widthStr = edgeMeta['width'];
|
|
269
|
-
const edgeWidth = widthStr ? parseFloat(widthStr) : undefined;
|
|
270
|
-
const edgeDescFromPipe = edgeMeta['description'];
|
|
271
|
-
|
|
272
|
-
// Remove known keys
|
|
273
|
-
const edgeRestMeta = { ...edgeMeta };
|
|
274
|
-
delete edgeRestMeta['color'];
|
|
275
|
-
delete edgeRestMeta['width'];
|
|
276
|
-
delete edgeRestMeta['description'];
|
|
277
|
-
|
|
278
|
-
// sourceIndex is the index of the current node (it hasn't been pushed yet)
|
|
279
|
-
const sourceIndex = result.nodes.length;
|
|
280
|
-
// targetIndex is always the next node (will be resolved post-parse)
|
|
281
|
-
const targetIndex = sourceIndex + 1;
|
|
282
|
-
|
|
283
|
-
currentEdge = {
|
|
284
|
-
sourceIndex,
|
|
285
|
-
targetIndex,
|
|
286
|
-
...(edgeLabel !== undefined && { label: edgeLabel }),
|
|
287
|
-
...(edgeColor !== undefined && { color: edgeColor }),
|
|
288
|
-
...(edgeWidth !== undefined && { width: edgeWidth }),
|
|
289
|
-
description: edgeDescFromPipe ? [edgeDescFromPipe] : [],
|
|
290
|
-
lineNumber: lineNum,
|
|
291
|
-
metadata: edgeRestMeta,
|
|
292
|
-
};
|
|
293
|
-
|
|
294
|
-
// Check explicit target for diagnostic
|
|
295
|
-
if (explicitTarget) {
|
|
296
|
-
// Store for post-parse validation
|
|
297
|
-
(
|
|
298
|
-
currentEdge as CycleEdge & { _explicitTarget?: string }
|
|
299
|
-
)._explicitTarget = explicitTarget;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
state = 'edge';
|
|
303
|
-
continue;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// Not an edge — must be a description line
|
|
307
|
-
if (state === 'edge' && currentEdge) {
|
|
308
|
-
// Description under an edge
|
|
309
|
-
// Handle bullet points: `- item` → `• item`
|
|
310
|
-
const descLine = trimmed.startsWith('- ')
|
|
311
|
-
? `• ${trimmed.substring(2)}`
|
|
312
|
-
: trimmed;
|
|
313
|
-
currentEdge.description.push(descLine);
|
|
314
|
-
continue;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
if (state === 'node' && currentNode) {
|
|
318
|
-
// Description under a node
|
|
319
|
-
const descLine = trimmed.startsWith('- ')
|
|
320
|
-
? `• ${trimmed.substring(2)}`
|
|
321
|
-
: trimmed;
|
|
322
|
-
currentNode.description.push(descLine);
|
|
323
|
-
continue;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// Indented line with no context
|
|
327
|
-
warn(
|
|
328
|
-
lineNum,
|
|
329
|
-
`Indented line "${trimmed}" has no step above it — add a step on a non-indented line first, then indent its details. (§21)`
|
|
330
|
-
);
|
|
331
|
-
continue;
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// Flush remaining
|
|
336
|
-
flushNode();
|
|
337
|
-
|
|
338
|
-
// ── Post-parse validation ──
|
|
339
|
-
if (result.nodes.length < 2) {
|
|
340
|
-
return fail(
|
|
341
|
-
result.titleLineNumber || 1,
|
|
342
|
-
'cycle requires at least 2 nodes.'
|
|
343
|
-
);
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
// ── Resolve edge targets and generate implicit edges ──
|
|
347
|
-
const nodeCount = result.nodes.length;
|
|
348
|
-
const edgeBySource = new Map<number, Writable<CycleEdge>>();
|
|
349
|
-
for (const edge of result.edges as Writable<CycleEdge>[]) {
|
|
350
|
-
// Fix target index to wrap around
|
|
351
|
-
edge.targetIndex = (edge.sourceIndex + 1) % nodeCount;
|
|
352
|
-
edgeBySource.set(edge.sourceIndex, edge);
|
|
353
|
-
|
|
354
|
-
// Check explicit target diagnostic
|
|
355
|
-
const typed = edge as Writable<CycleEdge> & { _explicitTarget?: string };
|
|
356
|
-
if (typed._explicitTarget) {
|
|
357
|
-
// In-bounds: targetIndex computed as (sourceIndex + 1) % nodeCount.
|
|
358
|
-
const actualTarget = result.nodes[edge.targetIndex]!.label;
|
|
359
|
-
if (typed._explicitTarget !== actualTarget) {
|
|
360
|
-
info(
|
|
361
|
-
edge.lineNumber!,
|
|
362
|
-
`In cycle diagrams, edges always connect to the next node ('${actualTarget}'). Explicit target '${typed._explicitTarget}' is ignored.`
|
|
363
|
-
);
|
|
364
|
-
}
|
|
365
|
-
delete typed._explicitTarget;
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
// Generate implicit edges for nodes without explicit edge annotations
|
|
370
|
-
const allEdges: Writable<CycleEdge>[] = [];
|
|
371
|
-
for (let i = 0; i < nodeCount; i++) {
|
|
372
|
-
const existing = edgeBySource.get(i);
|
|
373
|
-
if (existing) {
|
|
374
|
-
allEdges.push(existing);
|
|
375
|
-
} else {
|
|
376
|
-
allEdges.push({
|
|
377
|
-
sourceIndex: i,
|
|
378
|
-
targetIndex: (i + 1) % nodeCount,
|
|
379
|
-
description: [],
|
|
380
|
-
metadata: {},
|
|
381
|
-
});
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
result.edges = allEdges;
|
|
385
|
-
|
|
386
|
-
return result;
|
|
387
|
-
}
|