flowink 0.1.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.
- package/LICENSE +21 -0
- package/NOTICE.md +17 -0
- package/README.md +301 -0
- package/dist/errors.d.ts +13 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +3560 -0
- package/dist/index.js.map +7 -0
- package/dist/layout.d.ts +13 -0
- package/dist/parse.d.ts +3 -0
- package/dist/parser/generated.d.ts +3 -0
- package/dist/parser/preprocess.d.ts +11 -0
- package/dist/parser/semantic.d.ts +76 -0
- package/dist/place-labels.d.ts +15 -0
- package/dist/rasterize.d.ts +47 -0
- package/dist/text.d.ts +36 -0
- package/dist/types.d.ts +88 -0
- package/examples/basic.mmd +4 -0
- package/examples/chinese.mmd +2 -0
- package/examples/cycle.mmd +2 -0
- package/examples/decision.mmd +4 -0
- package/examples/hero.mmd +2 -0
- package/examples/subgraph.mmd +5 -0
- package/package.json +71 -0
- package/vendor/mermaid/LICENSE +21 -0
- package/vendor/mermaid/README.md +16 -0
- package/vendor/mermaid/flow.jison +635 -0
- package/vendor/mermaid/flowDb.ts +1336 -0
- package/vendor/mermaid/flowParser.ts +12 -0
- package/vendor/mermaid/provenance.json +14 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,3560 @@
|
|
|
1
|
+
// src/parser/generated.js
|
|
2
|
+
var parser = (function() {
|
|
3
|
+
var o = function(k, v, o2, l) {
|
|
4
|
+
for (o2 = o2 || {}, l = k.length; l--; o2[k[l]] = v) ;
|
|
5
|
+
return o2;
|
|
6
|
+
}, $V0 = [1, 4], $V1 = [1, 3], $V2 = [1, 5], $V3 = [1, 8, 9, 10, 11, 27, 34, 36, 38, 44, 60, 84, 85, 86, 87, 88, 89, 102, 105, 106, 109, 111, 114, 115, 116, 121, 122, 123, 124, 125], $V4 = [2, 2], $V5 = [1, 13], $V6 = [1, 14], $V7 = [1, 15], $V8 = [1, 16], $V9 = [1, 23], $Va = [1, 25], $Vb = [1, 26], $Vc = [1, 27], $Vd = [1, 50], $Ve = [1, 49], $Vf = [1, 29], $Vg = [1, 30], $Vh = [1, 31], $Vi = [1, 32], $Vj = [1, 33], $Vk = [1, 45], $Vl = [1, 47], $Vm = [1, 43], $Vn = [1, 48], $Vo = [1, 44], $Vp = [1, 51], $Vq = [1, 46], $Vr = [1, 52], $Vs = [1, 53], $Vt = [1, 34], $Vu = [1, 35], $Vv = [1, 36], $Vw = [1, 37], $Vx = [1, 38], $Vy = [1, 58], $Vz = [1, 8, 9, 10, 11, 27, 32, 34, 36, 38, 44, 60, 84, 85, 86, 87, 88, 89, 102, 105, 106, 109, 111, 114, 115, 116, 121, 122, 123, 124, 125], $VA = [1, 62], $VB = [1, 61], $VC = [1, 63], $VD = [8, 9, 11, 75, 77, 78], $VE = [1, 79], $VF = [1, 92], $VG = [1, 97], $VH = [1, 96], $VI = [1, 93], $VJ = [1, 89], $VK = [1, 95], $VL = [1, 91], $VM = [1, 98], $VN = [1, 94], $VO = [1, 99], $VP = [1, 90], $VQ = [8, 9, 10, 11, 40, 75, 77, 78], $VR = [8, 9, 10, 11, 40, 46, 75, 77, 78], $VS = [8, 9, 10, 11, 29, 40, 44, 46, 48, 50, 52, 54, 56, 58, 60, 63, 65, 67, 68, 70, 75, 77, 78, 89, 102, 105, 106, 109, 111, 114, 115, 116], $VT = [8, 9, 11, 44, 60, 75, 77, 78, 89, 102, 105, 106, 109, 111, 114, 115, 116], $VU = [44, 60, 89, 102, 105, 106, 109, 111, 114, 115, 116], $VV = [1, 122], $VW = [1, 123], $VX = [1, 125], $VY = [1, 124], $VZ = [44, 60, 62, 74, 89, 102, 105, 106, 109, 111, 114, 115, 116], $V_ = [1, 134], $V$ = [1, 148], $V01 = [1, 149], $V11 = [1, 150], $V21 = [1, 151], $V31 = [1, 136], $V41 = [1, 138], $V51 = [1, 142], $V61 = [1, 143], $V71 = [1, 144], $V81 = [1, 145], $V91 = [1, 146], $Va1 = [1, 147], $Vb1 = [1, 152], $Vc1 = [1, 153], $Vd1 = [1, 132], $Ve1 = [1, 133], $Vf1 = [1, 140], $Vg1 = [1, 135], $Vh1 = [1, 139], $Vi1 = [1, 137], $Vj1 = [8, 9, 10, 11, 27, 32, 34, 36, 38, 44, 60, 84, 85, 86, 87, 88, 89, 102, 105, 106, 109, 111, 114, 115, 116, 121, 122, 123, 124, 125], $Vk1 = [1, 155], $Vl1 = [1, 157], $Vm1 = [8, 9, 11], $Vn1 = [8, 9, 10, 11, 14, 44, 60, 89, 105, 106, 109, 111, 114, 115, 116], $Vo1 = [1, 177], $Vp1 = [1, 173], $Vq1 = [1, 174], $Vr1 = [1, 178], $Vs1 = [1, 175], $Vt1 = [1, 176], $Vu1 = [77, 116, 119], $Vv1 = [8, 9, 10, 11, 12, 14, 27, 29, 32, 44, 60, 75, 84, 85, 86, 87, 88, 89, 90, 105, 109, 111, 114, 115, 116], $Vw1 = [10, 106], $Vx1 = [31, 49, 51, 53, 55, 57, 62, 64, 66, 67, 69, 71, 116, 117, 118], $Vy1 = [1, 248], $Vz1 = [1, 246], $VA1 = [1, 250], $VB1 = [1, 244], $VC1 = [1, 245], $VD1 = [1, 247], $VE1 = [1, 249], $VF1 = [1, 251], $VG1 = [1, 269], $VH1 = [8, 9, 11, 106], $VI1 = [8, 9, 10, 11, 60, 84, 105, 106, 109, 110, 111, 112];
|
|
7
|
+
var parser2 = {
|
|
8
|
+
trace: function trace() {
|
|
9
|
+
},
|
|
10
|
+
yy: {},
|
|
11
|
+
symbols_: { "error": 2, "start": 3, "graphConfig": 4, "document": 5, "line": 6, "statement": 7, "SEMI": 8, "NEWLINE": 9, "SPACE": 10, "EOF": 11, "GRAPH": 12, "NODIR": 13, "DIR": 14, "FirstStmtSeparator": 15, "ending": 16, "endToken": 17, "spaceList": 18, "spaceListNewline": 19, "vertexStatement": 20, "separator": 21, "styleStatement": 22, "linkStyleStatement": 23, "classDefStatement": 24, "classStatement": 25, "clickStatement": 26, "subgraph": 27, "textNoTags": 28, "SQS": 29, "text": 30, "SQE": 31, "end": 32, "direction": 33, "acc_title": 34, "acc_title_value": 35, "acc_descr": 36, "acc_descr_value": 37, "acc_descr_multiline_value": 38, "shapeData": 39, "SHAPE_DATA": 40, "link": 41, "node": 42, "styledVertex": 43, "AMP": 44, "vertex": 45, "STYLE_SEPARATOR": 46, "idString": 47, "DOUBLECIRCLESTART": 48, "DOUBLECIRCLEEND": 49, "PS": 50, "PE": 51, "(-": 52, "-)": 53, "STADIUMSTART": 54, "STADIUMEND": 55, "SUBROUTINESTART": 56, "SUBROUTINEEND": 57, "VERTEX_WITH_PROPS_START": 58, "NODE_STRING[field]": 59, "COLON": 60, "NODE_STRING[value]": 61, "PIPE": 62, "CYLINDERSTART": 63, "CYLINDEREND": 64, "DIAMOND_START": 65, "DIAMOND_STOP": 66, "TAGEND": 67, "TRAPSTART": 68, "TRAPEND": 69, "INVTRAPSTART": 70, "INVTRAPEND": 71, "linkStatement": 72, "arrowText": 73, "TESTSTR": 74, "START_LINK": 75, "edgeText": 76, "LINK": 77, "LINK_ID": 78, "edgeTextToken": 79, "STR": 80, "MD_STR": 81, "textToken": 82, "keywords": 83, "STYLE": 84, "LINKSTYLE": 85, "CLASSDEF": 86, "CLASS": 87, "CLICK": 88, "DOWN": 89, "UP": 90, "textNoTagsToken": 91, "stylesOpt": 92, "idString[vertex]": 93, "idString[class]": 94, "CALLBACKNAME": 95, "CALLBACKARGS": 96, "HREF": 97, "LINK_TARGET": 98, "STR[link]": 99, "STR[tooltip]": 100, "alphaNum": 101, "DEFAULT": 102, "numList": 103, "INTERPOLATE": 104, "NUM": 105, "COMMA": 106, "style": 107, "styleComponent": 108, "NODE_STRING": 109, "UNIT": 110, "BRKT": 111, "PCT": 112, "idStringToken": 113, "MINUS": 114, "MULT": 115, "UNICODE_TEXT": 116, "TEXT": 117, "TAGSTART": 118, "EDGE_TEXT": 119, "alphaNumToken": 120, "direction_tb": 121, "direction_bt": 122, "direction_rl": 123, "direction_lr": 124, "direction_td": 125, "$accept": 0, "$end": 1 },
|
|
12
|
+
terminals_: { 2: "error", 8: "SEMI", 9: "NEWLINE", 10: "SPACE", 11: "EOF", 12: "GRAPH", 13: "NODIR", 14: "DIR", 27: "subgraph", 29: "SQS", 31: "SQE", 32: "end", 34: "acc_title", 35: "acc_title_value", 36: "acc_descr", 37: "acc_descr_value", 38: "acc_descr_multiline_value", 40: "SHAPE_DATA", 44: "AMP", 46: "STYLE_SEPARATOR", 48: "DOUBLECIRCLESTART", 49: "DOUBLECIRCLEEND", 50: "PS", 51: "PE", 52: "(-", 53: "-)", 54: "STADIUMSTART", 55: "STADIUMEND", 56: "SUBROUTINESTART", 57: "SUBROUTINEEND", 58: "VERTEX_WITH_PROPS_START", 59: "NODE_STRING[field]", 60: "COLON", 61: "NODE_STRING[value]", 62: "PIPE", 63: "CYLINDERSTART", 64: "CYLINDEREND", 65: "DIAMOND_START", 66: "DIAMOND_STOP", 67: "TAGEND", 68: "TRAPSTART", 69: "TRAPEND", 70: "INVTRAPSTART", 71: "INVTRAPEND", 74: "TESTSTR", 75: "START_LINK", 77: "LINK", 78: "LINK_ID", 80: "STR", 81: "MD_STR", 84: "STYLE", 85: "LINKSTYLE", 86: "CLASSDEF", 87: "CLASS", 88: "CLICK", 89: "DOWN", 90: "UP", 93: "idString[vertex]", 94: "idString[class]", 95: "CALLBACKNAME", 96: "CALLBACKARGS", 97: "HREF", 98: "LINK_TARGET", 99: "STR[link]", 100: "STR[tooltip]", 102: "DEFAULT", 104: "INTERPOLATE", 105: "NUM", 106: "COMMA", 109: "NODE_STRING", 110: "UNIT", 111: "BRKT", 112: "PCT", 114: "MINUS", 115: "MULT", 116: "UNICODE_TEXT", 117: "TEXT", 118: "TAGSTART", 119: "EDGE_TEXT", 121: "direction_tb", 122: "direction_bt", 123: "direction_rl", 124: "direction_lr", 125: "direction_td" },
|
|
13
|
+
productions_: [0, [3, 2], [5, 0], [5, 2], [6, 1], [6, 1], [6, 1], [6, 1], [6, 1], [4, 2], [4, 2], [4, 2], [4, 3], [16, 2], [16, 1], [17, 1], [17, 1], [17, 1], [15, 1], [15, 1], [15, 2], [19, 2], [19, 2], [19, 1], [19, 1], [18, 2], [18, 1], [7, 2], [7, 2], [7, 2], [7, 2], [7, 2], [7, 2], [7, 9], [7, 6], [7, 4], [7, 1], [7, 2], [7, 2], [7, 1], [21, 1], [21, 1], [21, 1], [39, 2], [39, 1], [20, 4], [20, 3], [20, 4], [20, 2], [20, 2], [20, 1], [42, 1], [42, 6], [42, 5], [43, 1], [43, 3], [45, 4], [45, 4], [45, 6], [45, 4], [45, 4], [45, 4], [45, 8], [45, 4], [45, 4], [45, 4], [45, 6], [45, 4], [45, 4], [45, 4], [45, 4], [45, 4], [45, 1], [41, 2], [41, 3], [41, 3], [41, 1], [41, 3], [41, 4], [76, 1], [76, 2], [76, 1], [76, 1], [72, 1], [72, 2], [73, 3], [30, 1], [30, 2], [30, 1], [30, 1], [83, 1], [83, 1], [83, 1], [83, 1], [83, 1], [83, 1], [83, 1], [83, 1], [83, 1], [83, 1], [83, 1], [28, 1], [28, 2], [28, 1], [28, 1], [24, 5], [25, 5], [26, 2], [26, 4], [26, 3], [26, 5], [26, 3], [26, 5], [26, 5], [26, 7], [26, 2], [26, 4], [26, 2], [26, 4], [26, 4], [26, 6], [22, 5], [23, 5], [23, 5], [23, 9], [23, 9], [23, 7], [23, 7], [103, 1], [103, 3], [92, 1], [92, 3], [107, 1], [107, 2], [108, 1], [108, 1], [108, 1], [108, 1], [108, 1], [108, 1], [108, 1], [108, 1], [113, 1], [113, 1], [113, 1], [113, 1], [113, 1], [113, 1], [113, 1], [113, 1], [113, 1], [113, 1], [113, 1], [82, 1], [82, 1], [82, 1], [82, 1], [91, 1], [91, 1], [91, 1], [91, 1], [91, 1], [91, 1], [91, 1], [91, 1], [91, 1], [91, 1], [91, 1], [79, 1], [79, 1], [120, 1], [120, 1], [120, 1], [120, 1], [120, 1], [120, 1], [120, 1], [120, 1], [120, 1], [120, 1], [120, 1], [47, 1], [47, 2], [101, 1], [101, 2], [33, 1], [33, 1], [33, 1], [33, 1], [33, 1]],
|
|
14
|
+
performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$) {
|
|
15
|
+
var $0 = $$.length - 1;
|
|
16
|
+
switch (yystate) {
|
|
17
|
+
case 2:
|
|
18
|
+
this.$ = [];
|
|
19
|
+
break;
|
|
20
|
+
case 3:
|
|
21
|
+
if (!Array.isArray($$[$0]) || $$[$0].length > 0) {
|
|
22
|
+
$$[$0 - 1].push($$[$0]);
|
|
23
|
+
}
|
|
24
|
+
this.$ = $$[$0 - 1];
|
|
25
|
+
break;
|
|
26
|
+
case 4:
|
|
27
|
+
case 183:
|
|
28
|
+
this.$ = $$[$0];
|
|
29
|
+
break;
|
|
30
|
+
case 11:
|
|
31
|
+
yy.setDirection("TB");
|
|
32
|
+
this.$ = "TB";
|
|
33
|
+
break;
|
|
34
|
+
case 12:
|
|
35
|
+
yy.setDirection($$[$0 - 1]);
|
|
36
|
+
this.$ = $$[$0 - 1];
|
|
37
|
+
break;
|
|
38
|
+
case 27:
|
|
39
|
+
this.$ = $$[$0 - 1].nodes;
|
|
40
|
+
break;
|
|
41
|
+
case 28:
|
|
42
|
+
case 29:
|
|
43
|
+
case 30:
|
|
44
|
+
case 31:
|
|
45
|
+
case 32:
|
|
46
|
+
this.$ = [];
|
|
47
|
+
break;
|
|
48
|
+
case 33:
|
|
49
|
+
this.$ = yy.addSubGraph($$[$0 - 6], $$[$0 - 1], $$[$0 - 4]);
|
|
50
|
+
break;
|
|
51
|
+
case 34:
|
|
52
|
+
this.$ = yy.addSubGraph($$[$0 - 3], $$[$0 - 1], $$[$0 - 3]);
|
|
53
|
+
break;
|
|
54
|
+
case 35:
|
|
55
|
+
this.$ = yy.addSubGraph(void 0, $$[$0 - 1], void 0);
|
|
56
|
+
break;
|
|
57
|
+
case 37:
|
|
58
|
+
this.$ = $$[$0].trim();
|
|
59
|
+
yy.setAccTitle(this.$);
|
|
60
|
+
break;
|
|
61
|
+
case 38:
|
|
62
|
+
case 39:
|
|
63
|
+
this.$ = $$[$0].trim();
|
|
64
|
+
yy.setAccDescription(this.$);
|
|
65
|
+
break;
|
|
66
|
+
case 43:
|
|
67
|
+
this.$ = $$[$0 - 1] + $$[$0];
|
|
68
|
+
break;
|
|
69
|
+
case 44:
|
|
70
|
+
this.$ = $$[$0];
|
|
71
|
+
break;
|
|
72
|
+
case 45:
|
|
73
|
+
yy.addVertex($$[$0 - 1][$$[$0 - 1].length - 1], void 0, void 0, void 0, void 0, void 0, void 0, $$[$0]);
|
|
74
|
+
yy.addLink($$[$0 - 3].stmt, $$[$0 - 1], $$[$0 - 2]);
|
|
75
|
+
this.$ = { stmt: $$[$0 - 1], nodes: $$[$0 - 1].concat($$[$0 - 3].nodes) };
|
|
76
|
+
break;
|
|
77
|
+
case 46:
|
|
78
|
+
yy.addLink($$[$0 - 2].stmt, $$[$0], $$[$0 - 1]);
|
|
79
|
+
this.$ = { stmt: $$[$0], nodes: $$[$0].concat($$[$0 - 2].nodes) };
|
|
80
|
+
break;
|
|
81
|
+
case 47:
|
|
82
|
+
yy.addLink($$[$0 - 3].stmt, $$[$0 - 1], $$[$0 - 2]);
|
|
83
|
+
this.$ = { stmt: $$[$0 - 1], nodes: $$[$0 - 1].concat($$[$0 - 3].nodes) };
|
|
84
|
+
break;
|
|
85
|
+
case 48:
|
|
86
|
+
this.$ = { stmt: $$[$0 - 1], nodes: $$[$0 - 1] };
|
|
87
|
+
break;
|
|
88
|
+
case 49:
|
|
89
|
+
yy.addVertex($$[$0 - 1][$$[$0 - 1].length - 1], void 0, void 0, void 0, void 0, void 0, void 0, $$[$0]);
|
|
90
|
+
this.$ = { stmt: $$[$0 - 1], nodes: $$[$0 - 1], shapeData: $$[$0] };
|
|
91
|
+
break;
|
|
92
|
+
case 50:
|
|
93
|
+
this.$ = { stmt: $$[$0], nodes: $$[$0] };
|
|
94
|
+
break;
|
|
95
|
+
case 51:
|
|
96
|
+
this.$ = [$$[$0]];
|
|
97
|
+
break;
|
|
98
|
+
case 52:
|
|
99
|
+
yy.addVertex($$[$0 - 5][$$[$0 - 5].length - 1], void 0, void 0, void 0, void 0, void 0, void 0, $$[$0 - 4]);
|
|
100
|
+
this.$ = $$[$0 - 5].concat($$[$0]);
|
|
101
|
+
break;
|
|
102
|
+
case 53:
|
|
103
|
+
this.$ = $$[$0 - 4].concat($$[$0]);
|
|
104
|
+
break;
|
|
105
|
+
case 54:
|
|
106
|
+
this.$ = $$[$0];
|
|
107
|
+
break;
|
|
108
|
+
case 55:
|
|
109
|
+
this.$ = $$[$0 - 2];
|
|
110
|
+
yy.setClass($$[$0 - 2], $$[$0]);
|
|
111
|
+
break;
|
|
112
|
+
case 56:
|
|
113
|
+
this.$ = $$[$0 - 3];
|
|
114
|
+
yy.addVertex($$[$0 - 3], $$[$0 - 1], "square");
|
|
115
|
+
break;
|
|
116
|
+
case 57:
|
|
117
|
+
this.$ = $$[$0 - 3];
|
|
118
|
+
yy.addVertex($$[$0 - 3], $$[$0 - 1], "doublecircle");
|
|
119
|
+
break;
|
|
120
|
+
case 58:
|
|
121
|
+
this.$ = $$[$0 - 5];
|
|
122
|
+
yy.addVertex($$[$0 - 5], $$[$0 - 2], "circle");
|
|
123
|
+
break;
|
|
124
|
+
case 59:
|
|
125
|
+
this.$ = $$[$0 - 3];
|
|
126
|
+
yy.addVertex($$[$0 - 3], $$[$0 - 1], "ellipse");
|
|
127
|
+
break;
|
|
128
|
+
case 60:
|
|
129
|
+
this.$ = $$[$0 - 3];
|
|
130
|
+
yy.addVertex($$[$0 - 3], $$[$0 - 1], "stadium");
|
|
131
|
+
break;
|
|
132
|
+
case 61:
|
|
133
|
+
this.$ = $$[$0 - 3];
|
|
134
|
+
yy.addVertex($$[$0 - 3], $$[$0 - 1], "subroutine");
|
|
135
|
+
break;
|
|
136
|
+
case 62:
|
|
137
|
+
this.$ = $$[$0 - 7];
|
|
138
|
+
yy.addVertex($$[$0 - 7], $$[$0 - 1], "rect", void 0, void 0, void 0, Object.fromEntries([[$$[$0 - 5], $$[$0 - 3]]]));
|
|
139
|
+
break;
|
|
140
|
+
case 63:
|
|
141
|
+
this.$ = $$[$0 - 3];
|
|
142
|
+
yy.addVertex($$[$0 - 3], $$[$0 - 1], "cylinder");
|
|
143
|
+
break;
|
|
144
|
+
case 64:
|
|
145
|
+
this.$ = $$[$0 - 3];
|
|
146
|
+
yy.addVertex($$[$0 - 3], $$[$0 - 1], "round");
|
|
147
|
+
break;
|
|
148
|
+
case 65:
|
|
149
|
+
this.$ = $$[$0 - 3];
|
|
150
|
+
yy.addVertex($$[$0 - 3], $$[$0 - 1], "diamond");
|
|
151
|
+
break;
|
|
152
|
+
case 66:
|
|
153
|
+
this.$ = $$[$0 - 5];
|
|
154
|
+
yy.addVertex($$[$0 - 5], $$[$0 - 2], "hexagon");
|
|
155
|
+
break;
|
|
156
|
+
case 67:
|
|
157
|
+
this.$ = $$[$0 - 3];
|
|
158
|
+
yy.addVertex($$[$0 - 3], $$[$0 - 1], "odd");
|
|
159
|
+
break;
|
|
160
|
+
case 68:
|
|
161
|
+
this.$ = $$[$0 - 3];
|
|
162
|
+
yy.addVertex($$[$0 - 3], $$[$0 - 1], "trapezoid");
|
|
163
|
+
break;
|
|
164
|
+
case 69:
|
|
165
|
+
this.$ = $$[$0 - 3];
|
|
166
|
+
yy.addVertex($$[$0 - 3], $$[$0 - 1], "inv_trapezoid");
|
|
167
|
+
break;
|
|
168
|
+
case 70:
|
|
169
|
+
this.$ = $$[$0 - 3];
|
|
170
|
+
yy.addVertex($$[$0 - 3], $$[$0 - 1], "lean_right");
|
|
171
|
+
break;
|
|
172
|
+
case 71:
|
|
173
|
+
this.$ = $$[$0 - 3];
|
|
174
|
+
yy.addVertex($$[$0 - 3], $$[$0 - 1], "lean_left");
|
|
175
|
+
break;
|
|
176
|
+
case 72:
|
|
177
|
+
this.$ = $$[$0];
|
|
178
|
+
yy.addVertex($$[$0]);
|
|
179
|
+
break;
|
|
180
|
+
case 73:
|
|
181
|
+
$$[$0 - 1].text = $$[$0];
|
|
182
|
+
this.$ = $$[$0 - 1];
|
|
183
|
+
break;
|
|
184
|
+
case 74:
|
|
185
|
+
case 75:
|
|
186
|
+
$$[$0 - 2].text = $$[$0 - 1];
|
|
187
|
+
this.$ = $$[$0 - 2];
|
|
188
|
+
break;
|
|
189
|
+
case 76:
|
|
190
|
+
this.$ = $$[$0];
|
|
191
|
+
break;
|
|
192
|
+
case 77:
|
|
193
|
+
var inf = yy.destructLink($$[$0], $$[$0 - 2]);
|
|
194
|
+
this.$ = { "type": inf.type, "stroke": inf.stroke, "length": inf.length, "text": $$[$0 - 1] };
|
|
195
|
+
break;
|
|
196
|
+
case 78:
|
|
197
|
+
var inf = yy.destructLink($$[$0], $$[$0 - 2]);
|
|
198
|
+
this.$ = { "type": inf.type, "stroke": inf.stroke, "length": inf.length, "text": $$[$0 - 1], "id": $$[$0 - 3] };
|
|
199
|
+
break;
|
|
200
|
+
case 79:
|
|
201
|
+
this.$ = { text: $$[$0], type: "text" };
|
|
202
|
+
break;
|
|
203
|
+
case 80:
|
|
204
|
+
this.$ = { text: $$[$0 - 1].text + "" + $$[$0], type: $$[$0 - 1].type };
|
|
205
|
+
break;
|
|
206
|
+
case 81:
|
|
207
|
+
this.$ = { text: $$[$0], type: "string" };
|
|
208
|
+
break;
|
|
209
|
+
case 82:
|
|
210
|
+
this.$ = { text: $$[$0], type: "markdown" };
|
|
211
|
+
break;
|
|
212
|
+
case 83:
|
|
213
|
+
var inf = yy.destructLink($$[$0]);
|
|
214
|
+
this.$ = { "type": inf.type, "stroke": inf.stroke, "length": inf.length };
|
|
215
|
+
break;
|
|
216
|
+
case 84:
|
|
217
|
+
var inf = yy.destructLink($$[$0]);
|
|
218
|
+
this.$ = { "type": inf.type, "stroke": inf.stroke, "length": inf.length, "id": $$[$0 - 1] };
|
|
219
|
+
break;
|
|
220
|
+
case 85:
|
|
221
|
+
this.$ = $$[$0 - 1];
|
|
222
|
+
break;
|
|
223
|
+
case 86:
|
|
224
|
+
this.$ = { text: $$[$0], type: "text" };
|
|
225
|
+
break;
|
|
226
|
+
case 87:
|
|
227
|
+
this.$ = { text: $$[$0 - 1].text + "" + $$[$0], type: $$[$0 - 1].type };
|
|
228
|
+
break;
|
|
229
|
+
case 88:
|
|
230
|
+
this.$ = { text: $$[$0], type: "string" };
|
|
231
|
+
break;
|
|
232
|
+
case 89:
|
|
233
|
+
case 104:
|
|
234
|
+
this.$ = { text: $$[$0], type: "markdown" };
|
|
235
|
+
break;
|
|
236
|
+
case 101:
|
|
237
|
+
this.$ = { text: $$[$0], type: "text" };
|
|
238
|
+
break;
|
|
239
|
+
case 102:
|
|
240
|
+
this.$ = { text: $$[$0 - 1].text + "" + $$[$0], type: $$[$0 - 1].type };
|
|
241
|
+
break;
|
|
242
|
+
case 103:
|
|
243
|
+
this.$ = { text: $$[$0], type: "text" };
|
|
244
|
+
break;
|
|
245
|
+
case 105:
|
|
246
|
+
this.$ = $$[$0 - 4];
|
|
247
|
+
yy.addClass($$[$0 - 2], $$[$0]);
|
|
248
|
+
break;
|
|
249
|
+
case 106:
|
|
250
|
+
this.$ = $$[$0 - 4];
|
|
251
|
+
yy.setClass($$[$0 - 2], $$[$0]);
|
|
252
|
+
break;
|
|
253
|
+
case 107:
|
|
254
|
+
case 115:
|
|
255
|
+
this.$ = $$[$0 - 1];
|
|
256
|
+
yy.setClickEvent($$[$0 - 1], $$[$0]);
|
|
257
|
+
break;
|
|
258
|
+
case 108:
|
|
259
|
+
case 116:
|
|
260
|
+
this.$ = $$[$0 - 3];
|
|
261
|
+
yy.setClickEvent($$[$0 - 3], $$[$0 - 2]);
|
|
262
|
+
yy.setTooltip($$[$0 - 3], $$[$0]);
|
|
263
|
+
break;
|
|
264
|
+
case 109:
|
|
265
|
+
this.$ = $$[$0 - 2];
|
|
266
|
+
yy.setClickEvent($$[$0 - 2], $$[$0 - 1], $$[$0]);
|
|
267
|
+
break;
|
|
268
|
+
case 110:
|
|
269
|
+
this.$ = $$[$0 - 4];
|
|
270
|
+
yy.setClickEvent($$[$0 - 4], $$[$0 - 3], $$[$0 - 2]);
|
|
271
|
+
yy.setTooltip($$[$0 - 4], $$[$0]);
|
|
272
|
+
break;
|
|
273
|
+
case 111:
|
|
274
|
+
this.$ = $$[$0 - 2];
|
|
275
|
+
yy.setLink($$[$0 - 2], $$[$0]);
|
|
276
|
+
break;
|
|
277
|
+
case 112:
|
|
278
|
+
this.$ = $$[$0 - 4];
|
|
279
|
+
yy.setLink($$[$0 - 4], $$[$0 - 2]);
|
|
280
|
+
yy.setTooltip($$[$0 - 4], $$[$0]);
|
|
281
|
+
break;
|
|
282
|
+
case 113:
|
|
283
|
+
this.$ = $$[$0 - 4];
|
|
284
|
+
yy.setLink($$[$0 - 4], $$[$0 - 2], $$[$0]);
|
|
285
|
+
break;
|
|
286
|
+
case 114:
|
|
287
|
+
this.$ = $$[$0 - 6];
|
|
288
|
+
yy.setLink($$[$0 - 6], $$[$0 - 4], $$[$0]);
|
|
289
|
+
yy.setTooltip($$[$0 - 6], $$[$0 - 2]);
|
|
290
|
+
break;
|
|
291
|
+
case 117:
|
|
292
|
+
this.$ = $$[$0 - 1];
|
|
293
|
+
yy.setLink($$[$0 - 1], $$[$0]);
|
|
294
|
+
break;
|
|
295
|
+
case 118:
|
|
296
|
+
this.$ = $$[$0 - 3];
|
|
297
|
+
yy.setLink($$[$0 - 3], $$[$0 - 2]);
|
|
298
|
+
yy.setTooltip($$[$0 - 3], $$[$0]);
|
|
299
|
+
break;
|
|
300
|
+
case 119:
|
|
301
|
+
this.$ = $$[$0 - 3];
|
|
302
|
+
yy.setLink($$[$0 - 3], $$[$0 - 2], $$[$0]);
|
|
303
|
+
break;
|
|
304
|
+
case 120:
|
|
305
|
+
this.$ = $$[$0 - 5];
|
|
306
|
+
yy.setLink($$[$0 - 5], $$[$0 - 4], $$[$0]);
|
|
307
|
+
yy.setTooltip($$[$0 - 5], $$[$0 - 2]);
|
|
308
|
+
break;
|
|
309
|
+
case 121:
|
|
310
|
+
this.$ = $$[$0 - 4];
|
|
311
|
+
yy.addVertex($$[$0 - 2], void 0, void 0, $$[$0]);
|
|
312
|
+
break;
|
|
313
|
+
case 122:
|
|
314
|
+
this.$ = $$[$0 - 4];
|
|
315
|
+
yy.updateLink([$$[$0 - 2]], $$[$0]);
|
|
316
|
+
break;
|
|
317
|
+
case 123:
|
|
318
|
+
this.$ = $$[$0 - 4];
|
|
319
|
+
yy.updateLink($$[$0 - 2], $$[$0]);
|
|
320
|
+
break;
|
|
321
|
+
case 124:
|
|
322
|
+
this.$ = $$[$0 - 8];
|
|
323
|
+
yy.updateLinkInterpolate([$$[$0 - 6]], $$[$0 - 2]);
|
|
324
|
+
yy.updateLink([$$[$0 - 6]], $$[$0]);
|
|
325
|
+
break;
|
|
326
|
+
case 125:
|
|
327
|
+
this.$ = $$[$0 - 8];
|
|
328
|
+
yy.updateLinkInterpolate($$[$0 - 6], $$[$0 - 2]);
|
|
329
|
+
yy.updateLink($$[$0 - 6], $$[$0]);
|
|
330
|
+
break;
|
|
331
|
+
case 126:
|
|
332
|
+
this.$ = $$[$0 - 6];
|
|
333
|
+
yy.updateLinkInterpolate([$$[$0 - 4]], $$[$0]);
|
|
334
|
+
break;
|
|
335
|
+
case 127:
|
|
336
|
+
this.$ = $$[$0 - 6];
|
|
337
|
+
yy.updateLinkInterpolate($$[$0 - 4], $$[$0]);
|
|
338
|
+
break;
|
|
339
|
+
case 128:
|
|
340
|
+
case 130:
|
|
341
|
+
this.$ = [$$[$0]];
|
|
342
|
+
break;
|
|
343
|
+
case 129:
|
|
344
|
+
case 131:
|
|
345
|
+
$$[$0 - 2].push($$[$0]);
|
|
346
|
+
this.$ = $$[$0 - 2];
|
|
347
|
+
break;
|
|
348
|
+
case 133:
|
|
349
|
+
this.$ = $$[$0 - 1] + $$[$0];
|
|
350
|
+
break;
|
|
351
|
+
case 181:
|
|
352
|
+
this.$ = $$[$0];
|
|
353
|
+
break;
|
|
354
|
+
case 182:
|
|
355
|
+
this.$ = $$[$0 - 1] + "" + $$[$0];
|
|
356
|
+
break;
|
|
357
|
+
case 184:
|
|
358
|
+
this.$ = $$[$0 - 1] + "" + $$[$0];
|
|
359
|
+
break;
|
|
360
|
+
case 185:
|
|
361
|
+
this.$ = { stmt: "dir", value: "TB" };
|
|
362
|
+
break;
|
|
363
|
+
case 186:
|
|
364
|
+
this.$ = { stmt: "dir", value: "BT" };
|
|
365
|
+
break;
|
|
366
|
+
case 187:
|
|
367
|
+
this.$ = { stmt: "dir", value: "RL" };
|
|
368
|
+
break;
|
|
369
|
+
case 188:
|
|
370
|
+
this.$ = { stmt: "dir", value: "LR" };
|
|
371
|
+
break;
|
|
372
|
+
case 189:
|
|
373
|
+
this.$ = { stmt: "dir", value: "TD" };
|
|
374
|
+
break;
|
|
375
|
+
}
|
|
376
|
+
},
|
|
377
|
+
table: [{ 3: 1, 4: 2, 9: $V0, 10: $V1, 12: $V2 }, { 1: [3] }, o($V3, $V4, { 5: 6 }), { 4: 7, 9: $V0, 10: $V1, 12: $V2 }, { 4: 8, 9: $V0, 10: $V1, 12: $V2 }, { 13: [1, 9], 14: [1, 10] }, { 1: [2, 1], 6: 11, 7: 12, 8: $V5, 9: $V6, 10: $V7, 11: $V8, 20: 17, 22: 18, 23: 19, 24: 20, 25: 21, 26: 22, 27: $V9, 33: 24, 34: $Va, 36: $Vb, 38: $Vc, 42: 28, 43: 39, 44: $Vd, 45: 40, 47: 41, 60: $Ve, 84: $Vf, 85: $Vg, 86: $Vh, 87: $Vi, 88: $Vj, 89: $Vk, 102: $Vl, 105: $Vm, 106: $Vn, 109: $Vo, 111: $Vp, 113: 42, 114: $Vq, 115: $Vr, 116: $Vs, 121: $Vt, 122: $Vu, 123: $Vv, 124: $Vw, 125: $Vx }, o($V3, [2, 9]), o($V3, [2, 10]), o($V3, [2, 11]), { 8: [1, 55], 9: [1, 56], 10: $Vy, 15: 54, 18: 57 }, o($Vz, [2, 3]), o($Vz, [2, 4]), o($Vz, [2, 5]), o($Vz, [2, 6]), o($Vz, [2, 7]), o($Vz, [2, 8]), { 8: $VA, 9: $VB, 11: $VC, 21: 59, 41: 60, 72: 64, 75: [1, 65], 77: [1, 67], 78: [1, 66] }, { 8: $VA, 9: $VB, 11: $VC, 21: 68 }, { 8: $VA, 9: $VB, 11: $VC, 21: 69 }, { 8: $VA, 9: $VB, 11: $VC, 21: 70 }, { 8: $VA, 9: $VB, 11: $VC, 21: 71 }, { 8: $VA, 9: $VB, 11: $VC, 21: 72 }, { 8: $VA, 9: $VB, 10: [1, 73], 11: $VC, 21: 74 }, o($Vz, [2, 36]), { 35: [1, 75] }, { 37: [1, 76] }, o($Vz, [2, 39]), o($VD, [2, 50], { 18: 77, 39: 78, 10: $Vy, 40: $VE }), { 10: [1, 80] }, { 10: [1, 81] }, { 10: [1, 82] }, { 10: [1, 83] }, { 14: $VF, 44: $VG, 60: $VH, 80: [1, 87], 89: $VI, 95: [1, 84], 97: [1, 85], 101: 86, 105: $VJ, 106: $VK, 109: $VL, 111: $VM, 114: $VN, 115: $VO, 116: $VP, 120: 88 }, o($Vz, [2, 185]), o($Vz, [2, 186]), o($Vz, [2, 187]), o($Vz, [2, 188]), o($Vz, [2, 189]), o($VQ, [2, 51]), o($VQ, [2, 54], { 46: [1, 100] }), o($VR, [2, 72], { 113: 113, 29: [1, 101], 44: $Vd, 48: [1, 102], 50: [1, 103], 52: [1, 104], 54: [1, 105], 56: [1, 106], 58: [1, 107], 60: $Ve, 63: [1, 108], 65: [1, 109], 67: [1, 110], 68: [1, 111], 70: [1, 112], 89: $Vk, 102: $Vl, 105: $Vm, 106: $Vn, 109: $Vo, 111: $Vp, 114: $Vq, 115: $Vr, 116: $Vs }), o($VS, [2, 181]), o($VS, [2, 142]), o($VS, [2, 143]), o($VS, [2, 144]), o($VS, [2, 145]), o($VS, [2, 146]), o($VS, [2, 147]), o($VS, [2, 148]), o($VS, [2, 149]), o($VS, [2, 150]), o($VS, [2, 151]), o($VS, [2, 152]), o($V3, [2, 12]), o($V3, [2, 18]), o($V3, [2, 19]), { 9: [1, 114] }, o($VT, [2, 26], { 18: 115, 10: $Vy }), o($Vz, [2, 27]), { 42: 116, 43: 39, 44: $Vd, 45: 40, 47: 41, 60: $Ve, 89: $Vk, 102: $Vl, 105: $Vm, 106: $Vn, 109: $Vo, 111: $Vp, 113: 42, 114: $Vq, 115: $Vr, 116: $Vs }, o($Vz, [2, 40]), o($Vz, [2, 41]), o($Vz, [2, 42]), o($VU, [2, 76], { 73: 117, 62: [1, 119], 74: [1, 118] }), { 76: 120, 79: 121, 80: $VV, 81: $VW, 116: $VX, 119: $VY }, { 75: [1, 126], 77: [1, 127] }, o($VZ, [2, 83]), o($Vz, [2, 28]), o($Vz, [2, 29]), o($Vz, [2, 30]), o($Vz, [2, 31]), o($Vz, [2, 32]), { 10: $V_, 12: $V$, 14: $V01, 27: $V11, 28: 128, 32: $V21, 44: $V31, 60: $V41, 75: $V51, 80: [1, 130], 81: [1, 131], 83: 141, 84: $V61, 85: $V71, 86: $V81, 87: $V91, 88: $Va1, 89: $Vb1, 90: $Vc1, 91: 129, 105: $Vd1, 109: $Ve1, 111: $Vf1, 114: $Vg1, 115: $Vh1, 116: $Vi1 }, o($Vj1, $V4, { 5: 154 }), o($Vz, [2, 37]), o($Vz, [2, 38]), o($VD, [2, 48], { 44: $Vk1 }), o($VD, [2, 49], { 18: 156, 10: $Vy, 40: $Vl1 }), o($VQ, [2, 44]), { 44: $Vd, 47: 158, 60: $Ve, 89: $Vk, 102: $Vl, 105: $Vm, 106: $Vn, 109: $Vo, 111: $Vp, 113: 42, 114: $Vq, 115: $Vr, 116: $Vs }, { 102: [1, 159], 103: 160, 105: [1, 161] }, { 44: $Vd, 47: 162, 60: $Ve, 89: $Vk, 102: $Vl, 105: $Vm, 106: $Vn, 109: $Vo, 111: $Vp, 113: 42, 114: $Vq, 115: $Vr, 116: $Vs }, { 44: $Vd, 47: 163, 60: $Ve, 89: $Vk, 102: $Vl, 105: $Vm, 106: $Vn, 109: $Vo, 111: $Vp, 113: 42, 114: $Vq, 115: $Vr, 116: $Vs }, o($Vm1, [2, 107], { 10: [1, 164], 96: [1, 165] }), { 80: [1, 166] }, o($Vm1, [2, 115], { 120: 168, 10: [1, 167], 14: $VF, 44: $VG, 60: $VH, 89: $VI, 105: $VJ, 106: $VK, 109: $VL, 111: $VM, 114: $VN, 115: $VO, 116: $VP }), o($Vm1, [2, 117], { 10: [1, 169] }), o($Vn1, [2, 183]), o($Vn1, [2, 170]), o($Vn1, [2, 171]), o($Vn1, [2, 172]), o($Vn1, [2, 173]), o($Vn1, [2, 174]), o($Vn1, [2, 175]), o($Vn1, [2, 176]), o($Vn1, [2, 177]), o($Vn1, [2, 178]), o($Vn1, [2, 179]), o($Vn1, [2, 180]), { 44: $Vd, 47: 170, 60: $Ve, 89: $Vk, 102: $Vl, 105: $Vm, 106: $Vn, 109: $Vo, 111: $Vp, 113: 42, 114: $Vq, 115: $Vr, 116: $Vs }, { 30: 171, 67: $Vo1, 80: $Vp1, 81: $Vq1, 82: 172, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, { 30: 179, 67: $Vo1, 80: $Vp1, 81: $Vq1, 82: 172, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, { 30: 181, 50: [1, 180], 67: $Vo1, 80: $Vp1, 81: $Vq1, 82: 172, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, { 30: 182, 67: $Vo1, 80: $Vp1, 81: $Vq1, 82: 172, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, { 30: 183, 67: $Vo1, 80: $Vp1, 81: $Vq1, 82: 172, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, { 30: 184, 67: $Vo1, 80: $Vp1, 81: $Vq1, 82: 172, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, { 109: [1, 185] }, { 30: 186, 67: $Vo1, 80: $Vp1, 81: $Vq1, 82: 172, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, { 30: 187, 65: [1, 188], 67: $Vo1, 80: $Vp1, 81: $Vq1, 82: 172, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, { 30: 189, 67: $Vo1, 80: $Vp1, 81: $Vq1, 82: 172, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, { 30: 190, 67: $Vo1, 80: $Vp1, 81: $Vq1, 82: 172, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, { 30: 191, 67: $Vo1, 80: $Vp1, 81: $Vq1, 82: 172, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, o($VS, [2, 182]), o($V3, [2, 20]), o($VT, [2, 25]), o($VD, [2, 46], { 39: 192, 18: 193, 10: $Vy, 40: $VE }), o($VU, [2, 73], { 10: [1, 194] }), { 10: [1, 195] }, { 30: 196, 67: $Vo1, 80: $Vp1, 81: $Vq1, 82: 172, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, { 77: [1, 197], 79: 198, 116: $VX, 119: $VY }, o($Vu1, [2, 79]), o($Vu1, [2, 81]), o($Vu1, [2, 82]), o($Vu1, [2, 168]), o($Vu1, [2, 169]), { 76: 199, 79: 121, 80: $VV, 81: $VW, 116: $VX, 119: $VY }, o($VZ, [2, 84]), { 8: $VA, 9: $VB, 10: $V_, 11: $VC, 12: $V$, 14: $V01, 21: 201, 27: $V11, 29: [1, 200], 32: $V21, 44: $V31, 60: $V41, 75: $V51, 83: 141, 84: $V61, 85: $V71, 86: $V81, 87: $V91, 88: $Va1, 89: $Vb1, 90: $Vc1, 91: 202, 105: $Vd1, 109: $Ve1, 111: $Vf1, 114: $Vg1, 115: $Vh1, 116: $Vi1 }, o($Vv1, [2, 101]), o($Vv1, [2, 103]), o($Vv1, [2, 104]), o($Vv1, [2, 157]), o($Vv1, [2, 158]), o($Vv1, [2, 159]), o($Vv1, [2, 160]), o($Vv1, [2, 161]), o($Vv1, [2, 162]), o($Vv1, [2, 163]), o($Vv1, [2, 164]), o($Vv1, [2, 165]), o($Vv1, [2, 166]), o($Vv1, [2, 167]), o($Vv1, [2, 90]), o($Vv1, [2, 91]), o($Vv1, [2, 92]), o($Vv1, [2, 93]), o($Vv1, [2, 94]), o($Vv1, [2, 95]), o($Vv1, [2, 96]), o($Vv1, [2, 97]), o($Vv1, [2, 98]), o($Vv1, [2, 99]), o($Vv1, [2, 100]), { 6: 11, 7: 12, 8: $V5, 9: $V6, 10: $V7, 11: $V8, 20: 17, 22: 18, 23: 19, 24: 20, 25: 21, 26: 22, 27: $V9, 32: [1, 203], 33: 24, 34: $Va, 36: $Vb, 38: $Vc, 42: 28, 43: 39, 44: $Vd, 45: 40, 47: 41, 60: $Ve, 84: $Vf, 85: $Vg, 86: $Vh, 87: $Vi, 88: $Vj, 89: $Vk, 102: $Vl, 105: $Vm, 106: $Vn, 109: $Vo, 111: $Vp, 113: 42, 114: $Vq, 115: $Vr, 116: $Vs, 121: $Vt, 122: $Vu, 123: $Vv, 124: $Vw, 125: $Vx }, { 10: $Vy, 18: 204 }, { 44: [1, 205] }, o($VQ, [2, 43]), { 10: [1, 206], 44: $Vd, 60: $Ve, 89: $Vk, 102: $Vl, 105: $Vm, 106: $Vn, 109: $Vo, 111: $Vp, 113: 113, 114: $Vq, 115: $Vr, 116: $Vs }, { 10: [1, 207] }, { 10: [1, 208], 106: [1, 209] }, o($Vw1, [2, 128]), { 10: [1, 210], 44: $Vd, 60: $Ve, 89: $Vk, 102: $Vl, 105: $Vm, 106: $Vn, 109: $Vo, 111: $Vp, 113: 113, 114: $Vq, 115: $Vr, 116: $Vs }, { 10: [1, 211], 44: $Vd, 60: $Ve, 89: $Vk, 102: $Vl, 105: $Vm, 106: $Vn, 109: $Vo, 111: $Vp, 113: 113, 114: $Vq, 115: $Vr, 116: $Vs }, { 80: [1, 212] }, o($Vm1, [2, 109], { 10: [1, 213] }), o($Vm1, [2, 111], { 10: [1, 214] }), { 80: [1, 215] }, o($Vn1, [2, 184]), { 80: [1, 216], 98: [1, 217] }, o($VQ, [2, 55], { 113: 113, 44: $Vd, 60: $Ve, 89: $Vk, 102: $Vl, 105: $Vm, 106: $Vn, 109: $Vo, 111: $Vp, 114: $Vq, 115: $Vr, 116: $Vs }), { 31: [1, 218], 67: $Vo1, 82: 219, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, o($Vx1, [2, 86]), o($Vx1, [2, 88]), o($Vx1, [2, 89]), o($Vx1, [2, 153]), o($Vx1, [2, 154]), o($Vx1, [2, 155]), o($Vx1, [2, 156]), { 49: [1, 220], 67: $Vo1, 82: 219, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, { 30: 221, 67: $Vo1, 80: $Vp1, 81: $Vq1, 82: 172, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, { 51: [1, 222], 67: $Vo1, 82: 219, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, { 53: [1, 223], 67: $Vo1, 82: 219, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, { 55: [1, 224], 67: $Vo1, 82: 219, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, { 57: [1, 225], 67: $Vo1, 82: 219, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, { 60: [1, 226] }, { 64: [1, 227], 67: $Vo1, 82: 219, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, { 66: [1, 228], 67: $Vo1, 82: 219, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, { 30: 229, 67: $Vo1, 80: $Vp1, 81: $Vq1, 82: 172, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, { 31: [1, 230], 67: $Vo1, 82: 219, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, { 67: $Vo1, 69: [1, 231], 71: [1, 232], 82: 219, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, { 67: $Vo1, 69: [1, 234], 71: [1, 233], 82: 219, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, o($VD, [2, 45], { 18: 156, 10: $Vy, 40: $Vl1 }), o($VD, [2, 47], { 44: $Vk1 }), o($VU, [2, 75]), o($VU, [2, 74]), { 62: [1, 235], 67: $Vo1, 82: 219, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, o($VU, [2, 77]), o($Vu1, [2, 80]), { 77: [1, 236], 79: 198, 116: $VX, 119: $VY }, { 30: 237, 67: $Vo1, 80: $Vp1, 81: $Vq1, 82: 172, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, o($Vj1, $V4, { 5: 238 }), o($Vv1, [2, 102]), o($Vz, [2, 35]), { 43: 239, 44: $Vd, 45: 40, 47: 41, 60: $Ve, 89: $Vk, 102: $Vl, 105: $Vm, 106: $Vn, 109: $Vo, 111: $Vp, 113: 42, 114: $Vq, 115: $Vr, 116: $Vs }, { 10: $Vy, 18: 240 }, { 10: $Vy1, 60: $Vz1, 84: $VA1, 92: 241, 105: $VB1, 107: 242, 108: 243, 109: $VC1, 110: $VD1, 111: $VE1, 112: $VF1 }, { 10: $Vy1, 60: $Vz1, 84: $VA1, 92: 252, 104: [1, 253], 105: $VB1, 107: 242, 108: 243, 109: $VC1, 110: $VD1, 111: $VE1, 112: $VF1 }, { 10: $Vy1, 60: $Vz1, 84: $VA1, 92: 254, 104: [1, 255], 105: $VB1, 107: 242, 108: 243, 109: $VC1, 110: $VD1, 111: $VE1, 112: $VF1 }, { 105: [1, 256] }, { 10: $Vy1, 60: $Vz1, 84: $VA1, 92: 257, 105: $VB1, 107: 242, 108: 243, 109: $VC1, 110: $VD1, 111: $VE1, 112: $VF1 }, { 44: $Vd, 47: 258, 60: $Ve, 89: $Vk, 102: $Vl, 105: $Vm, 106: $Vn, 109: $Vo, 111: $Vp, 113: 42, 114: $Vq, 115: $Vr, 116: $Vs }, o($Vm1, [2, 108]), { 80: [1, 259] }, { 80: [1, 260], 98: [1, 261] }, o($Vm1, [2, 116]), o($Vm1, [2, 118], { 10: [1, 262] }), o($Vm1, [2, 119]), o($VR, [2, 56]), o($Vx1, [2, 87]), o($VR, [2, 57]), { 51: [1, 263], 67: $Vo1, 82: 219, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, o($VR, [2, 64]), o($VR, [2, 59]), o($VR, [2, 60]), o($VR, [2, 61]), { 109: [1, 264] }, o($VR, [2, 63]), o($VR, [2, 65]), { 66: [1, 265], 67: $Vo1, 82: 219, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, o($VR, [2, 67]), o($VR, [2, 68]), o($VR, [2, 70]), o($VR, [2, 69]), o($VR, [2, 71]), o([10, 44, 60, 89, 102, 105, 106, 109, 111, 114, 115, 116], [2, 85]), o($VU, [2, 78]), { 31: [1, 266], 67: $Vo1, 82: 219, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, { 6: 11, 7: 12, 8: $V5, 9: $V6, 10: $V7, 11: $V8, 20: 17, 22: 18, 23: 19, 24: 20, 25: 21, 26: 22, 27: $V9, 32: [1, 267], 33: 24, 34: $Va, 36: $Vb, 38: $Vc, 42: 28, 43: 39, 44: $Vd, 45: 40, 47: 41, 60: $Ve, 84: $Vf, 85: $Vg, 86: $Vh, 87: $Vi, 88: $Vj, 89: $Vk, 102: $Vl, 105: $Vm, 106: $Vn, 109: $Vo, 111: $Vp, 113: 42, 114: $Vq, 115: $Vr, 116: $Vs, 121: $Vt, 122: $Vu, 123: $Vv, 124: $Vw, 125: $Vx }, o($VQ, [2, 53]), { 43: 268, 44: $Vd, 45: 40, 47: 41, 60: $Ve, 89: $Vk, 102: $Vl, 105: $Vm, 106: $Vn, 109: $Vo, 111: $Vp, 113: 42, 114: $Vq, 115: $Vr, 116: $Vs }, o($Vm1, [2, 121], { 106: $VG1 }), o($VH1, [2, 130], { 108: 270, 10: $Vy1, 60: $Vz1, 84: $VA1, 105: $VB1, 109: $VC1, 110: $VD1, 111: $VE1, 112: $VF1 }), o($VI1, [2, 132]), o($VI1, [2, 134]), o($VI1, [2, 135]), o($VI1, [2, 136]), o($VI1, [2, 137]), o($VI1, [2, 138]), o($VI1, [2, 139]), o($VI1, [2, 140]), o($VI1, [2, 141]), o($Vm1, [2, 122], { 106: $VG1 }), { 10: [1, 271] }, o($Vm1, [2, 123], { 106: $VG1 }), { 10: [1, 272] }, o($Vw1, [2, 129]), o($Vm1, [2, 105], { 106: $VG1 }), o($Vm1, [2, 106], { 113: 113, 44: $Vd, 60: $Ve, 89: $Vk, 102: $Vl, 105: $Vm, 106: $Vn, 109: $Vo, 111: $Vp, 114: $Vq, 115: $Vr, 116: $Vs }), o($Vm1, [2, 110]), o($Vm1, [2, 112], { 10: [1, 273] }), o($Vm1, [2, 113]), { 98: [1, 274] }, { 51: [1, 275] }, { 62: [1, 276] }, { 66: [1, 277] }, { 8: $VA, 9: $VB, 11: $VC, 21: 278 }, o($Vz, [2, 34]), o($VQ, [2, 52]), { 10: $Vy1, 60: $Vz1, 84: $VA1, 105: $VB1, 107: 279, 108: 243, 109: $VC1, 110: $VD1, 111: $VE1, 112: $VF1 }, o($VI1, [2, 133]), { 14: $VF, 44: $VG, 60: $VH, 89: $VI, 101: 280, 105: $VJ, 106: $VK, 109: $VL, 111: $VM, 114: $VN, 115: $VO, 116: $VP, 120: 88 }, { 14: $VF, 44: $VG, 60: $VH, 89: $VI, 101: 281, 105: $VJ, 106: $VK, 109: $VL, 111: $VM, 114: $VN, 115: $VO, 116: $VP, 120: 88 }, { 98: [1, 282] }, o($Vm1, [2, 120]), o($VR, [2, 58]), { 30: 283, 67: $Vo1, 80: $Vp1, 81: $Vq1, 82: 172, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, o($VR, [2, 66]), o($Vj1, $V4, { 5: 284 }), o($VH1, [2, 131], { 108: 270, 10: $Vy1, 60: $Vz1, 84: $VA1, 105: $VB1, 109: $VC1, 110: $VD1, 111: $VE1, 112: $VF1 }), o($Vm1, [2, 126], { 120: 168, 10: [1, 285], 14: $VF, 44: $VG, 60: $VH, 89: $VI, 105: $VJ, 106: $VK, 109: $VL, 111: $VM, 114: $VN, 115: $VO, 116: $VP }), o($Vm1, [2, 127], { 120: 168, 10: [1, 286], 14: $VF, 44: $VG, 60: $VH, 89: $VI, 105: $VJ, 106: $VK, 109: $VL, 111: $VM, 114: $VN, 115: $VO, 116: $VP }), o($Vm1, [2, 114]), { 31: [1, 287], 67: $Vo1, 82: 219, 116: $Vr1, 117: $Vs1, 118: $Vt1 }, { 6: 11, 7: 12, 8: $V5, 9: $V6, 10: $V7, 11: $V8, 20: 17, 22: 18, 23: 19, 24: 20, 25: 21, 26: 22, 27: $V9, 32: [1, 288], 33: 24, 34: $Va, 36: $Vb, 38: $Vc, 42: 28, 43: 39, 44: $Vd, 45: 40, 47: 41, 60: $Ve, 84: $Vf, 85: $Vg, 86: $Vh, 87: $Vi, 88: $Vj, 89: $Vk, 102: $Vl, 105: $Vm, 106: $Vn, 109: $Vo, 111: $Vp, 113: 42, 114: $Vq, 115: $Vr, 116: $Vs, 121: $Vt, 122: $Vu, 123: $Vv, 124: $Vw, 125: $Vx }, { 10: $Vy1, 60: $Vz1, 84: $VA1, 92: 289, 105: $VB1, 107: 242, 108: 243, 109: $VC1, 110: $VD1, 111: $VE1, 112: $VF1 }, { 10: $Vy1, 60: $Vz1, 84: $VA1, 92: 290, 105: $VB1, 107: 242, 108: 243, 109: $VC1, 110: $VD1, 111: $VE1, 112: $VF1 }, o($VR, [2, 62]), o($Vz, [2, 33]), o($Vm1, [2, 124], { 106: $VG1 }), o($Vm1, [2, 125], { 106: $VG1 })],
|
|
378
|
+
defaultActions: {},
|
|
379
|
+
parseError: function parseError(str, hash) {
|
|
380
|
+
if (hash.recoverable) {
|
|
381
|
+
this.trace(str);
|
|
382
|
+
} else {
|
|
383
|
+
var error = new Error(str);
|
|
384
|
+
error.hash = hash;
|
|
385
|
+
throw error;
|
|
386
|
+
}
|
|
387
|
+
},
|
|
388
|
+
parse: function parse2(input) {
|
|
389
|
+
var self = this, stack = [0], tstack = [], vstack = [null], lstack = [], table = this.table, yytext = "", yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1;
|
|
390
|
+
var args = lstack.slice.call(arguments, 1);
|
|
391
|
+
var lexer2 = Object.create(this.lexer);
|
|
392
|
+
var sharedState = { yy: {} };
|
|
393
|
+
for (var k in this.yy) {
|
|
394
|
+
if (Object.prototype.hasOwnProperty.call(this.yy, k)) {
|
|
395
|
+
sharedState.yy[k] = this.yy[k];
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
lexer2.setInput(input, sharedState.yy);
|
|
399
|
+
sharedState.yy.lexer = lexer2;
|
|
400
|
+
sharedState.yy.parser = this;
|
|
401
|
+
if (typeof lexer2.yylloc == "undefined") {
|
|
402
|
+
lexer2.yylloc = {};
|
|
403
|
+
}
|
|
404
|
+
var yyloc = lexer2.yylloc;
|
|
405
|
+
lstack.push(yyloc);
|
|
406
|
+
var ranges = lexer2.options && lexer2.options.ranges;
|
|
407
|
+
if (typeof sharedState.yy.parseError === "function") {
|
|
408
|
+
this.parseError = sharedState.yy.parseError;
|
|
409
|
+
} else {
|
|
410
|
+
this.parseError = Object.getPrototypeOf(this).parseError;
|
|
411
|
+
}
|
|
412
|
+
function popStack(n) {
|
|
413
|
+
stack.length = stack.length - 2 * n;
|
|
414
|
+
vstack.length = vstack.length - n;
|
|
415
|
+
lstack.length = lstack.length - n;
|
|
416
|
+
}
|
|
417
|
+
_token_stack:
|
|
418
|
+
var lex = function() {
|
|
419
|
+
var token;
|
|
420
|
+
token = lexer2.lex() || EOF;
|
|
421
|
+
if (typeof token !== "number") {
|
|
422
|
+
token = self.symbols_[token] || token;
|
|
423
|
+
}
|
|
424
|
+
return token;
|
|
425
|
+
};
|
|
426
|
+
var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;
|
|
427
|
+
while (true) {
|
|
428
|
+
state = stack[stack.length - 1];
|
|
429
|
+
if (this.defaultActions[state]) {
|
|
430
|
+
action = this.defaultActions[state];
|
|
431
|
+
} else {
|
|
432
|
+
if (symbol === null || typeof symbol == "undefined") {
|
|
433
|
+
symbol = lex();
|
|
434
|
+
}
|
|
435
|
+
action = table[state] && table[state][symbol];
|
|
436
|
+
}
|
|
437
|
+
if (typeof action === "undefined" || !action.length || !action[0]) {
|
|
438
|
+
var errStr = "";
|
|
439
|
+
expected = [];
|
|
440
|
+
for (p in table[state]) {
|
|
441
|
+
if (this.terminals_[p] && p > TERROR) {
|
|
442
|
+
expected.push("'" + this.terminals_[p] + "'");
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
if (lexer2.showPosition) {
|
|
446
|
+
errStr = "Parse error on line " + (yylineno + 1) + ":\n" + lexer2.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + (this.terminals_[symbol] || symbol) + "'";
|
|
447
|
+
} else {
|
|
448
|
+
errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == EOF ? "end of input" : "'" + (this.terminals_[symbol] || symbol) + "'");
|
|
449
|
+
}
|
|
450
|
+
this.parseError(errStr, {
|
|
451
|
+
text: lexer2.match,
|
|
452
|
+
token: this.terminals_[symbol] || symbol,
|
|
453
|
+
line: lexer2.yylineno,
|
|
454
|
+
loc: yyloc,
|
|
455
|
+
expected
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
if (action[0] instanceof Array && action.length > 1) {
|
|
459
|
+
throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol);
|
|
460
|
+
}
|
|
461
|
+
switch (action[0]) {
|
|
462
|
+
case 1:
|
|
463
|
+
stack.push(symbol);
|
|
464
|
+
vstack.push(lexer2.yytext);
|
|
465
|
+
lstack.push(lexer2.yylloc);
|
|
466
|
+
stack.push(action[1]);
|
|
467
|
+
symbol = null;
|
|
468
|
+
if (!preErrorSymbol) {
|
|
469
|
+
yyleng = lexer2.yyleng;
|
|
470
|
+
yytext = lexer2.yytext;
|
|
471
|
+
yylineno = lexer2.yylineno;
|
|
472
|
+
yyloc = lexer2.yylloc;
|
|
473
|
+
if (recovering > 0) {
|
|
474
|
+
recovering--;
|
|
475
|
+
}
|
|
476
|
+
} else {
|
|
477
|
+
symbol = preErrorSymbol;
|
|
478
|
+
preErrorSymbol = null;
|
|
479
|
+
}
|
|
480
|
+
break;
|
|
481
|
+
case 2:
|
|
482
|
+
len = this.productions_[action[1]][1];
|
|
483
|
+
yyval.$ = vstack[vstack.length - len];
|
|
484
|
+
yyval._$ = {
|
|
485
|
+
first_line: lstack[lstack.length - (len || 1)].first_line,
|
|
486
|
+
last_line: lstack[lstack.length - 1].last_line,
|
|
487
|
+
first_column: lstack[lstack.length - (len || 1)].first_column,
|
|
488
|
+
last_column: lstack[lstack.length - 1].last_column
|
|
489
|
+
};
|
|
490
|
+
if (ranges) {
|
|
491
|
+
yyval._$.range = [
|
|
492
|
+
lstack[lstack.length - (len || 1)].range[0],
|
|
493
|
+
lstack[lstack.length - 1].range[1]
|
|
494
|
+
];
|
|
495
|
+
}
|
|
496
|
+
r = this.performAction.apply(yyval, [
|
|
497
|
+
yytext,
|
|
498
|
+
yyleng,
|
|
499
|
+
yylineno,
|
|
500
|
+
sharedState.yy,
|
|
501
|
+
action[1],
|
|
502
|
+
vstack,
|
|
503
|
+
lstack
|
|
504
|
+
].concat(args));
|
|
505
|
+
if (typeof r !== "undefined") {
|
|
506
|
+
return r;
|
|
507
|
+
}
|
|
508
|
+
if (len) {
|
|
509
|
+
stack = stack.slice(0, -1 * len * 2);
|
|
510
|
+
vstack = vstack.slice(0, -1 * len);
|
|
511
|
+
lstack = lstack.slice(0, -1 * len);
|
|
512
|
+
}
|
|
513
|
+
stack.push(this.productions_[action[1]][0]);
|
|
514
|
+
vstack.push(yyval.$);
|
|
515
|
+
lstack.push(yyval._$);
|
|
516
|
+
newState = table[stack[stack.length - 2]][stack[stack.length - 1]];
|
|
517
|
+
stack.push(newState);
|
|
518
|
+
break;
|
|
519
|
+
case 3:
|
|
520
|
+
return true;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
return true;
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
var lexer = /* @__PURE__ */ (function() {
|
|
527
|
+
var lexer2 = {
|
|
528
|
+
EOF: 1,
|
|
529
|
+
parseError: function parseError(str, hash) {
|
|
530
|
+
if (this.yy.parser) {
|
|
531
|
+
this.yy.parser.parseError(str, hash);
|
|
532
|
+
} else {
|
|
533
|
+
throw new Error(str);
|
|
534
|
+
}
|
|
535
|
+
},
|
|
536
|
+
// resets the lexer, sets new input
|
|
537
|
+
setInput: function(input, yy) {
|
|
538
|
+
this.yy = yy || this.yy || {};
|
|
539
|
+
this._input = input;
|
|
540
|
+
this._more = this._backtrack = this.done = false;
|
|
541
|
+
this.yylineno = this.yyleng = 0;
|
|
542
|
+
this.yytext = this.matched = this.match = "";
|
|
543
|
+
this.conditionStack = ["INITIAL"];
|
|
544
|
+
this.yylloc = {
|
|
545
|
+
first_line: 1,
|
|
546
|
+
first_column: 0,
|
|
547
|
+
last_line: 1,
|
|
548
|
+
last_column: 0
|
|
549
|
+
};
|
|
550
|
+
if (this.options.ranges) {
|
|
551
|
+
this.yylloc.range = [0, 0];
|
|
552
|
+
}
|
|
553
|
+
this.offset = 0;
|
|
554
|
+
return this;
|
|
555
|
+
},
|
|
556
|
+
// consumes and returns one char from the input
|
|
557
|
+
input: function() {
|
|
558
|
+
var ch = this._input[0];
|
|
559
|
+
this.yytext += ch;
|
|
560
|
+
this.yyleng++;
|
|
561
|
+
this.offset++;
|
|
562
|
+
this.match += ch;
|
|
563
|
+
this.matched += ch;
|
|
564
|
+
var lines = ch.match(/(?:\r\n?|\n).*/g);
|
|
565
|
+
if (lines) {
|
|
566
|
+
this.yylineno++;
|
|
567
|
+
this.yylloc.last_line++;
|
|
568
|
+
} else {
|
|
569
|
+
this.yylloc.last_column++;
|
|
570
|
+
}
|
|
571
|
+
if (this.options.ranges) {
|
|
572
|
+
this.yylloc.range[1]++;
|
|
573
|
+
}
|
|
574
|
+
this._input = this._input.slice(1);
|
|
575
|
+
return ch;
|
|
576
|
+
},
|
|
577
|
+
// unshifts one char (or a string) into the input
|
|
578
|
+
unput: function(ch) {
|
|
579
|
+
var len = ch.length;
|
|
580
|
+
var lines = ch.split(/(?:\r\n?|\n)/g);
|
|
581
|
+
this._input = ch + this._input;
|
|
582
|
+
this.yytext = this.yytext.substr(0, this.yytext.length - len);
|
|
583
|
+
this.offset -= len;
|
|
584
|
+
var oldLines = this.match.split(/(?:\r\n?|\n)/g);
|
|
585
|
+
this.match = this.match.substr(0, this.match.length - 1);
|
|
586
|
+
this.matched = this.matched.substr(0, this.matched.length - 1);
|
|
587
|
+
if (lines.length - 1) {
|
|
588
|
+
this.yylineno -= lines.length - 1;
|
|
589
|
+
}
|
|
590
|
+
var r = this.yylloc.range;
|
|
591
|
+
this.yylloc = {
|
|
592
|
+
first_line: this.yylloc.first_line,
|
|
593
|
+
last_line: this.yylineno + 1,
|
|
594
|
+
first_column: this.yylloc.first_column,
|
|
595
|
+
last_column: lines ? (lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length : this.yylloc.first_column - len
|
|
596
|
+
};
|
|
597
|
+
if (this.options.ranges) {
|
|
598
|
+
this.yylloc.range = [r[0], r[0] + this.yyleng - len];
|
|
599
|
+
}
|
|
600
|
+
this.yyleng = this.yytext.length;
|
|
601
|
+
return this;
|
|
602
|
+
},
|
|
603
|
+
// When called from action, caches matched text and appends it on next action
|
|
604
|
+
more: function() {
|
|
605
|
+
this._more = true;
|
|
606
|
+
return this;
|
|
607
|
+
},
|
|
608
|
+
// When called from action, signals the lexer that this rule fails to match the input, so the next matching rule (regex) should be tested instead.
|
|
609
|
+
reject: function() {
|
|
610
|
+
if (this.options.backtrack_lexer) {
|
|
611
|
+
this._backtrack = true;
|
|
612
|
+
} else {
|
|
613
|
+
return this.parseError("Lexical error on line " + (this.yylineno + 1) + ". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n" + this.showPosition(), {
|
|
614
|
+
text: "",
|
|
615
|
+
token: null,
|
|
616
|
+
line: this.yylineno
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
return this;
|
|
620
|
+
},
|
|
621
|
+
// retain first n characters of the match
|
|
622
|
+
less: function(n) {
|
|
623
|
+
this.unput(this.match.slice(n));
|
|
624
|
+
},
|
|
625
|
+
// displays already matched input, i.e. for error messages
|
|
626
|
+
pastInput: function() {
|
|
627
|
+
var past = this.matched.substr(0, this.matched.length - this.match.length);
|
|
628
|
+
return (past.length > 20 ? "..." : "") + past.substr(-20).replace(/\n/g, "");
|
|
629
|
+
},
|
|
630
|
+
// displays upcoming input, i.e. for error messages
|
|
631
|
+
upcomingInput: function() {
|
|
632
|
+
var next = this.match;
|
|
633
|
+
if (next.length < 20) {
|
|
634
|
+
next += this._input.substr(0, 20 - next.length);
|
|
635
|
+
}
|
|
636
|
+
return (next.substr(0, 20) + (next.length > 20 ? "..." : "")).replace(/\n/g, "");
|
|
637
|
+
},
|
|
638
|
+
// displays the character position where the lexing error occurred, i.e. for error messages
|
|
639
|
+
showPosition: function() {
|
|
640
|
+
var pre = this.pastInput();
|
|
641
|
+
var c = new Array(pre.length + 1).join("-");
|
|
642
|
+
return pre + this.upcomingInput() + "\n" + c + "^";
|
|
643
|
+
},
|
|
644
|
+
// test the lexed token: return FALSE when not a match, otherwise return token
|
|
645
|
+
test_match: function(match, indexed_rule) {
|
|
646
|
+
var token, lines, backup;
|
|
647
|
+
if (this.options.backtrack_lexer) {
|
|
648
|
+
backup = {
|
|
649
|
+
yylineno: this.yylineno,
|
|
650
|
+
yylloc: {
|
|
651
|
+
first_line: this.yylloc.first_line,
|
|
652
|
+
last_line: this.last_line,
|
|
653
|
+
first_column: this.yylloc.first_column,
|
|
654
|
+
last_column: this.yylloc.last_column
|
|
655
|
+
},
|
|
656
|
+
yytext: this.yytext,
|
|
657
|
+
match: this.match,
|
|
658
|
+
matches: this.matches,
|
|
659
|
+
matched: this.matched,
|
|
660
|
+
yyleng: this.yyleng,
|
|
661
|
+
offset: this.offset,
|
|
662
|
+
_more: this._more,
|
|
663
|
+
_input: this._input,
|
|
664
|
+
yy: this.yy,
|
|
665
|
+
conditionStack: this.conditionStack.slice(0),
|
|
666
|
+
done: this.done
|
|
667
|
+
};
|
|
668
|
+
if (this.options.ranges) {
|
|
669
|
+
backup.yylloc.range = this.yylloc.range.slice(0);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
lines = match[0].match(/(?:\r\n?|\n).*/g);
|
|
673
|
+
if (lines) {
|
|
674
|
+
this.yylineno += lines.length;
|
|
675
|
+
}
|
|
676
|
+
this.yylloc = {
|
|
677
|
+
first_line: this.yylloc.last_line,
|
|
678
|
+
last_line: this.yylineno + 1,
|
|
679
|
+
first_column: this.yylloc.last_column,
|
|
680
|
+
last_column: lines ? lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length : this.yylloc.last_column + match[0].length
|
|
681
|
+
};
|
|
682
|
+
this.yytext += match[0];
|
|
683
|
+
this.match += match[0];
|
|
684
|
+
this.matches = match;
|
|
685
|
+
this.yyleng = this.yytext.length;
|
|
686
|
+
if (this.options.ranges) {
|
|
687
|
+
this.yylloc.range = [this.offset, this.offset += this.yyleng];
|
|
688
|
+
}
|
|
689
|
+
this._more = false;
|
|
690
|
+
this._backtrack = false;
|
|
691
|
+
this._input = this._input.slice(match[0].length);
|
|
692
|
+
this.matched += match[0];
|
|
693
|
+
token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]);
|
|
694
|
+
if (this.done && this._input) {
|
|
695
|
+
this.done = false;
|
|
696
|
+
}
|
|
697
|
+
if (token) {
|
|
698
|
+
return token;
|
|
699
|
+
} else if (this._backtrack) {
|
|
700
|
+
for (var k in backup) {
|
|
701
|
+
this[k] = backup[k];
|
|
702
|
+
}
|
|
703
|
+
return false;
|
|
704
|
+
}
|
|
705
|
+
return false;
|
|
706
|
+
},
|
|
707
|
+
// return next match in input
|
|
708
|
+
next: function() {
|
|
709
|
+
if (this.done) {
|
|
710
|
+
return this.EOF;
|
|
711
|
+
}
|
|
712
|
+
if (!this._input) {
|
|
713
|
+
this.done = true;
|
|
714
|
+
}
|
|
715
|
+
var token, match, tempMatch, index;
|
|
716
|
+
if (!this._more) {
|
|
717
|
+
this.yytext = "";
|
|
718
|
+
this.match = "";
|
|
719
|
+
}
|
|
720
|
+
var rules = this._currentRules();
|
|
721
|
+
for (var i = 0; i < rules.length; i++) {
|
|
722
|
+
tempMatch = this._input.match(this.rules[rules[i]]);
|
|
723
|
+
if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
|
|
724
|
+
match = tempMatch;
|
|
725
|
+
index = i;
|
|
726
|
+
if (this.options.backtrack_lexer) {
|
|
727
|
+
token = this.test_match(tempMatch, rules[i]);
|
|
728
|
+
if (token !== false) {
|
|
729
|
+
return token;
|
|
730
|
+
} else if (this._backtrack) {
|
|
731
|
+
match = false;
|
|
732
|
+
continue;
|
|
733
|
+
} else {
|
|
734
|
+
return false;
|
|
735
|
+
}
|
|
736
|
+
} else if (!this.options.flex) {
|
|
737
|
+
break;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
if (match) {
|
|
742
|
+
token = this.test_match(match, rules[index]);
|
|
743
|
+
if (token !== false) {
|
|
744
|
+
return token;
|
|
745
|
+
}
|
|
746
|
+
return false;
|
|
747
|
+
}
|
|
748
|
+
if (this._input === "") {
|
|
749
|
+
return this.EOF;
|
|
750
|
+
} else {
|
|
751
|
+
return this.parseError("Lexical error on line " + (this.yylineno + 1) + ". Unrecognized text.\n" + this.showPosition(), {
|
|
752
|
+
text: "",
|
|
753
|
+
token: null,
|
|
754
|
+
line: this.yylineno
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
},
|
|
758
|
+
// return next match that has a token
|
|
759
|
+
lex: function lex() {
|
|
760
|
+
var r = this.next();
|
|
761
|
+
if (r) {
|
|
762
|
+
return r;
|
|
763
|
+
} else {
|
|
764
|
+
return this.lex();
|
|
765
|
+
}
|
|
766
|
+
},
|
|
767
|
+
// activates a new lexer condition state (pushes the new lexer condition state onto the condition stack)
|
|
768
|
+
begin: function begin(condition) {
|
|
769
|
+
this.conditionStack.push(condition);
|
|
770
|
+
},
|
|
771
|
+
// pop the previously active lexer condition state off the condition stack
|
|
772
|
+
popState: function popState() {
|
|
773
|
+
var n = this.conditionStack.length - 1;
|
|
774
|
+
if (n > 0) {
|
|
775
|
+
return this.conditionStack.pop();
|
|
776
|
+
} else {
|
|
777
|
+
return this.conditionStack[0];
|
|
778
|
+
}
|
|
779
|
+
},
|
|
780
|
+
// produce the lexer rule set which is active for the currently active lexer condition state
|
|
781
|
+
_currentRules: function _currentRules() {
|
|
782
|
+
if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) {
|
|
783
|
+
return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules;
|
|
784
|
+
} else {
|
|
785
|
+
return this.conditions["INITIAL"].rules;
|
|
786
|
+
}
|
|
787
|
+
},
|
|
788
|
+
// return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available
|
|
789
|
+
topState: function topState(n) {
|
|
790
|
+
n = this.conditionStack.length - 1 - Math.abs(n || 0);
|
|
791
|
+
if (n >= 0) {
|
|
792
|
+
return this.conditionStack[n];
|
|
793
|
+
} else {
|
|
794
|
+
return "INITIAL";
|
|
795
|
+
}
|
|
796
|
+
},
|
|
797
|
+
// alias for begin(condition)
|
|
798
|
+
pushState: function pushState(condition) {
|
|
799
|
+
this.begin(condition);
|
|
800
|
+
},
|
|
801
|
+
// return the number of states currently on the stack
|
|
802
|
+
stateStackSize: function stateStackSize() {
|
|
803
|
+
return this.conditionStack.length;
|
|
804
|
+
},
|
|
805
|
+
options: {},
|
|
806
|
+
performAction: function anonymous(yy, yy_, $avoiding_name_collisions, YY_START) {
|
|
807
|
+
var YYSTATE = YY_START;
|
|
808
|
+
switch ($avoiding_name_collisions) {
|
|
809
|
+
case 0:
|
|
810
|
+
this.begin("acc_title");
|
|
811
|
+
return 34;
|
|
812
|
+
break;
|
|
813
|
+
case 1:
|
|
814
|
+
this.popState();
|
|
815
|
+
return "acc_title_value";
|
|
816
|
+
break;
|
|
817
|
+
case 2:
|
|
818
|
+
this.begin("acc_descr");
|
|
819
|
+
return 36;
|
|
820
|
+
break;
|
|
821
|
+
case 3:
|
|
822
|
+
this.popState();
|
|
823
|
+
return "acc_descr_value";
|
|
824
|
+
break;
|
|
825
|
+
case 4:
|
|
826
|
+
this.begin("acc_descr_multiline");
|
|
827
|
+
break;
|
|
828
|
+
case 5:
|
|
829
|
+
this.popState();
|
|
830
|
+
break;
|
|
831
|
+
case 6:
|
|
832
|
+
return "acc_descr_multiline_value";
|
|
833
|
+
break;
|
|
834
|
+
case 7:
|
|
835
|
+
this.pushState("shapeData");
|
|
836
|
+
yy_.yytext = "";
|
|
837
|
+
return 40;
|
|
838
|
+
break;
|
|
839
|
+
case 8:
|
|
840
|
+
this.pushState("shapeDataStr");
|
|
841
|
+
return 40;
|
|
842
|
+
break;
|
|
843
|
+
case 9:
|
|
844
|
+
this.popState();
|
|
845
|
+
return 40;
|
|
846
|
+
break;
|
|
847
|
+
case 10:
|
|
848
|
+
const re = /\n\s*/g;
|
|
849
|
+
yy_.yytext = yy_.yytext.replace(re, "<br/>");
|
|
850
|
+
return 40;
|
|
851
|
+
break;
|
|
852
|
+
case 11:
|
|
853
|
+
return 40;
|
|
854
|
+
break;
|
|
855
|
+
case 12:
|
|
856
|
+
this.popState();
|
|
857
|
+
break;
|
|
858
|
+
case 13:
|
|
859
|
+
this.begin("callbackname");
|
|
860
|
+
break;
|
|
861
|
+
case 14:
|
|
862
|
+
this.popState();
|
|
863
|
+
break;
|
|
864
|
+
case 15:
|
|
865
|
+
this.popState();
|
|
866
|
+
this.begin("callbackargs");
|
|
867
|
+
break;
|
|
868
|
+
case 16:
|
|
869
|
+
return 95;
|
|
870
|
+
break;
|
|
871
|
+
case 17:
|
|
872
|
+
this.popState();
|
|
873
|
+
break;
|
|
874
|
+
case 18:
|
|
875
|
+
return 96;
|
|
876
|
+
break;
|
|
877
|
+
case 19:
|
|
878
|
+
return "MD_STR";
|
|
879
|
+
break;
|
|
880
|
+
case 20:
|
|
881
|
+
this.popState();
|
|
882
|
+
break;
|
|
883
|
+
case 21:
|
|
884
|
+
this.begin("md_string");
|
|
885
|
+
break;
|
|
886
|
+
case 22:
|
|
887
|
+
return "STR";
|
|
888
|
+
break;
|
|
889
|
+
case 23:
|
|
890
|
+
this.popState();
|
|
891
|
+
break;
|
|
892
|
+
case 24:
|
|
893
|
+
this.pushState("string");
|
|
894
|
+
break;
|
|
895
|
+
case 25:
|
|
896
|
+
return 84;
|
|
897
|
+
break;
|
|
898
|
+
case 26:
|
|
899
|
+
return 102;
|
|
900
|
+
break;
|
|
901
|
+
case 27:
|
|
902
|
+
return 85;
|
|
903
|
+
break;
|
|
904
|
+
case 28:
|
|
905
|
+
return 104;
|
|
906
|
+
break;
|
|
907
|
+
case 29:
|
|
908
|
+
return 86;
|
|
909
|
+
break;
|
|
910
|
+
case 30:
|
|
911
|
+
return 87;
|
|
912
|
+
break;
|
|
913
|
+
case 31:
|
|
914
|
+
return 97;
|
|
915
|
+
break;
|
|
916
|
+
case 32:
|
|
917
|
+
this.begin("click");
|
|
918
|
+
break;
|
|
919
|
+
case 33:
|
|
920
|
+
this.popState();
|
|
921
|
+
break;
|
|
922
|
+
case 34:
|
|
923
|
+
return 88;
|
|
924
|
+
break;
|
|
925
|
+
case 35:
|
|
926
|
+
if (yy.lex.firstGraph()) {
|
|
927
|
+
this.begin("dir");
|
|
928
|
+
}
|
|
929
|
+
return 12;
|
|
930
|
+
break;
|
|
931
|
+
case 36:
|
|
932
|
+
if (yy.lex.firstGraph()) {
|
|
933
|
+
this.begin("dir");
|
|
934
|
+
}
|
|
935
|
+
return 12;
|
|
936
|
+
break;
|
|
937
|
+
case 37:
|
|
938
|
+
if (yy.lex.firstGraph()) {
|
|
939
|
+
this.begin("dir");
|
|
940
|
+
}
|
|
941
|
+
return 12;
|
|
942
|
+
break;
|
|
943
|
+
case 38:
|
|
944
|
+
if (yy.lex.firstGraph()) {
|
|
945
|
+
this.begin("dir");
|
|
946
|
+
}
|
|
947
|
+
return 12;
|
|
948
|
+
break;
|
|
949
|
+
case 39:
|
|
950
|
+
return 27;
|
|
951
|
+
break;
|
|
952
|
+
case 40:
|
|
953
|
+
return 32;
|
|
954
|
+
break;
|
|
955
|
+
case 41:
|
|
956
|
+
return 98;
|
|
957
|
+
break;
|
|
958
|
+
case 42:
|
|
959
|
+
return 98;
|
|
960
|
+
break;
|
|
961
|
+
case 43:
|
|
962
|
+
return 98;
|
|
963
|
+
break;
|
|
964
|
+
case 44:
|
|
965
|
+
return 98;
|
|
966
|
+
break;
|
|
967
|
+
case 45:
|
|
968
|
+
this.popState();
|
|
969
|
+
return 13;
|
|
970
|
+
break;
|
|
971
|
+
case 46:
|
|
972
|
+
this.popState();
|
|
973
|
+
return 14;
|
|
974
|
+
break;
|
|
975
|
+
case 47:
|
|
976
|
+
this.popState();
|
|
977
|
+
return 14;
|
|
978
|
+
break;
|
|
979
|
+
case 48:
|
|
980
|
+
this.popState();
|
|
981
|
+
return 14;
|
|
982
|
+
break;
|
|
983
|
+
case 49:
|
|
984
|
+
this.popState();
|
|
985
|
+
return 14;
|
|
986
|
+
break;
|
|
987
|
+
case 50:
|
|
988
|
+
this.popState();
|
|
989
|
+
return 14;
|
|
990
|
+
break;
|
|
991
|
+
case 51:
|
|
992
|
+
this.popState();
|
|
993
|
+
return 14;
|
|
994
|
+
break;
|
|
995
|
+
case 52:
|
|
996
|
+
this.popState();
|
|
997
|
+
return 14;
|
|
998
|
+
break;
|
|
999
|
+
case 53:
|
|
1000
|
+
this.popState();
|
|
1001
|
+
return 14;
|
|
1002
|
+
break;
|
|
1003
|
+
case 54:
|
|
1004
|
+
this.popState();
|
|
1005
|
+
return 14;
|
|
1006
|
+
break;
|
|
1007
|
+
case 55:
|
|
1008
|
+
this.popState();
|
|
1009
|
+
return 14;
|
|
1010
|
+
break;
|
|
1011
|
+
case 56:
|
|
1012
|
+
return 121;
|
|
1013
|
+
break;
|
|
1014
|
+
case 57:
|
|
1015
|
+
return 122;
|
|
1016
|
+
break;
|
|
1017
|
+
case 58:
|
|
1018
|
+
return 123;
|
|
1019
|
+
break;
|
|
1020
|
+
case 59:
|
|
1021
|
+
return 124;
|
|
1022
|
+
break;
|
|
1023
|
+
case 60:
|
|
1024
|
+
return 125;
|
|
1025
|
+
break;
|
|
1026
|
+
case 61:
|
|
1027
|
+
return 78;
|
|
1028
|
+
break;
|
|
1029
|
+
case 62:
|
|
1030
|
+
return 105;
|
|
1031
|
+
break;
|
|
1032
|
+
case 63:
|
|
1033
|
+
return 111;
|
|
1034
|
+
break;
|
|
1035
|
+
case 64:
|
|
1036
|
+
return 46;
|
|
1037
|
+
break;
|
|
1038
|
+
case 65:
|
|
1039
|
+
return 60;
|
|
1040
|
+
break;
|
|
1041
|
+
case 66:
|
|
1042
|
+
return 44;
|
|
1043
|
+
break;
|
|
1044
|
+
case 67:
|
|
1045
|
+
return 8;
|
|
1046
|
+
break;
|
|
1047
|
+
case 68:
|
|
1048
|
+
return 106;
|
|
1049
|
+
break;
|
|
1050
|
+
case 69:
|
|
1051
|
+
return 115;
|
|
1052
|
+
break;
|
|
1053
|
+
case 70:
|
|
1054
|
+
this.popState();
|
|
1055
|
+
return 77;
|
|
1056
|
+
break;
|
|
1057
|
+
case 71:
|
|
1058
|
+
this.pushState("edgeText");
|
|
1059
|
+
return 75;
|
|
1060
|
+
break;
|
|
1061
|
+
case 72:
|
|
1062
|
+
return 119;
|
|
1063
|
+
break;
|
|
1064
|
+
case 73:
|
|
1065
|
+
this.popState();
|
|
1066
|
+
return 77;
|
|
1067
|
+
break;
|
|
1068
|
+
case 74:
|
|
1069
|
+
this.pushState("thickEdgeText");
|
|
1070
|
+
return 75;
|
|
1071
|
+
break;
|
|
1072
|
+
case 75:
|
|
1073
|
+
return 119;
|
|
1074
|
+
break;
|
|
1075
|
+
case 76:
|
|
1076
|
+
this.popState();
|
|
1077
|
+
return 77;
|
|
1078
|
+
break;
|
|
1079
|
+
case 77:
|
|
1080
|
+
this.pushState("dottedEdgeText");
|
|
1081
|
+
return 75;
|
|
1082
|
+
break;
|
|
1083
|
+
case 78:
|
|
1084
|
+
return 119;
|
|
1085
|
+
break;
|
|
1086
|
+
case 79:
|
|
1087
|
+
return 77;
|
|
1088
|
+
break;
|
|
1089
|
+
case 80:
|
|
1090
|
+
this.popState();
|
|
1091
|
+
return 53;
|
|
1092
|
+
break;
|
|
1093
|
+
case 81:
|
|
1094
|
+
return "TEXT";
|
|
1095
|
+
break;
|
|
1096
|
+
case 82:
|
|
1097
|
+
this.pushState("ellipseText");
|
|
1098
|
+
return 52;
|
|
1099
|
+
break;
|
|
1100
|
+
case 83:
|
|
1101
|
+
this.popState();
|
|
1102
|
+
return 55;
|
|
1103
|
+
break;
|
|
1104
|
+
case 84:
|
|
1105
|
+
this.pushState("text");
|
|
1106
|
+
return 54;
|
|
1107
|
+
break;
|
|
1108
|
+
case 85:
|
|
1109
|
+
this.popState();
|
|
1110
|
+
return 57;
|
|
1111
|
+
break;
|
|
1112
|
+
case 86:
|
|
1113
|
+
this.pushState("text");
|
|
1114
|
+
return 56;
|
|
1115
|
+
break;
|
|
1116
|
+
case 87:
|
|
1117
|
+
return 58;
|
|
1118
|
+
break;
|
|
1119
|
+
case 88:
|
|
1120
|
+
this.pushState("text");
|
|
1121
|
+
return 67;
|
|
1122
|
+
break;
|
|
1123
|
+
case 89:
|
|
1124
|
+
this.popState();
|
|
1125
|
+
return 64;
|
|
1126
|
+
break;
|
|
1127
|
+
case 90:
|
|
1128
|
+
this.pushState("text");
|
|
1129
|
+
return 63;
|
|
1130
|
+
break;
|
|
1131
|
+
case 91:
|
|
1132
|
+
this.popState();
|
|
1133
|
+
return 49;
|
|
1134
|
+
break;
|
|
1135
|
+
case 92:
|
|
1136
|
+
this.pushState("text");
|
|
1137
|
+
return 48;
|
|
1138
|
+
break;
|
|
1139
|
+
case 93:
|
|
1140
|
+
this.popState();
|
|
1141
|
+
return 69;
|
|
1142
|
+
break;
|
|
1143
|
+
case 94:
|
|
1144
|
+
this.popState();
|
|
1145
|
+
return 71;
|
|
1146
|
+
break;
|
|
1147
|
+
case 95:
|
|
1148
|
+
return 117;
|
|
1149
|
+
break;
|
|
1150
|
+
case 96:
|
|
1151
|
+
this.pushState("trapText");
|
|
1152
|
+
return 68;
|
|
1153
|
+
break;
|
|
1154
|
+
case 97:
|
|
1155
|
+
this.pushState("trapText");
|
|
1156
|
+
return 70;
|
|
1157
|
+
break;
|
|
1158
|
+
case 98:
|
|
1159
|
+
return 118;
|
|
1160
|
+
break;
|
|
1161
|
+
case 99:
|
|
1162
|
+
return 67;
|
|
1163
|
+
break;
|
|
1164
|
+
case 100:
|
|
1165
|
+
return 90;
|
|
1166
|
+
break;
|
|
1167
|
+
case 101:
|
|
1168
|
+
return "SEP";
|
|
1169
|
+
break;
|
|
1170
|
+
case 102:
|
|
1171
|
+
return 89;
|
|
1172
|
+
break;
|
|
1173
|
+
case 103:
|
|
1174
|
+
return 115;
|
|
1175
|
+
break;
|
|
1176
|
+
case 104:
|
|
1177
|
+
return 111;
|
|
1178
|
+
break;
|
|
1179
|
+
case 105:
|
|
1180
|
+
return 44;
|
|
1181
|
+
break;
|
|
1182
|
+
case 106:
|
|
1183
|
+
return 109;
|
|
1184
|
+
break;
|
|
1185
|
+
case 107:
|
|
1186
|
+
return 114;
|
|
1187
|
+
break;
|
|
1188
|
+
case 108:
|
|
1189
|
+
return 116;
|
|
1190
|
+
break;
|
|
1191
|
+
case 109:
|
|
1192
|
+
this.popState();
|
|
1193
|
+
return 62;
|
|
1194
|
+
break;
|
|
1195
|
+
case 110:
|
|
1196
|
+
this.pushState("text");
|
|
1197
|
+
return 62;
|
|
1198
|
+
break;
|
|
1199
|
+
case 111:
|
|
1200
|
+
this.popState();
|
|
1201
|
+
return 51;
|
|
1202
|
+
break;
|
|
1203
|
+
case 112:
|
|
1204
|
+
this.pushState("text");
|
|
1205
|
+
return 50;
|
|
1206
|
+
break;
|
|
1207
|
+
case 113:
|
|
1208
|
+
this.popState();
|
|
1209
|
+
return 31;
|
|
1210
|
+
break;
|
|
1211
|
+
case 114:
|
|
1212
|
+
this.pushState("text");
|
|
1213
|
+
return 29;
|
|
1214
|
+
break;
|
|
1215
|
+
case 115:
|
|
1216
|
+
this.popState();
|
|
1217
|
+
return 66;
|
|
1218
|
+
break;
|
|
1219
|
+
case 116:
|
|
1220
|
+
this.pushState("text");
|
|
1221
|
+
return 65;
|
|
1222
|
+
break;
|
|
1223
|
+
case 117:
|
|
1224
|
+
return "TEXT";
|
|
1225
|
+
break;
|
|
1226
|
+
case 118:
|
|
1227
|
+
return "QUOTE";
|
|
1228
|
+
break;
|
|
1229
|
+
case 119:
|
|
1230
|
+
return 9;
|
|
1231
|
+
break;
|
|
1232
|
+
case 120:
|
|
1233
|
+
return 10;
|
|
1234
|
+
break;
|
|
1235
|
+
case 121:
|
|
1236
|
+
return 11;
|
|
1237
|
+
break;
|
|
1238
|
+
}
|
|
1239
|
+
},
|
|
1240
|
+
rules: [/^(?:accTitle\s*:\s*)/, /^(?:(?!\n||)*[^\n]*)/, /^(?:accDescr\s*:\s*)/, /^(?:(?!\n||)*[^\n]*)/, /^(?:accDescr\s*\{\s*)/, /^(?:[\}])/, /^(?:[^\}]*)/, /^(?:@\{)/, /^(?:["])/, /^(?:["])/, /^(?:[^\"]+)/, /^(?:[^}^"]+)/, /^(?:\})/, /^(?:call[\s]+)/, /^(?:\([\s]*\))/, /^(?:\()/, /^(?:[^(]*)/, /^(?:\))/, /^(?:[^)]*)/, /^(?:[^`"]+)/, /^(?:[`]["])/, /^(?:["][`])/, /^(?:[^"]+)/, /^(?:["])/, /^(?:["])/, /^(?:style\b)/, /^(?:default\b)/, /^(?:linkStyle\b)/, /^(?:interpolate\b)/, /^(?:classDef\b)/, /^(?:class\b)/, /^(?:href[\s])/, /^(?:click[\s]+)/, /^(?:[\s\n])/, /^(?:[^\s\n]*)/, /^(?:flowchart-elk\b)/, /^(?:swimlane-beta\b)/, /^(?:graph\b)/, /^(?:flowchart\b)/, /^(?:subgraph\b)/, /^(?:end\b\s*)/, /^(?:_self\b)/, /^(?:_blank\b)/, /^(?:_parent\b)/, /^(?:_top\b)/, /^(?:(\r?\n)*\s*\n)/, /^(?:\s*LR\b)/, /^(?:\s*RL\b)/, /^(?:\s*TB\b)/, /^(?:\s*BT\b)/, /^(?:\s*TD\b)/, /^(?:\s*BR\b)/, /^(?:\s*<)/, /^(?:\s*>)/, /^(?:\s*\^)/, /^(?:\s*v\b)/, /^(?:.*direction\s+TB[^\n]*)/, /^(?:.*direction\s+BT[^\n]*)/, /^(?:.*direction\s+RL[^\n]*)/, /^(?:.*direction\s+LR[^\n]*)/, /^(?:.*direction\s+TD[^\n]*)/, /^(?:[^\s\"]+@(?=[^\{\"]))/, /^(?:[0-9]+)/, /^(?:#)/, /^(?::::)/, /^(?::)/, /^(?:&)/, /^(?:;)/, /^(?:,)/, /^(?:\*)/, /^(?:\s*[xo<]?--+[-xo>]\s*)/, /^(?:\s*[xo<]?--\s*)/, /^(?:[^-]|-(?!-)+)/, /^(?:\s*[xo<]?==+[=xo>]\s*)/, /^(?:\s*[xo<]?==\s*)/, /^(?:[^=]|=(?!))/, /^(?:\s*[xo<]?-?\.+-[xo>]?\s*)/, /^(?:\s*[xo<]?-\.\s*)/, /^(?:[^\.]|\.(?!))/, /^(?:\s*~~[\~]+\s*)/, /^(?:[-/\)][\)])/, /^(?:[^\(\)\[\]\{\}]|!\)+)/, /^(?:\(-)/, /^(?:\]\))/, /^(?:\(\[)/, /^(?:\]\])/, /^(?:\[\[)/, /^(?:\[\|)/, /^(?:>)/, /^(?:\)\])/, /^(?:\[\()/, /^(?:\)\)\))/, /^(?:\(\(\()/, /^(?:[\\(?=\])][\]])/, /^(?:\/(?=\])\])/, /^(?:\/(?!\])|\\(?!\])|[^\\\[\]\(\)\{\}\/]+)/, /^(?:\[\/)/, /^(?:\[\\)/, /^(?:<)/, /^(?:>)/, /^(?:\^)/, /^(?:\\\|)/, /^(?:v\b)/, /^(?:\*)/, /^(?:#)/, /^(?:&)/, /^(?:([A-Za-z0-9!"\#$%&'*+\.`?\\_\/]|-(?=[^\>\-\.])|(?!))+)/, /^(?:-)/, /^(?:[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]|[\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377]|[\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5]|[\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA]|[\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE]|[\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA]|[\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0]|[\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977]|[\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2]|[\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A]|[\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39]|[\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8]|[\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C]|[\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C]|[\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99]|[\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0]|[\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D]|[\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3]|[\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10]|[\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1]|[\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81]|[\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3]|[\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6]|[\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A]|[\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081]|[\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D]|[\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0]|[\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310]|[\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C]|[\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711]|[\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7]|[\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C]|[\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16]|[\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF]|[\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC]|[\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D]|[\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D]|[\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3]|[\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F]|[\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128]|[\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184]|[\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3]|[\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6]|[\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE]|[\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C]|[\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D]|[\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC]|[\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B]|[\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788]|[\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805]|[\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB]|[\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28]|[\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5]|[\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4]|[\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E]|[\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D]|[\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36]|[\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D]|[\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC]|[\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF]|[\uFFD2-\uFFD7\uFFDA-\uFFDC])/, /^(?:\|)/, /^(?:\|)/, /^(?:\))/, /^(?:\()/, /^(?:\])/, /^(?:\[)/, /^(?:(\}))/, /^(?:\{)/, /^(?:[^\[\]\(\)\{\}\|\"]+)/, /^(?:")/, /^(?:(\r?\n)+)/, /^(?:[^\S\n\r]+)/, /^(?:$)/],
|
|
1241
|
+
conditions: { "shapeDataEndBracket": { "rules": [21, 24, 79, 82, 84, 86, 90, 92, 96, 97, 110, 112, 114, 116], "inclusive": false }, "shapeDataStr": { "rules": [9, 10, 21, 24, 79, 82, 84, 86, 90, 92, 96, 97, 110, 112, 114, 116], "inclusive": false }, "shapeData": { "rules": [8, 11, 12, 21, 24, 79, 82, 84, 86, 90, 92, 96, 97, 110, 112, 114, 116], "inclusive": false }, "callbackargs": { "rules": [17, 18, 21, 24, 79, 82, 84, 86, 90, 92, 96, 97, 110, 112, 114, 116], "inclusive": false }, "callbackname": { "rules": [14, 15, 16, 21, 24, 79, 82, 84, 86, 90, 92, 96, 97, 110, 112, 114, 116], "inclusive": false }, "href": { "rules": [21, 24, 79, 82, 84, 86, 90, 92, 96, 97, 110, 112, 114, 116], "inclusive": false }, "click": { "rules": [21, 24, 33, 34, 79, 82, 84, 86, 90, 92, 96, 97, 110, 112, 114, 116], "inclusive": false }, "dottedEdgeText": { "rules": [21, 24, 76, 78, 79, 82, 84, 86, 90, 92, 96, 97, 110, 112, 114, 116], "inclusive": false }, "thickEdgeText": { "rules": [21, 24, 73, 75, 79, 82, 84, 86, 90, 92, 96, 97, 110, 112, 114, 116], "inclusive": false }, "edgeText": { "rules": [21, 24, 70, 72, 79, 82, 84, 86, 90, 92, 96, 97, 110, 112, 114, 116], "inclusive": false }, "trapText": { "rules": [21, 24, 79, 82, 84, 86, 90, 92, 93, 94, 95, 96, 97, 110, 112, 114, 116], "inclusive": false }, "ellipseText": { "rules": [21, 24, 79, 80, 81, 82, 84, 86, 90, 92, 96, 97, 110, 112, 114, 116], "inclusive": false }, "text": { "rules": [21, 24, 79, 82, 83, 84, 85, 86, 89, 90, 91, 92, 96, 97, 109, 110, 111, 112, 113, 114, 115, 116, 117], "inclusive": false }, "vertex": { "rules": [21, 24, 79, 82, 84, 86, 90, 92, 96, 97, 110, 112, 114, 116], "inclusive": false }, "dir": { "rules": [21, 24, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 79, 82, 84, 86, 90, 92, 96, 97, 110, 112, 114, 116], "inclusive": false }, "acc_descr_multiline": { "rules": [5, 6, 21, 24, 79, 82, 84, 86, 90, 92, 96, 97, 110, 112, 114, 116], "inclusive": false }, "acc_descr": { "rules": [3, 21, 24, 79, 82, 84, 86, 90, 92, 96, 97, 110, 112, 114, 116], "inclusive": false }, "acc_title": { "rules": [1, 21, 24, 79, 82, 84, 86, 90, 92, 96, 97, 110, 112, 114, 116], "inclusive": false }, "md_string": { "rules": [19, 20, 21, 24, 79, 82, 84, 86, 90, 92, 96, 97, 110, 112, 114, 116], "inclusive": false }, "string": { "rules": [21, 22, 23, 24, 79, 82, 84, 86, 90, 92, 96, 97, 110, 112, 114, 116], "inclusive": false }, "INITIAL": { "rules": [0, 2, 4, 7, 13, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 73, 74, 76, 77, 79, 82, 84, 86, 87, 88, 90, 92, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 110, 112, 114, 116, 118, 119, 120, 121], "inclusive": true } }
|
|
1242
|
+
};
|
|
1243
|
+
return lexer2;
|
|
1244
|
+
})();
|
|
1245
|
+
parser2.lexer = lexer;
|
|
1246
|
+
function Parser() {
|
|
1247
|
+
this.yy = {};
|
|
1248
|
+
}
|
|
1249
|
+
Parser.prototype = parser2;
|
|
1250
|
+
parser2.Parser = Parser;
|
|
1251
|
+
return new Parser();
|
|
1252
|
+
})();
|
|
1253
|
+
var generatedParser = parser;
|
|
1254
|
+
var generated_default = generatedParser;
|
|
1255
|
+
|
|
1256
|
+
// src/errors.js
|
|
1257
|
+
var FlowInkError = class extends Error {
|
|
1258
|
+
/** @param {string} message @param {{code?:string,line?:number,column?:number,cause?:unknown}} [options] */
|
|
1259
|
+
constructor(message, options = {}) {
|
|
1260
|
+
super(message, { cause: options.cause });
|
|
1261
|
+
this.name = "FlowInkError";
|
|
1262
|
+
this.code = options.code ?? "FLOWINK_ERROR";
|
|
1263
|
+
this.line = options.line;
|
|
1264
|
+
this.column = options.column;
|
|
1265
|
+
}
|
|
1266
|
+
};
|
|
1267
|
+
|
|
1268
|
+
// src/parser/semantic.js
|
|
1269
|
+
import yaml from "js-yaml";
|
|
1270
|
+
var VALID_SHAPES = new Set(`join rounded state anchor db summary database start document event stop console process text circle rect display prepare squareRect choice note composite rectWithTitle labelRect block_arrow collapsedGroup iconSquare iconCircle icon iconRounded imageSquare kanbanItem proc rectangle roundedRect stadium terminal pill fr-rect subprocess subproc framed-rectangle subroutine cyl cylinder datastore data-store folder directory bucket browser person circ bang cloud diam decision diamond question hex hexagon lean-r lean-right in-out lean_right lean-l lean-left out-in lean_left trap-b priority trapezoid-bottom trapezoid trap-t manual trapezoid-top inv-trapezoid inv_trapezoid dbl-circ double-circle doublecircle notch-rect card notched-rectangle lin-rect lined-rectangle lined-process lin-proc shaded-process sm-circ small-circle stateStart fr-circ framed-circle stateEnd fork forkJoin hourglass collate brace comment brace-l brace-r braces bolt com-link lightning-bolt doc delay half-rounded-rectangle h-cyl das horizontal-cylinder lin-cyl disk lined-cylinder curv-trap curved-trapezoid div-rect div-proc divided-rectangle divided-process tri extract triangle win-pane internal-storage window-pane f-circ junction filled-circle notch-pent loop-limit notched-pentagon flip-tri manual-file flipped-triangle sl-rect manual-input sloped-rectangle docs documents st-doc stacked-document st-rect procs processes stacked-rectangle bow-rect stored-data bow-tie-rectangle cross-circ crossed-circle tag-doc tagged-document tag-rect tagged-rectangle tag-proc tagged-process flag paper-tape odd rect_left_inv_arrow lin-doc lined-document`.split(/\s+/));
|
|
1271
|
+
function textValue(value) {
|
|
1272
|
+
if (value === void 0 || value === null) return "";
|
|
1273
|
+
return typeof value === "object" && "text" in value ? String(value.text) : String(value);
|
|
1274
|
+
}
|
|
1275
|
+
function labelType(value) {
|
|
1276
|
+
return value?.type === "markdown" || value?.type === "string" ? value.type : "text";
|
|
1277
|
+
}
|
|
1278
|
+
function parseShapeData(raw) {
|
|
1279
|
+
const metadata = {};
|
|
1280
|
+
if (!raw) return metadata;
|
|
1281
|
+
const body = String(raw).trim();
|
|
1282
|
+
const lines = body.split("\n");
|
|
1283
|
+
const indents = lines.slice(1).filter((line) => line.trim()).map((line) => line.match(/^\s*/)[0].length);
|
|
1284
|
+
const indent = indents.length ? Math.min(...indents) : 0;
|
|
1285
|
+
const normalized = lines.map((line, index) => index === 0 ? line : line.slice(Math.min(indent, line.length))).join("\n");
|
|
1286
|
+
try {
|
|
1287
|
+
const parsed = yaml.load(normalized.includes("\n") ? normalized : `{${normalized}}`, { schema: yaml.JSON_SCHEMA });
|
|
1288
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) Object.assign(metadata, parsed);
|
|
1289
|
+
} catch (error) {
|
|
1290
|
+
throw new FlowInkError(error?.message ?? "Invalid shape data.", { code: "SHAPE_DATA_ERROR", cause: error });
|
|
1291
|
+
}
|
|
1292
|
+
metadata.raw = body;
|
|
1293
|
+
return metadata;
|
|
1294
|
+
}
|
|
1295
|
+
var FlowSemanticDB = class {
|
|
1296
|
+
constructor(source) {
|
|
1297
|
+
this.source = source;
|
|
1298
|
+
this.direction = "TB";
|
|
1299
|
+
this.vertices = /* @__PURE__ */ new Map();
|
|
1300
|
+
this.edges = [];
|
|
1301
|
+
this.classes = /* @__PURE__ */ new Map();
|
|
1302
|
+
this.classTextStyles = /* @__PURE__ */ new Map();
|
|
1303
|
+
this.subGraphs = [];
|
|
1304
|
+
this.subGraphLookup = /* @__PURE__ */ new Map();
|
|
1305
|
+
this.tooltips = /* @__PURE__ */ new Map();
|
|
1306
|
+
this.interactions = /* @__PURE__ */ new Map();
|
|
1307
|
+
this.defaultStyles = [];
|
|
1308
|
+
this.defaultInterpolate = void 0;
|
|
1309
|
+
this.vertexCounter = 0;
|
|
1310
|
+
this.firstGraphFlag = true;
|
|
1311
|
+
this.lex = { firstGraph: () => this.firstGraph() };
|
|
1312
|
+
this.title = void 0;
|
|
1313
|
+
this.description = void 0;
|
|
1314
|
+
for (const name of [
|
|
1315
|
+
"firstGraph",
|
|
1316
|
+
"setDirection",
|
|
1317
|
+
"addVertex",
|
|
1318
|
+
"addSingleLink",
|
|
1319
|
+
"addLink",
|
|
1320
|
+
"destructLink",
|
|
1321
|
+
"addSubGraph",
|
|
1322
|
+
"addClass",
|
|
1323
|
+
"setClass",
|
|
1324
|
+
"updateLink",
|
|
1325
|
+
"updateLinkInterpolate",
|
|
1326
|
+
"setTooltip",
|
|
1327
|
+
"setLink",
|
|
1328
|
+
"setClickEvent",
|
|
1329
|
+
"setAccTitle",
|
|
1330
|
+
"setAccDescription"
|
|
1331
|
+
]) this[name] = this[name].bind(this);
|
|
1332
|
+
}
|
|
1333
|
+
firstGraph() {
|
|
1334
|
+
if (this.firstGraphFlag) {
|
|
1335
|
+
this.firstGraphFlag = false;
|
|
1336
|
+
return true;
|
|
1337
|
+
}
|
|
1338
|
+
return false;
|
|
1339
|
+
}
|
|
1340
|
+
clear() {
|
|
1341
|
+
}
|
|
1342
|
+
setDirection(direction) {
|
|
1343
|
+
const value = String(direction).trim();
|
|
1344
|
+
this.direction = value === "TD" || value.includes("v") ? "TB" : value.includes(">") ? "LR" : value.includes("<") ? "RL" : value.includes("^") ? "BT" : value;
|
|
1345
|
+
}
|
|
1346
|
+
addVertex(id, textObj, type, styles, classes, dir, props, rawShapeData) {
|
|
1347
|
+
if (!id || !String(id).trim()) return;
|
|
1348
|
+
id = String(id);
|
|
1349
|
+
const shapeData = rawShapeData !== void 0 ? parseShapeData(rawShapeData) : void 0;
|
|
1350
|
+
const subGraph = this.subGraphLookup.get(id);
|
|
1351
|
+
if (subGraph && shapeData) {
|
|
1352
|
+
Object.assign(subGraph.metadata, shapeData);
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
1355
|
+
const edge = this.edges.find((item) => item.id === id.replace(/^@|@$/g, ""));
|
|
1356
|
+
if (edge && rawShapeData !== void 0) {
|
|
1357
|
+
const placeholder = this.vertices.get(id);
|
|
1358
|
+
if (placeholder && placeholder.label === id && placeholder.shape === "rect" && !placeholder.styles.length && !placeholder.classes.length) this.vertices.delete(id);
|
|
1359
|
+
Object.assign(edge.metadata, shapeData);
|
|
1360
|
+
const shape = edge.metadata;
|
|
1361
|
+
if (shape.animate !== void 0) edge.animate = Boolean(shape.animate);
|
|
1362
|
+
if (shape.animation !== void 0) edge.animation = String(shape.animation);
|
|
1363
|
+
if (shape.curve !== void 0) {
|
|
1364
|
+
edge.curve = String(shape.curve);
|
|
1365
|
+
edge.interpolate = String(shape.curve);
|
|
1366
|
+
edge.metadata.interpolate = String(shape.curve);
|
|
1367
|
+
}
|
|
1368
|
+
return;
|
|
1369
|
+
}
|
|
1370
|
+
let vertex = this.vertices.get(id);
|
|
1371
|
+
if (!vertex) {
|
|
1372
|
+
vertex = { id, label: id, labelType: "text", shape: "rect", styles: [], classes: [], metadata: {} };
|
|
1373
|
+
this.vertices.set(id, vertex);
|
|
1374
|
+
}
|
|
1375
|
+
this.vertexCounter += 1;
|
|
1376
|
+
if (textObj !== void 0) {
|
|
1377
|
+
vertex.label = textValue(textObj).trim().replace(/^"|"$/g, "");
|
|
1378
|
+
vertex.labelType = labelType(textObj);
|
|
1379
|
+
}
|
|
1380
|
+
if (type) vertex.shape = type;
|
|
1381
|
+
if (Array.isArray(styles)) vertex.styles.push(...styles);
|
|
1382
|
+
if (Array.isArray(classes)) vertex.classes.push(...classes);
|
|
1383
|
+
if (dir) vertex.direction = dir;
|
|
1384
|
+
if (props && typeof props === "object") Object.assign(vertex.metadata, props);
|
|
1385
|
+
if (rawShapeData !== void 0) Object.assign(vertex.metadata, shapeData);
|
|
1386
|
+
if (rawShapeData !== void 0) {
|
|
1387
|
+
const shapeData2 = vertex.metadata;
|
|
1388
|
+
if (shapeData2.shape !== void 0) {
|
|
1389
|
+
const shape = String(shapeData2.shape);
|
|
1390
|
+
if (shape !== shape.toLowerCase() || shape.includes("_") || !VALID_SHAPES.has(shape)) {
|
|
1391
|
+
throw new FlowInkError(`No such shape: ${shape}.`, { code: "INVALID_SHAPE" });
|
|
1392
|
+
}
|
|
1393
|
+
vertex.shape = shape;
|
|
1394
|
+
}
|
|
1395
|
+
if (shapeData2.label !== void 0) {
|
|
1396
|
+
vertex.label = String(shapeData2.label);
|
|
1397
|
+
vertex.labelType = shapeData2.labelType === void 0 ? "markdown" : labelType({ type: shapeData2.labelType });
|
|
1398
|
+
} else if (shapeData2.labelType !== void 0) vertex.labelType = labelType({ type: shapeData2.labelType });
|
|
1399
|
+
else if ((shapeData2.icon || shapeData2.img) && vertex.label === id) vertex.label = "";
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
addSingleLink(start, end, type = {}, id) {
|
|
1403
|
+
const cleanId = id ? String(id).replace(/^@|@$/g, "") : void 0;
|
|
1404
|
+
const existingUserId = cleanId && this.edges.find((item) => item.id === cleanId);
|
|
1405
|
+
if (existingUserId && !existingUserId.isUserDefinedId) {
|
|
1406
|
+
let replacement = `L${this.edges.length}`;
|
|
1407
|
+
while (this.edges.some((item) => item.id === replacement) || replacement === cleanId) replacement = `L${Number(replacement.slice(1)) + 1}`;
|
|
1408
|
+
existingUserId.id = replacement;
|
|
1409
|
+
}
|
|
1410
|
+
let generatedId = `L${this.edges.length}`;
|
|
1411
|
+
while (this.edges.some((item) => item.id === generatedId) || generatedId === cleanId) {
|
|
1412
|
+
generatedId = `L${Number(generatedId.slice(1)) + 1}`;
|
|
1413
|
+
}
|
|
1414
|
+
const useUserId = Boolean(cleanId && !this.edges.some((item) => item.id === cleanId));
|
|
1415
|
+
const edge = {
|
|
1416
|
+
id: useUserId ? cleanId : generatedId,
|
|
1417
|
+
source: String(start),
|
|
1418
|
+
target: String(end),
|
|
1419
|
+
label: textValue(type.text),
|
|
1420
|
+
labelType: labelType(type.text),
|
|
1421
|
+
arrowStart: "none",
|
|
1422
|
+
arrowEnd: "none",
|
|
1423
|
+
stroke: type.stroke ?? "normal",
|
|
1424
|
+
length: Math.min(type.length ?? 1, 10),
|
|
1425
|
+
styles: [],
|
|
1426
|
+
classes: [],
|
|
1427
|
+
metadata: this.defaultInterpolate === void 0 ? {} : { interpolate: this.defaultInterpolate }
|
|
1428
|
+
};
|
|
1429
|
+
if (this.defaultInterpolate !== void 0) edge.interpolate = this.defaultInterpolate;
|
|
1430
|
+
if (useUserId) edge.isUserDefinedId = true;
|
|
1431
|
+
if (useUserId) edge.metadata.isUserDefinedId = true;
|
|
1432
|
+
const map = {
|
|
1433
|
+
arrow_open: ["none", "none"],
|
|
1434
|
+
arrow_point: ["none", "point"],
|
|
1435
|
+
arrow_circle: ["none", "circle"],
|
|
1436
|
+
arrow_cross: ["none", "cross"],
|
|
1437
|
+
double_arrow_point: ["point", "point"],
|
|
1438
|
+
double_arrow_circle: ["circle", "circle"],
|
|
1439
|
+
double_arrow_cross: ["cross", "cross"]
|
|
1440
|
+
};
|
|
1441
|
+
[edge.arrowStart, edge.arrowEnd] = map[type.type] ?? ["none", "none"];
|
|
1442
|
+
this.edges.push(edge);
|
|
1443
|
+
}
|
|
1444
|
+
addLink(starts, ends, linkData = {}) {
|
|
1445
|
+
const id = linkData?.id ? String(linkData.id).replace(/^@|@$/g, "") : void 0;
|
|
1446
|
+
for (const start of starts) for (const end of ends) this.addSingleLink(start, end, linkData, start === starts.at(-1) && end === ends[0] ? id : void 0);
|
|
1447
|
+
}
|
|
1448
|
+
destructLink(value, startValue) {
|
|
1449
|
+
const end = String(value).trim();
|
|
1450
|
+
let type = end.endsWith(">") ? "arrow_point" : end.endsWith("o") ? "arrow_circle" : end.endsWith("x") ? "arrow_cross" : "arrow_open";
|
|
1451
|
+
let line = end.slice(0, -1);
|
|
1452
|
+
let stroke = "normal";
|
|
1453
|
+
const startMarker = line[0];
|
|
1454
|
+
const endMarker = end.at(-1);
|
|
1455
|
+
if (!startValue && (startMarker === "<" && endMarker === ">" || startMarker === "o" && endMarker === "o" || startMarker === "x" && endMarker === "x")) {
|
|
1456
|
+
type = `double_${type}`;
|
|
1457
|
+
line = line.slice(1);
|
|
1458
|
+
}
|
|
1459
|
+
stroke = line.startsWith("=") ? "thick" : line.startsWith("~") ? "invisible" : line.includes(".") ? "dotted" : "normal";
|
|
1460
|
+
let length = line.length - 1;
|
|
1461
|
+
if (stroke === "dotted") length = (line.match(/\./g) || []).length;
|
|
1462
|
+
if (startValue) {
|
|
1463
|
+
const start = String(startValue).trim();
|
|
1464
|
+
const startType = start[0] === "<" ? "arrow_point" : start[0] === "o" ? "arrow_circle" : start[0] === "x" ? "arrow_cross" : "arrow_open";
|
|
1465
|
+
if (startType !== "arrow_open" && startType !== type) return { type: "INVALID", stroke: "INVALID" };
|
|
1466
|
+
if (startType !== "arrow_open") type = `double_${type.replace("arrow_", "arrow_")}`;
|
|
1467
|
+
if (type === "double_arrow_arrow_point") type = "double_arrow_point";
|
|
1468
|
+
}
|
|
1469
|
+
return { type, stroke, length };
|
|
1470
|
+
}
|
|
1471
|
+
addSubGraph(idObj, list, titleObj) {
|
|
1472
|
+
const title = textValue(titleObj ?? idObj).trim();
|
|
1473
|
+
const sameText = idObj && titleObj && idObj === titleObj;
|
|
1474
|
+
const id = idObj?.text && (!sameText || !/\s/.test(idObj.text)) ? idObj.text.trim() : `subGraph${this.subGraphs.length}`;
|
|
1475
|
+
const flat = (list ?? []).flat(Infinity);
|
|
1476
|
+
const directions = flat.filter((item) => item?.stmt === "dir");
|
|
1477
|
+
const direction = directions.at(-1)?.value;
|
|
1478
|
+
const nodeIds = [...new Set(flat.flatMap((item) => {
|
|
1479
|
+
if (typeof item === "string" && item.trim()) return [item];
|
|
1480
|
+
if (item && typeof item === "object" && typeof item.id === "string") return [item.id];
|
|
1481
|
+
return [];
|
|
1482
|
+
}))];
|
|
1483
|
+
const occupied = new Set(this.subGraphs.flatMap((group) => group.nodeIds));
|
|
1484
|
+
const uniqueNodeIds = nodeIds.filter((nodeId) => !occupied.has(nodeId));
|
|
1485
|
+
const subgraph = { id, label: title, nodeIds: uniqueNodeIds, ...direction ? { direction: direction === "TD" ? "TB" : direction } : {}, styles: [], classes: [], metadata: { labelType: labelType(titleObj ?? idObj) } };
|
|
1486
|
+
this.subGraphs.push(subgraph);
|
|
1487
|
+
this.subGraphLookup.set(id, subgraph);
|
|
1488
|
+
for (const nodeId of nodeIds) {
|
|
1489
|
+
const node = this.vertices.get(nodeId);
|
|
1490
|
+
if (node && !node.parentId) node.parentId = id;
|
|
1491
|
+
const child = this.subGraphLookup.get(nodeId);
|
|
1492
|
+
if (child && !child.parentId) child.parentId = id;
|
|
1493
|
+
}
|
|
1494
|
+
return subgraph;
|
|
1495
|
+
}
|
|
1496
|
+
addClass(ids, styles) {
|
|
1497
|
+
const values = String(styles?.join?.() ?? styles ?? "").replace(/\\,/g, "\xA7\xA7\xA7").replace(/,/g, ";").replace(/§§§/g, ",").split(";").map((style) => style.trim()).filter(Boolean);
|
|
1498
|
+
for (const id of String(ids).split(",")) {
|
|
1499
|
+
this.classes.set(id, [...this.classes.get(id) ?? [], ...values]);
|
|
1500
|
+
const textStyles = values.filter((style) => /color/.test(style)).map((style) => style.replace("fill", "bgFill"));
|
|
1501
|
+
if (textStyles.length) this.classTextStyles.set(id, [...this.classTextStyles.get(id) ?? [], ...textStyles]);
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
setClass(ids, className) {
|
|
1505
|
+
for (const id of String(ids).split(",")) {
|
|
1506
|
+
const node = this.vertices.get(id);
|
|
1507
|
+
if (node) node.classes.push(String(className));
|
|
1508
|
+
const edge = this.edges.find((item) => item.id === id);
|
|
1509
|
+
if (edge) edge.classes.push(String(className));
|
|
1510
|
+
const group = this.subGraphLookup.get(id);
|
|
1511
|
+
if (group) group.classes.push(String(className));
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
updateLink(positions, styles) {
|
|
1515
|
+
for (const position of positions) {
|
|
1516
|
+
if (position === "default") this.defaultStyles = styles.slice();
|
|
1517
|
+
else if (this.edges[position]) {
|
|
1518
|
+
this.edges[position].styles = styles.slice();
|
|
1519
|
+
if (styles.length && !styles.some((style) => String(style).startsWith("fill"))) this.edges[position].styles.push("fill:none");
|
|
1520
|
+
} else throw new FlowInkError(`The link index ${position} is out of bounds.`, { code: "INVALID_LINK_INDEX" });
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
updateLinkInterpolate(positions, value) {
|
|
1524
|
+
const interpolate = String(value);
|
|
1525
|
+
for (const position of positions) {
|
|
1526
|
+
if (position === "default") {
|
|
1527
|
+
this.defaultInterpolate = interpolate;
|
|
1528
|
+
} else if (this.edges[position]) {
|
|
1529
|
+
this.edges[position].metadata.interpolate = interpolate;
|
|
1530
|
+
this.edges[position].interpolate = interpolate;
|
|
1531
|
+
} else throw new FlowInkError(`The link index ${position} is out of bounds.`, { code: "INVALID_LINK_INDEX" });
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
setTooltip(ids, tooltip) {
|
|
1535
|
+
for (const id of String(ids).split(",")) this.tooltips.set(id, String(tooltip));
|
|
1536
|
+
}
|
|
1537
|
+
setLink(ids, link, target) {
|
|
1538
|
+
for (const id of String(ids).split(",")) {
|
|
1539
|
+
if (!this.vertices.has(id) && !this.edges.some((edge) => edge.id === id) && !this.subGraphLookup.has(id)) continue;
|
|
1540
|
+
this.interactions.set(id, { href: String(link), target });
|
|
1541
|
+
this.setClass(id, "clickable");
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
setClickEvent(ids, callback, args) {
|
|
1545
|
+
for (const id of String(ids).split(",")) {
|
|
1546
|
+
if (!this.vertices.has(id) && !this.edges.some((edge) => edge.id === id) && !this.subGraphLookup.has(id)) continue;
|
|
1547
|
+
this.interactions.set(id, { callback: String(callback), args: args ? String(args) : void 0 });
|
|
1548
|
+
this.setClass(id, "clickable");
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
setAccTitle(value) {
|
|
1552
|
+
this.title = String(value);
|
|
1553
|
+
}
|
|
1554
|
+
setAccDescription(value) {
|
|
1555
|
+
this.description = String(value);
|
|
1556
|
+
}
|
|
1557
|
+
finalize() {
|
|
1558
|
+
for (const group of this.subGraphs) {
|
|
1559
|
+
const synthetic = this.vertices.get(group.id);
|
|
1560
|
+
if (synthetic) {
|
|
1561
|
+
group.styles.push(...synthetic.styles);
|
|
1562
|
+
group.classes.push(...synthetic.classes);
|
|
1563
|
+
Object.assign(group.metadata, synthetic.metadata);
|
|
1564
|
+
}
|
|
1565
|
+
if (this.tooltips.has(group.id)) group.metadata.tooltip = this.tooltips.get(group.id);
|
|
1566
|
+
if (this.interactions.has(group.id)) group.metadata.interaction = this.interactions.get(group.id);
|
|
1567
|
+
}
|
|
1568
|
+
for (const node of this.vertices.values()) {
|
|
1569
|
+
for (const className of node.classes) node.styles.push(...this.classes.get(className) ?? []);
|
|
1570
|
+
if (this.tooltips.has(node.id)) node.metadata.tooltip = this.tooltips.get(node.id);
|
|
1571
|
+
if (this.interactions.has(node.id)) node.metadata.interaction = this.interactions.get(node.id);
|
|
1572
|
+
}
|
|
1573
|
+
for (const edge of this.edges) {
|
|
1574
|
+
if (edge.interpolate === void 0 && this.defaultInterpolate !== void 0) {
|
|
1575
|
+
edge.interpolate = this.defaultInterpolate;
|
|
1576
|
+
edge.metadata.interpolate = this.defaultInterpolate;
|
|
1577
|
+
}
|
|
1578
|
+
edge.styles = [...this.defaultStyles, ...edge.styles];
|
|
1579
|
+
for (const className of edge.classes) edge.styles.push(...this.classes.get(className) ?? []);
|
|
1580
|
+
if (this.interactions.has(edge.id)) edge.metadata.interaction = this.interactions.get(edge.id);
|
|
1581
|
+
}
|
|
1582
|
+
const metadata = {};
|
|
1583
|
+
if (this.title !== void 0) metadata.title = this.title;
|
|
1584
|
+
if (this.description !== void 0) metadata.description = this.description;
|
|
1585
|
+
if (this.title !== void 0) metadata.accessibilityTitle = this.title;
|
|
1586
|
+
if (this.description !== void 0) metadata.accessibilityDescription = this.description;
|
|
1587
|
+
if (this.defaultStyles.length) metadata.defaultStyle = [...this.defaultStyles];
|
|
1588
|
+
if (this.defaultInterpolate !== void 0) metadata.defaultInterpolate = this.defaultInterpolate;
|
|
1589
|
+
if (this.classTextStyles.size) metadata.classTextStyles = Object.fromEntries(this.classTextStyles);
|
|
1590
|
+
return { source: this.source, direction: this.direction, nodes: [...this.vertices.values()], edges: this.edges, subgraphs: this.subGraphs, classes: Object.fromEntries(this.classes), metadata };
|
|
1591
|
+
}
|
|
1592
|
+
};
|
|
1593
|
+
function parserError(error, source) {
|
|
1594
|
+
const line = error?.hash?.loc?.first_line ?? error?.lineNumber;
|
|
1595
|
+
const firstColumn = error?.hash?.loc?.first_column;
|
|
1596
|
+
const column = firstColumn === void 0 ? void 0 : firstColumn + 1;
|
|
1597
|
+
return new FlowInkError(error?.message ?? "Invalid Mermaid flowchart", { code: "PARSE_ERROR", line, column, cause: error });
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
// src/parser/preprocess.js
|
|
1601
|
+
import yaml2 from "js-yaml";
|
|
1602
|
+
var FRONT_MATTER = /^([^\S\n\r]*)-{3}\s*[\n\r](.*?)[\n\r]\1-{3}\s*[\n\r]+/s;
|
|
1603
|
+
function cleanupText(value) {
|
|
1604
|
+
return value.replace(/\r\n?/g, "\n").replace(
|
|
1605
|
+
/<(\w+)([^>]*)>/g,
|
|
1606
|
+
(match, tag, attributes) => `<${tag}${attributes.replace(/="([^"]*)"/g, "='$1'")}>`
|
|
1607
|
+
);
|
|
1608
|
+
}
|
|
1609
|
+
function sourceLineAt(source, index) {
|
|
1610
|
+
return source.slice(0, index).split(/\r\n?|\n/).length;
|
|
1611
|
+
}
|
|
1612
|
+
function preprocess(source) {
|
|
1613
|
+
const original = String(source);
|
|
1614
|
+
let text = cleanupText(original.replace(/^\uFEFF/, ""));
|
|
1615
|
+
let frontmatter;
|
|
1616
|
+
let lineOffset = 0;
|
|
1617
|
+
const match = text.match(FRONT_MATTER);
|
|
1618
|
+
if (match) {
|
|
1619
|
+
const prefix = match[0];
|
|
1620
|
+
lineOffset = prefix.split(/\r?\n/).length - (prefix.endsWith("\n") ? 1 : 0);
|
|
1621
|
+
try {
|
|
1622
|
+
frontmatter = yaml2.load(match[2], { schema: yaml2.JSON_SCHEMA }) ?? {};
|
|
1623
|
+
if (!frontmatter || typeof frontmatter !== "object" || Array.isArray(frontmatter)) frontmatter = {};
|
|
1624
|
+
} catch (error) {
|
|
1625
|
+
const mark = error?.mark;
|
|
1626
|
+
throw new FlowInkError(error?.message ?? "Invalid Mermaid frontmatter", {
|
|
1627
|
+
code: "FRONTMATTER_ERROR",
|
|
1628
|
+
line: sourceLineAt(text, match.index + match[0].indexOf(match[2])) + (mark?.line ?? 0),
|
|
1629
|
+
column: mark ? mark.column + 1 : void 0,
|
|
1630
|
+
cause: error
|
|
1631
|
+
});
|
|
1632
|
+
}
|
|
1633
|
+
text = text.slice(prefix.length);
|
|
1634
|
+
}
|
|
1635
|
+
const directives = [];
|
|
1636
|
+
text = text.replace(/^\s*%%\{([\s\S]*?)\}%%\s*(?:\r?\n|$)/gm, (match2, value) => {
|
|
1637
|
+
directives.push(value.trim());
|
|
1638
|
+
return match2.replace(/[^\n]/g, "");
|
|
1639
|
+
});
|
|
1640
|
+
text = text.replace(/^[^\S\n]*%%(?!\{)[^\n]*/gm, "");
|
|
1641
|
+
const metadata = {};
|
|
1642
|
+
if (frontmatter) {
|
|
1643
|
+
metadata.frontmatter = frontmatter;
|
|
1644
|
+
if (frontmatter.title !== void 0) metadata.title = String(frontmatter.title);
|
|
1645
|
+
if (frontmatter.config !== void 0) metadata.config = frontmatter.config;
|
|
1646
|
+
if (frontmatter.displayMode !== void 0) metadata.displayMode = String(frontmatter.displayMode);
|
|
1647
|
+
}
|
|
1648
|
+
if (directives.length) metadata.directives = directives;
|
|
1649
|
+
return { text, metadata, lineOffset };
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
// src/parse.js
|
|
1653
|
+
function parse(source) {
|
|
1654
|
+
if (typeof source !== "string") throw new FlowInkError("Flowchart source must be a string", { code: "INVALID_INPUT" });
|
|
1655
|
+
const db = new FlowSemanticDB(source);
|
|
1656
|
+
const processed = preprocess(source);
|
|
1657
|
+
const localParser = new generated_default.Parser();
|
|
1658
|
+
try {
|
|
1659
|
+
localParser.yy = db;
|
|
1660
|
+
localParser.parse(`${processed.text.replace(/}[^\S\n]*(?=\n|$)/g, "}")}
|
|
1661
|
+
`);
|
|
1662
|
+
const graph = db.finalize();
|
|
1663
|
+
const canonicaliseLabel = (value) => String(value).replace(/(<[^>]+?)='([^']*)'/g, '$1="$2"');
|
|
1664
|
+
for (const node of graph.nodes) node.label = canonicaliseLabel(node.label);
|
|
1665
|
+
for (const edge of graph.edges) edge.label = canonicaliseLabel(edge.label);
|
|
1666
|
+
Object.assign(graph.metadata, processed.metadata);
|
|
1667
|
+
return graph;
|
|
1668
|
+
} catch (error) {
|
|
1669
|
+
if (error instanceof FlowInkError) throw error;
|
|
1670
|
+
const wrapped = parserError(error, source);
|
|
1671
|
+
if (wrapped.line !== void 0) wrapped.line += processed.lineOffset;
|
|
1672
|
+
throw wrapped;
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
// src/layout.js
|
|
1677
|
+
import ELK from "elkjs/lib/elk.bundled.js";
|
|
1678
|
+
|
|
1679
|
+
// src/text.js
|
|
1680
|
+
import stringWidth from "string-width";
|
|
1681
|
+
import { decodeHTML } from "entities";
|
|
1682
|
+
import { marked } from "marked";
|
|
1683
|
+
function displayWidth(value) {
|
|
1684
|
+
if (value === null || value === void 0) return 0;
|
|
1685
|
+
const text = String(value).replace(/\r\n?/g, "\n");
|
|
1686
|
+
return Math.max(0, ...text.split("\n").map((line) => stringWidth(line)));
|
|
1687
|
+
}
|
|
1688
|
+
var graphemeSegmenter = typeof Intl !== "undefined" && Intl.Segmenter ? new Intl.Segmenter(void 0, { granularity: "grapheme" }) : null;
|
|
1689
|
+
function expandTabs(value) {
|
|
1690
|
+
return value.split("\n").map((line) => {
|
|
1691
|
+
let column = 0;
|
|
1692
|
+
let result = "";
|
|
1693
|
+
const graphemes = graphemeSegmenter ? [...graphemeSegmenter.segment(line)].map(({ segment: segment2 }) => segment2) : [...line];
|
|
1694
|
+
for (const grapheme of graphemes) {
|
|
1695
|
+
if (grapheme === " ") {
|
|
1696
|
+
const spaces = 4 - column % 4;
|
|
1697
|
+
result += " ".repeat(spaces);
|
|
1698
|
+
column += spaces;
|
|
1699
|
+
} else {
|
|
1700
|
+
result += grapheme;
|
|
1701
|
+
column += stringWidth(grapheme);
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
return result;
|
|
1705
|
+
}).join("\n");
|
|
1706
|
+
}
|
|
1707
|
+
var BLOCK_TAGS = /^(?:address|article|aside|blockquote|br|caption|dd|div|dl|dt|fieldset|figcaption|figure|footer|form|h[1-6]|header|hr|li|main|nav|ol|p|pre|section|table|tbody|td|tfoot|th|thead|tr|ul)$/i;
|
|
1708
|
+
function decodeLabelEntities(value) {
|
|
1709
|
+
let result = decodeHTML(value);
|
|
1710
|
+
return result.replace(/(?<!&)#(x[0-9a-f]+|[0-9]+|[a-z][a-z0-9]+);/gi, (match, name) => {
|
|
1711
|
+
const entity = /^x/i.test(name) ? `&#${name};` : /^[0-9]/.test(name) ? `&#${name};` : `&${name};`;
|
|
1712
|
+
const decoded = decodeHTML(entity);
|
|
1713
|
+
return decoded === entity ? match : decoded;
|
|
1714
|
+
});
|
|
1715
|
+
}
|
|
1716
|
+
function htmlTokenText(value) {
|
|
1717
|
+
const source = String(value);
|
|
1718
|
+
let result = "";
|
|
1719
|
+
let index = 0;
|
|
1720
|
+
while (index < source.length) {
|
|
1721
|
+
if (source.startsWith("<!--", index)) {
|
|
1722
|
+
const end2 = source.indexOf("-->", index + 4);
|
|
1723
|
+
index = end2 < 0 ? source.length : end2 + 3;
|
|
1724
|
+
continue;
|
|
1725
|
+
}
|
|
1726
|
+
if (source[index] !== "<") {
|
|
1727
|
+
result += source[index];
|
|
1728
|
+
index += 1;
|
|
1729
|
+
continue;
|
|
1730
|
+
}
|
|
1731
|
+
let end = index + 1;
|
|
1732
|
+
let quote = "";
|
|
1733
|
+
for (; end < source.length; end += 1) {
|
|
1734
|
+
const character = source[end];
|
|
1735
|
+
if (quote) {
|
|
1736
|
+
if (character === quote) quote = "";
|
|
1737
|
+
} else if (character === '"' || character === "'") {
|
|
1738
|
+
quote = character;
|
|
1739
|
+
} else if (character === ">") {
|
|
1740
|
+
break;
|
|
1741
|
+
}
|
|
1742
|
+
}
|
|
1743
|
+
if (end >= source.length) {
|
|
1744
|
+
result += "<";
|
|
1745
|
+
index += 1;
|
|
1746
|
+
continue;
|
|
1747
|
+
}
|
|
1748
|
+
const rawTag = source.slice(index, end + 1);
|
|
1749
|
+
const match = rawTag.match(/^<(\/?[a-z][a-z0-9-]*)(?=\s|\/?>)[\s\S]*>$/i);
|
|
1750
|
+
if (!match) {
|
|
1751
|
+
result += "<";
|
|
1752
|
+
index += 1;
|
|
1753
|
+
continue;
|
|
1754
|
+
}
|
|
1755
|
+
const closing = match[1].startsWith("/");
|
|
1756
|
+
const tag = match[1].replace(/^\//, "").toLowerCase();
|
|
1757
|
+
if (tag === "img") {
|
|
1758
|
+
const alt = rawTag.match(/\balt\s*=\s*(['"])([\s\S]*?)\1/i);
|
|
1759
|
+
if (alt) result += alt[2];
|
|
1760
|
+
} else if (tag === "br") {
|
|
1761
|
+
result += "\n";
|
|
1762
|
+
} else if (BLOCK_TAGS.test(tag) && (closing || tag === "hr")) {
|
|
1763
|
+
result += "\n";
|
|
1764
|
+
}
|
|
1765
|
+
index = end + 1;
|
|
1766
|
+
}
|
|
1767
|
+
return result;
|
|
1768
|
+
}
|
|
1769
|
+
function tokenText(token) {
|
|
1770
|
+
if (!token) return "";
|
|
1771
|
+
const type = token.type;
|
|
1772
|
+
if (type === "html") return htmlTokenText(token.text ?? token.raw ?? "");
|
|
1773
|
+
if (type === "image") {
|
|
1774
|
+
return token.tokens ? tokensText(token.tokens) : token.text ?? "";
|
|
1775
|
+
}
|
|
1776
|
+
if (type === "br") return "\n";
|
|
1777
|
+
if (type === "codespan" || type === "code" || type === "text" || type === "escape") {
|
|
1778
|
+
if (type === "code" || type === "codespan") return token.text ?? "";
|
|
1779
|
+
if (token.tokens) return tokensText(token.tokens);
|
|
1780
|
+
return token.text ?? "";
|
|
1781
|
+
}
|
|
1782
|
+
if (type === "hr") return "\n";
|
|
1783
|
+
if (type === "space") return "\n";
|
|
1784
|
+
if (type === "table") {
|
|
1785
|
+
const header = (token.header ?? []).map(tokenText).join(" | ");
|
|
1786
|
+
const rows = (token.rows ?? []).map((row) => row.map(tokenText).join(" | "));
|
|
1787
|
+
return [header, ...rows].filter((line) => line !== "").join("\n") + "\n";
|
|
1788
|
+
}
|
|
1789
|
+
if (type === "list_item") {
|
|
1790
|
+
const body = token.tokens ? tokensText(token.tokens) : token.text ?? "";
|
|
1791
|
+
const marker = token.task ? `[${token.checked ? "x" : " "}] ` : "";
|
|
1792
|
+
return marker + body + "\n";
|
|
1793
|
+
}
|
|
1794
|
+
if (token.tokens) return tokensText(token.tokens) + (type === "paragraph" || type === "heading" ? "\n" : "");
|
|
1795
|
+
if (token.items) return token.items.map(tokenText).join("") + "\n";
|
|
1796
|
+
if (token.text !== void 0) return String(token.text);
|
|
1797
|
+
return "";
|
|
1798
|
+
}
|
|
1799
|
+
function tokensText(tokens) {
|
|
1800
|
+
return (tokens ?? []).map(tokenText).join("");
|
|
1801
|
+
}
|
|
1802
|
+
function labelLines(label, labelType2 = "text") {
|
|
1803
|
+
const source = label === null || label === void 0 ? "" : String(label);
|
|
1804
|
+
if (source === "") return [""];
|
|
1805
|
+
let plain;
|
|
1806
|
+
const markdown = /^(?:markdown|md)$/i.test(String(labelType2 ?? ""));
|
|
1807
|
+
if (!markdown) {
|
|
1808
|
+
plain = htmlTokenText(source);
|
|
1809
|
+
} else {
|
|
1810
|
+
try {
|
|
1811
|
+
plain = tokensText(marked.lexer(source));
|
|
1812
|
+
} catch {
|
|
1813
|
+
plain = htmlTokenText(source);
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
plain = expandTabs(decodeLabelEntities(plain).replace(/\r\n?/g, "\n"));
|
|
1817
|
+
plain = plain.replace(/^\n+|\n+$/g, "");
|
|
1818
|
+
return plain === "" ? [""] : plain.split("\n");
|
|
1819
|
+
}
|
|
1820
|
+
var SHAPE_ALIASES = /* @__PURE__ */ new Map([
|
|
1821
|
+
["rect", "rect"],
|
|
1822
|
+
["rectangle", "rect"],
|
|
1823
|
+
["square", "rect"],
|
|
1824
|
+
["proc", "rect"],
|
|
1825
|
+
["process", "rect"],
|
|
1826
|
+
["f_rect", "rect"],
|
|
1827
|
+
["fr_rect", "rect"],
|
|
1828
|
+
["subroutine", "rect"],
|
|
1829
|
+
["subproc", "rect"],
|
|
1830
|
+
["lined_square", "rect"],
|
|
1831
|
+
["notch_rect", "rect"],
|
|
1832
|
+
["div_rect", "rect"],
|
|
1833
|
+
["tag", "rect"],
|
|
1834
|
+
["fork", "rect"],
|
|
1835
|
+
["join", "rect"],
|
|
1836
|
+
["round", "round"],
|
|
1837
|
+
["rounded", "round"],
|
|
1838
|
+
["stadium", "round"],
|
|
1839
|
+
["pill", "round"],
|
|
1840
|
+
["event", "round"],
|
|
1841
|
+
["f_round", "round"],
|
|
1842
|
+
["fr_round", "round"],
|
|
1843
|
+
["circle", "circle"],
|
|
1844
|
+
["circ", "circle"],
|
|
1845
|
+
["doublecircle", "circle"],
|
|
1846
|
+
["dbl_circ", "circle"],
|
|
1847
|
+
["sm_circ", "circle"],
|
|
1848
|
+
["fr_circ", "circle"],
|
|
1849
|
+
["f_circ", "circle"],
|
|
1850
|
+
["state", "circle"],
|
|
1851
|
+
["diamond", "diamond"],
|
|
1852
|
+
["diam", "diamond"],
|
|
1853
|
+
["rhombus", "diamond"],
|
|
1854
|
+
["decision", "diamond"],
|
|
1855
|
+
["question", "diamond"],
|
|
1856
|
+
["image", "image"],
|
|
1857
|
+
["img", "image"],
|
|
1858
|
+
["icon", "icon"]
|
|
1859
|
+
]);
|
|
1860
|
+
function shapeKey(value) {
|
|
1861
|
+
return String(value ?? "").trim().toLowerCase().replace(/[\s-]+/g, "_");
|
|
1862
|
+
}
|
|
1863
|
+
function metadataField(metadata, name) {
|
|
1864
|
+
return metadata[name];
|
|
1865
|
+
}
|
|
1866
|
+
function shapeForNode(node) {
|
|
1867
|
+
const metadata = node && node.metadata && typeof node.metadata === "object" ? node.metadata : {};
|
|
1868
|
+
const primary = node?.shape;
|
|
1869
|
+
const metadataShape = metadataField(metadata, "shape");
|
|
1870
|
+
const iconValue = metadataField(metadata, "icon");
|
|
1871
|
+
const imgValue = metadataField(metadata, "img");
|
|
1872
|
+
const mediaKind = iconValue !== void 0 && iconValue !== null ? "icon" : imgValue !== void 0 && imgValue !== null ? "image" : void 0;
|
|
1873
|
+
const form = metadataField(metadata, "form");
|
|
1874
|
+
const formShape = mediaKind && SHAPE_ALIASES.has(shapeKey(form)) ? form : void 0;
|
|
1875
|
+
const typeShape = SHAPE_ALIASES.has(shapeKey(node?.type)) ? node?.type : void 0;
|
|
1876
|
+
const mediaUsesDefaultShape = mediaKind && metadataShape === void 0 && (primary === void 0 || shapeKey(primary) === "rect");
|
|
1877
|
+
const candidates = mediaUsesDefaultShape ? [formShape] : shapeKey(primary) === "rect" && metadataShape !== void 0 ? [metadataShape, primary, node?.shapeType, typeShape] : [primary, node?.shapeType, metadataShape, typeShape];
|
|
1878
|
+
for (const candidate of candidates) {
|
|
1879
|
+
if (candidate === void 0 || candidate === null) continue;
|
|
1880
|
+
const key3 = shapeKey(candidate);
|
|
1881
|
+
return { original: String(candidate), canonical: SHAPE_ALIASES.get(key3) ?? "rect", placeholderKind: mediaKind };
|
|
1882
|
+
}
|
|
1883
|
+
if (mediaKind) {
|
|
1884
|
+
return formShape ? { original: String(formShape), canonical: SHAPE_ALIASES.get(shapeKey(formShape)), placeholderKind: mediaKind } : { original: mediaKind, canonical: mediaKind, placeholderKind: mediaKind };
|
|
1885
|
+
}
|
|
1886
|
+
return { original: "rect", canonical: "rect" };
|
|
1887
|
+
}
|
|
1888
|
+
function prepareNode(node = {}) {
|
|
1889
|
+
const input = node && typeof node === "object" ? node : {};
|
|
1890
|
+
const metadataInput = input.metadata && typeof input.metadata === "object" ? input.metadata : {};
|
|
1891
|
+
const { original, canonical, placeholderKind } = shapeForNode(input);
|
|
1892
|
+
const label = metadataField(metadataInput, "label") ?? input.label ?? input.text ?? input.value ?? "";
|
|
1893
|
+
let lines = labelLines(label, input.labelType ?? metadataInput.labelType ?? "text");
|
|
1894
|
+
const shapePlaceholder = shapeKey(original) !== "rect" && !SHAPE_ALIASES.has(shapeKey(original));
|
|
1895
|
+
const prefixes = [];
|
|
1896
|
+
if (shapePlaceholder) prefixes.push(`[${original}]`);
|
|
1897
|
+
if (placeholderKind) prefixes.push(`[${placeholderKind}]`);
|
|
1898
|
+
else if (canonical === "image" || canonical === "icon") prefixes.push(`[${canonical}]`);
|
|
1899
|
+
if (prefixes.length) {
|
|
1900
|
+
lines = lines.length === 1 && lines[0] === "" ? prefixes : [...prefixes, ...lines];
|
|
1901
|
+
}
|
|
1902
|
+
const widest = Math.max(0, ...lines.map(displayWidth));
|
|
1903
|
+
const padding = 1;
|
|
1904
|
+
const borderWidth = 2;
|
|
1905
|
+
const borderHeight = 2;
|
|
1906
|
+
const minimumWidth = canonical === "circle" || canonical === "diamond" ? 5 : canonical === "image" || canonical === "icon" ? 7 : 5;
|
|
1907
|
+
const minimumHeight = canonical === "circle" || canonical === "diamond" ? 5 : 3;
|
|
1908
|
+
let width = Math.max(minimumWidth, widest + padding * 2 + borderWidth);
|
|
1909
|
+
let height = Math.max(minimumHeight, lines.length + borderHeight);
|
|
1910
|
+
const originalProperties = { ...input };
|
|
1911
|
+
delete originalProperties.metadata;
|
|
1912
|
+
const metadata = { ...metadataInput };
|
|
1913
|
+
if (metadata.originalShape === void 0) metadata.originalShape = original;
|
|
1914
|
+
if (metadata.originalProperties === void 0) metadata.originalProperties = originalProperties;
|
|
1915
|
+
if (shapePlaceholder || placeholderKind) {
|
|
1916
|
+
metadata.placeholder = true;
|
|
1917
|
+
if (shapePlaceholder) metadata.placeholderFor = original;
|
|
1918
|
+
if (placeholderKind) metadata.placeholderKind = placeholderKind;
|
|
1919
|
+
}
|
|
1920
|
+
return { lines, shape: canonical, width, height, metadata, originalShape: original };
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
// src/place-labels.js
|
|
1924
|
+
function placeLabels(layout2) {
|
|
1925
|
+
validateInput(layout2);
|
|
1926
|
+
const boxes = layout2.boxes;
|
|
1927
|
+
const edges = layout2.edges;
|
|
1928
|
+
const obstacles = buildBoxObstacles(boxes);
|
|
1929
|
+
const routeCells = /* @__PURE__ */ new Map();
|
|
1930
|
+
const arrowCells = /* @__PURE__ */ new Set();
|
|
1931
|
+
for (const edge of edges) {
|
|
1932
|
+
validateRoute(edge);
|
|
1933
|
+
const cells = segmentCellsForRoute(edge.points);
|
|
1934
|
+
for (const cell of cells) {
|
|
1935
|
+
const cellKey = key(cell.x, cell.y);
|
|
1936
|
+
if (!routeCells.has(cellKey)) routeCells.set(cellKey, /* @__PURE__ */ new Set());
|
|
1937
|
+
routeCells.get(cellKey).add(edge.id);
|
|
1938
|
+
}
|
|
1939
|
+
deriveArrowCells(edge, arrowCells);
|
|
1940
|
+
}
|
|
1941
|
+
const placed = [];
|
|
1942
|
+
for (const edge of edges) {
|
|
1943
|
+
if (!edge.label) continue;
|
|
1944
|
+
const label = normalizeLabel(edge.label, edge.id);
|
|
1945
|
+
const route = edge.points;
|
|
1946
|
+
const candidate = findPlacement({
|
|
1947
|
+
edge,
|
|
1948
|
+
label,
|
|
1949
|
+
route,
|
|
1950
|
+
obstacles,
|
|
1951
|
+
routeCells,
|
|
1952
|
+
arrowCells,
|
|
1953
|
+
placed,
|
|
1954
|
+
bounds: layoutBounds(layout2, boxes, edges)
|
|
1955
|
+
});
|
|
1956
|
+
if (!candidate) {
|
|
1957
|
+
throw new FlowInkError(`Cannot place label for edge ${edge.id} without hiding graph geometry.`, {
|
|
1958
|
+
code: "LABEL_PLACEMENT_ERROR"
|
|
1959
|
+
});
|
|
1960
|
+
}
|
|
1961
|
+
edge.label = { ...edge.label, ...label, x: candidate.x, y: candidate.y };
|
|
1962
|
+
placed.push({ edgeId: edge.id, ...label, x: candidate.x, y: candidate.y });
|
|
1963
|
+
}
|
|
1964
|
+
translateAndExpand(layout2);
|
|
1965
|
+
return layout2;
|
|
1966
|
+
}
|
|
1967
|
+
function validateInput(layout2) {
|
|
1968
|
+
if (!layout2 || typeof layout2 !== "object" || !Array.isArray(layout2.boxes) || !Array.isArray(layout2.edges)) {
|
|
1969
|
+
fail("Layout must contain boxes and edges arrays.", "INVALID_LAYOUT");
|
|
1970
|
+
}
|
|
1971
|
+
for (const box of layout2.boxes) {
|
|
1972
|
+
if (!box || typeof box.id !== "string" || !Number.isInteger(box.x) || !Number.isInteger(box.y) || !Number.isInteger(box.width) || !Number.isInteger(box.height) || box.width < 1 || box.height < 1 || !Array.isArray(box.lines)) {
|
|
1973
|
+
fail(`Layout box ${box?.id ?? "<unknown>"} is invalid.`, "INVALID_LAYOUT");
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1977
|
+
for (const edge of layout2.edges) {
|
|
1978
|
+
if (!edge || typeof edge.id !== "string" || ids.has(edge.id)) fail(`Layout edge id is missing or duplicated: ${edge?.id ?? "<unknown>"}.`, "INVALID_LAYOUT");
|
|
1979
|
+
ids.add(edge.id);
|
|
1980
|
+
if (!Array.isArray(edge.points) || edge.points.length < 1) fail(`Layout edge ${edge.id} must have at least one point.`, "INVALID_LAYOUT");
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
function validateRoute(edge) {
|
|
1984
|
+
for (const point of edge.points) {
|
|
1985
|
+
if (!point || !Number.isInteger(point.x) || !Number.isInteger(point.y)) {
|
|
1986
|
+
fail(`Layout edge ${edge.id} has an invalid route point.`, "INVALID_LAYOUT");
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
for (let i = 1; i < edge.points.length; i += 1) {
|
|
1990
|
+
const a = edge.points[i - 1];
|
|
1991
|
+
const b = edge.points[i];
|
|
1992
|
+
if (a.x !== b.x && a.y !== b.y) fail(`Layout edge ${edge.id} is not orthogonal.`, "NON_ORTHOGONAL_EDGE");
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
function normalizeLabel(source, edgeId) {
|
|
1996
|
+
if (!source || !Array.isArray(source.lines)) fail(`Label for edge ${edgeId} must provide lines.`, "INVALID_LAYOUT");
|
|
1997
|
+
const lines = source.lines.flatMap((line) => String(line).replace(/\r\n?/g, "\n").split("\n"));
|
|
1998
|
+
const measuredWidth = Math.max(0, ...lines.map((line) => displayWidth(line)));
|
|
1999
|
+
const suppliedWidth = Number.isInteger(source.width) && source.width > 0 ? source.width : 0;
|
|
2000
|
+
const suppliedHeight = Number.isInteger(source.height) && source.height > 0 ? source.height : 0;
|
|
2001
|
+
return {
|
|
2002
|
+
lines: lines.length ? lines : [""],
|
|
2003
|
+
width: Math.max(1, measuredWidth, suppliedWidth),
|
|
2004
|
+
height: Math.max(1, lines.length, suppliedHeight)
|
|
2005
|
+
};
|
|
2006
|
+
}
|
|
2007
|
+
function buildBoxObstacles(boxes) {
|
|
2008
|
+
const obstacles = /* @__PURE__ */ new Set();
|
|
2009
|
+
for (const box of boxes) {
|
|
2010
|
+
const isGroup = box.kind === "subgraph";
|
|
2011
|
+
for (let y = box.y; y < box.y + box.height; y += 1) {
|
|
2012
|
+
for (let x = box.x; x < box.x + box.width; x += 1) {
|
|
2013
|
+
const border = x === box.x || x === box.x + box.width - 1 || y === box.y || y === box.y + box.height - 1;
|
|
2014
|
+
const title = isGroup && y >= box.y + 1 && y < box.y + 1 + box.lines.length;
|
|
2015
|
+
if (!isGroup || border || title) obstacles.add(key(x, y));
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
return obstacles;
|
|
2020
|
+
}
|
|
2021
|
+
function findPlacement({ edge, label, route, obstacles, routeCells, arrowCells, placed, bounds }) {
|
|
2022
|
+
const segments = routeSegments(route).filter((segment2) => segment2.length > 0).sort((a, b) => b.length - a.length || a.index - b.index);
|
|
2023
|
+
const maxGap = Math.max(8, bounds.width + bounds.height + label.width + label.height + 4);
|
|
2024
|
+
for (let gap = 1; gap <= maxGap; gap += 1) {
|
|
2025
|
+
for (const segment2 of segments) {
|
|
2026
|
+
const candidates = adjacentCandidates(segment2, label, gap);
|
|
2027
|
+
for (const candidate of candidates) {
|
|
2028
|
+
if (clear(candidate, label, edge.id, false, obstacles, routeCells, arrowCells, placed)) return candidate;
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
const anchor2 = route[0];
|
|
2033
|
+
const ringLimit = Math.max(8, bounds.width + bounds.height + label.width + label.height + 4);
|
|
2034
|
+
for (let radius = 1; radius <= ringLimit; radius += 1) {
|
|
2035
|
+
const ring = [
|
|
2036
|
+
{ x: anchor2.x - Math.floor(label.width / 2), y: anchor2.y - label.height - radius },
|
|
2037
|
+
{ x: anchor2.x - Math.floor(label.width / 2), y: anchor2.y + radius },
|
|
2038
|
+
{ x: anchor2.x - label.width - radius, y: anchor2.y - Math.floor(label.height / 2) },
|
|
2039
|
+
{ x: anchor2.x + radius, y: anchor2.y - Math.floor(label.height / 2) }
|
|
2040
|
+
];
|
|
2041
|
+
for (const candidate of ring) {
|
|
2042
|
+
if (clear(candidate, label, edge.id, false, obstacles, routeCells, arrowCells, placed)) return candidate;
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
if (label.height === 1) {
|
|
2046
|
+
for (const segment2 of segments) {
|
|
2047
|
+
const candidate = inlineCandidate(segment2, label);
|
|
2048
|
+
if (candidate && clear(candidate, label, edge.id, true, obstacles, routeCells, arrowCells, placed) && connectedInline(candidate, label, edge.id, segment2, routeCells)) return candidate;
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
return null;
|
|
2052
|
+
}
|
|
2053
|
+
function routeSegments(points) {
|
|
2054
|
+
const result = [];
|
|
2055
|
+
for (let i = 1; i < points.length; i += 1) {
|
|
2056
|
+
const a = points[i - 1];
|
|
2057
|
+
const b = points[i];
|
|
2058
|
+
result.push({ index: i - 1, a, b, horizontal: a.y === b.y, length: Math.abs(b.x - a.x) + Math.abs(b.y - a.y) });
|
|
2059
|
+
}
|
|
2060
|
+
return result;
|
|
2061
|
+
}
|
|
2062
|
+
function adjacentCandidates(segment2, label, gap) {
|
|
2063
|
+
const { a, b } = segment2;
|
|
2064
|
+
const midX = Math.floor((a.x + b.x) / 2);
|
|
2065
|
+
const midY = Math.floor((a.y + b.y) / 2);
|
|
2066
|
+
const candidates = [];
|
|
2067
|
+
if (segment2.horizontal) {
|
|
2068
|
+
const x = midX - Math.floor(label.width / 2);
|
|
2069
|
+
candidates.push({ x, y: a.y - label.height - gap });
|
|
2070
|
+
candidates.push({ x, y: a.y + gap });
|
|
2071
|
+
} else {
|
|
2072
|
+
const y = midY - Math.floor(label.height / 2);
|
|
2073
|
+
candidates.push({ x: a.x - label.width - gap, y });
|
|
2074
|
+
candidates.push({ x: a.x + gap, y });
|
|
2075
|
+
}
|
|
2076
|
+
return candidates;
|
|
2077
|
+
}
|
|
2078
|
+
function inlineCandidate(segment2, label) {
|
|
2079
|
+
const { a, b } = segment2;
|
|
2080
|
+
if (segment2.horizontal) return { x: Math.floor((a.x + b.x - label.width) / 2), y: a.y };
|
|
2081
|
+
return { x: a.x, y: Math.floor((a.y + b.y - label.height) / 2) };
|
|
2082
|
+
}
|
|
2083
|
+
function clear(candidate, label, edgeId, inline, obstacles, routeCells, arrowCells, placed) {
|
|
2084
|
+
for (let y = candidate.y; y < candidate.y + label.height; y += 1) {
|
|
2085
|
+
for (let x = candidate.x; x < candidate.x + label.width; x += 1) {
|
|
2086
|
+
const cellKey = key(x, y);
|
|
2087
|
+
if (obstacles.has(cellKey) || arrowCells.has(cellKey)) return false;
|
|
2088
|
+
const owners = routeCells.get(cellKey);
|
|
2089
|
+
if (owners && (!inline || owners.size !== 1 || !owners.has(edgeId))) return false;
|
|
2090
|
+
if (placed.some((other) => intersects(candidate, label, other))) return false;
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
for (let y = candidate.y - 1; y <= candidate.y + label.height; y += 1) {
|
|
2094
|
+
for (let x = candidate.x - 1; x <= candidate.x + label.width; x += 1) {
|
|
2095
|
+
const owners = routeCells.get(key(x, y));
|
|
2096
|
+
if (owners && [...owners].some((owner) => owner !== edgeId)) return false;
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
2099
|
+
const ownDistance = distanceToRoute(candidate, label, routeCells, edgeId, true);
|
|
2100
|
+
const unrelatedDistance = distanceToRoute(candidate, label, routeCells, edgeId, false);
|
|
2101
|
+
if (ownDistance >= unrelatedDistance) return false;
|
|
2102
|
+
return true;
|
|
2103
|
+
}
|
|
2104
|
+
function distanceToRoute(candidate, label, routeCells, edgeId, own) {
|
|
2105
|
+
let distance = Infinity;
|
|
2106
|
+
for (const [cellKey, owners] of routeCells) {
|
|
2107
|
+
const isOwn = owners.size === 1 && owners.has(edgeId);
|
|
2108
|
+
if (isOwn !== own) continue;
|
|
2109
|
+
const [x, y] = cellKey.split(",").map(Number);
|
|
2110
|
+
distance = Math.min(distance, pointToRectDistance(x, y, candidate, label));
|
|
2111
|
+
if (distance === 0) return 0;
|
|
2112
|
+
}
|
|
2113
|
+
return distance;
|
|
2114
|
+
}
|
|
2115
|
+
function pointToRectDistance(x, y, candidate, label) {
|
|
2116
|
+
const dx = x < candidate.x ? candidate.x - x : x >= candidate.x + label.width ? x - (candidate.x + label.width - 1) : 0;
|
|
2117
|
+
const dy = y < candidate.y ? candidate.y - y : y >= candidate.y + label.height ? y - (candidate.y + label.height - 1) : 0;
|
|
2118
|
+
return dx + dy;
|
|
2119
|
+
}
|
|
2120
|
+
function connectedInline(candidate, label, edgeId, segment2, routeCells) {
|
|
2121
|
+
let inside2 = false;
|
|
2122
|
+
let outsideBefore = false;
|
|
2123
|
+
let outsideAfter = false;
|
|
2124
|
+
for (const cell of segmentCells(segment2.a, segment2.b)) {
|
|
2125
|
+
if (cell.x >= candidate.x && cell.x < candidate.x + label.width && cell.y >= candidate.y && cell.y < candidate.y + label.height) {
|
|
2126
|
+
inside2 = true;
|
|
2127
|
+
const before = { x: cell.x - Math.sign(segment2.b.x - segment2.a.x), y: cell.y - Math.sign(segment2.b.y - segment2.a.y) };
|
|
2128
|
+
const after = { x: cell.x + Math.sign(segment2.b.x - segment2.a.x), y: cell.y + Math.sign(segment2.b.y - segment2.a.y) };
|
|
2129
|
+
if (routeCells.get(key(before.x, before.y))?.has(edgeId)) outsideBefore = true;
|
|
2130
|
+
if (routeCells.get(key(after.x, after.y))?.has(edgeId)) outsideAfter = true;
|
|
2131
|
+
}
|
|
2132
|
+
}
|
|
2133
|
+
return inside2 && outsideBefore && outsideAfter;
|
|
2134
|
+
}
|
|
2135
|
+
function intersects(a, aSize, b) {
|
|
2136
|
+
return a.x < b.x + b.width && b.x < a.x + aSize.width && a.y < b.y + b.height && b.y < a.y + aSize.height;
|
|
2137
|
+
}
|
|
2138
|
+
function deriveArrowCells(edge, output) {
|
|
2139
|
+
if (edge.points.length < 2) return;
|
|
2140
|
+
const first = distinctPair(edge.points, true);
|
|
2141
|
+
const last = distinctPair(edge.points, false);
|
|
2142
|
+
if (edge.arrowStart && edge.arrowStart !== "none" && first) output.add(key(first.next.x, first.next.y));
|
|
2143
|
+
if (edge.arrowEnd && edge.arrowEnd !== "none" && last) output.add(key(last.previous.x, last.previous.y));
|
|
2144
|
+
}
|
|
2145
|
+
function distinctPair(points, start) {
|
|
2146
|
+
if (start) {
|
|
2147
|
+
for (let i = 1; i < points.length; i += 1) {
|
|
2148
|
+
if (points[i].x !== points[0].x || points[i].y !== points[0].y) return { next: oneStep(points[0], points[i]) };
|
|
2149
|
+
}
|
|
2150
|
+
} else {
|
|
2151
|
+
for (let i = points.length - 2; i >= 0; i -= 1) {
|
|
2152
|
+
if (points[i].x !== points.at(-1).x || points[i].y !== points.at(-1).y) return { previous: oneStep(points.at(-1), points[i]) };
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
2155
|
+
return null;
|
|
2156
|
+
}
|
|
2157
|
+
function oneStep(from, toward) {
|
|
2158
|
+
return { x: from.x + Math.sign(toward.x - from.x), y: from.y + Math.sign(toward.y - from.y) };
|
|
2159
|
+
}
|
|
2160
|
+
function segmentCells(a, b) {
|
|
2161
|
+
const cells = [];
|
|
2162
|
+
const dx = Math.sign(b.x - a.x);
|
|
2163
|
+
const dy = Math.sign(b.y - a.y);
|
|
2164
|
+
let x = a.x;
|
|
2165
|
+
let y = a.y;
|
|
2166
|
+
cells.push({ x, y });
|
|
2167
|
+
while (x !== b.x || y !== b.y) {
|
|
2168
|
+
x += dx;
|
|
2169
|
+
y += dy;
|
|
2170
|
+
cells.push({ x, y });
|
|
2171
|
+
}
|
|
2172
|
+
return cells;
|
|
2173
|
+
}
|
|
2174
|
+
function segmentCellsForRoute(points) {
|
|
2175
|
+
const result = [];
|
|
2176
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2177
|
+
for (let i = 1; i < points.length; i += 1) {
|
|
2178
|
+
for (const cell of segmentCells(points[i - 1], points[i])) {
|
|
2179
|
+
const cellKey = key(cell.x, cell.y);
|
|
2180
|
+
if (!seen.has(cellKey)) {
|
|
2181
|
+
seen.add(cellKey);
|
|
2182
|
+
result.push(cell);
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2186
|
+
if (points.length === 1) result.push(points[0]);
|
|
2187
|
+
return result;
|
|
2188
|
+
}
|
|
2189
|
+
function layoutBounds(layout2, boxes, edges) {
|
|
2190
|
+
const xs = [0];
|
|
2191
|
+
const ys = [0];
|
|
2192
|
+
for (const box of boxes) {
|
|
2193
|
+
xs.push(box.x, box.x + box.width);
|
|
2194
|
+
ys.push(box.y, box.y + box.height);
|
|
2195
|
+
}
|
|
2196
|
+
for (const edge of edges) for (const point of edge.points) {
|
|
2197
|
+
xs.push(point.x);
|
|
2198
|
+
ys.push(point.y);
|
|
2199
|
+
}
|
|
2200
|
+
return { width: Math.max(1, Math.max(...xs) - Math.min(...xs) + (layout2.width || 0)), height: Math.max(1, Math.max(...ys) - Math.min(...ys) + (layout2.height || 0)) };
|
|
2201
|
+
}
|
|
2202
|
+
function translateAndExpand(layout2) {
|
|
2203
|
+
const labels = layout2.edges.flatMap((edge) => edge.label ? [edge.label] : []);
|
|
2204
|
+
const xValues = [0];
|
|
2205
|
+
const yValues = [0];
|
|
2206
|
+
for (const box of layout2.boxes) {
|
|
2207
|
+
xValues.push(box.x);
|
|
2208
|
+
yValues.push(box.y);
|
|
2209
|
+
}
|
|
2210
|
+
for (const edge of layout2.edges) for (const point of edge.points) {
|
|
2211
|
+
xValues.push(point.x);
|
|
2212
|
+
yValues.push(point.y);
|
|
2213
|
+
}
|
|
2214
|
+
for (const label of labels) {
|
|
2215
|
+
xValues.push(label.x);
|
|
2216
|
+
yValues.push(label.y);
|
|
2217
|
+
}
|
|
2218
|
+
const shiftX = Math.max(0, -Math.min(...xValues));
|
|
2219
|
+
const shiftY = Math.max(0, -Math.min(...yValues));
|
|
2220
|
+
if (shiftX || shiftY) {
|
|
2221
|
+
for (const box of layout2.boxes) {
|
|
2222
|
+
box.x += shiftX;
|
|
2223
|
+
box.y += shiftY;
|
|
2224
|
+
}
|
|
2225
|
+
for (const edge of layout2.edges) {
|
|
2226
|
+
for (const point of edge.points) {
|
|
2227
|
+
point.x += shiftX;
|
|
2228
|
+
point.y += shiftY;
|
|
2229
|
+
}
|
|
2230
|
+
if (edge.label) {
|
|
2231
|
+
edge.label.x += shiftX;
|
|
2232
|
+
edge.label.y += shiftY;
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
const width = Math.max(0, Number.isInteger(layout2.width) ? layout2.width + shiftX : 0);
|
|
2237
|
+
const height = Math.max(0, Number.isInteger(layout2.height) ? layout2.height + shiftY : 0);
|
|
2238
|
+
layout2.width = width;
|
|
2239
|
+
layout2.height = height;
|
|
2240
|
+
for (const box of layout2.boxes) {
|
|
2241
|
+
layout2.width = Math.max(layout2.width, box.x + box.width);
|
|
2242
|
+
layout2.height = Math.max(layout2.height, box.y + box.height);
|
|
2243
|
+
}
|
|
2244
|
+
for (const edge of layout2.edges) {
|
|
2245
|
+
for (const point of edge.points) {
|
|
2246
|
+
layout2.width = Math.max(layout2.width, point.x + 1);
|
|
2247
|
+
layout2.height = Math.max(layout2.height, point.y + 1);
|
|
2248
|
+
}
|
|
2249
|
+
if (edge.label) {
|
|
2250
|
+
layout2.width = Math.max(layout2.width, edge.label.x + edge.label.width);
|
|
2251
|
+
layout2.height = Math.max(layout2.height, edge.label.y + edge.label.height);
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
function key(x, y) {
|
|
2256
|
+
return `${x},${y}`;
|
|
2257
|
+
}
|
|
2258
|
+
function fail(message, code) {
|
|
2259
|
+
throw new FlowInkError(message, { code });
|
|
2260
|
+
}
|
|
2261
|
+
|
|
2262
|
+
// src/layout.js
|
|
2263
|
+
var elk = new ELK();
|
|
2264
|
+
var DIRECTIONS = Object.freeze({ TB: "DOWN", BT: "UP", LR: "RIGHT", RL: "LEFT" });
|
|
2265
|
+
async function layout(graph) {
|
|
2266
|
+
const context = makeContext(graph);
|
|
2267
|
+
let laidOut;
|
|
2268
|
+
try {
|
|
2269
|
+
laidOut = await elk.layout(toElkGraph(context));
|
|
2270
|
+
} catch (cause) {
|
|
2271
|
+
throw new FlowInkError(`ELK could not lay out the flowchart: ${cause instanceof Error ? cause.message : String(cause)}`, {
|
|
2272
|
+
code: "LAYOUT_ERROR",
|
|
2273
|
+
cause
|
|
2274
|
+
});
|
|
2275
|
+
}
|
|
2276
|
+
const result = fromElkGraph(context, laidOut);
|
|
2277
|
+
if (needsWireClearance(context.graph, result)) expandGrid(result);
|
|
2278
|
+
return placeLabels(result);
|
|
2279
|
+
}
|
|
2280
|
+
function needsWireClearance(graph, layoutGraph) {
|
|
2281
|
+
const pairs = /* @__PURE__ */ new Set();
|
|
2282
|
+
const reverse = /* @__PURE__ */ new Set();
|
|
2283
|
+
for (const edge of graph.edges) {
|
|
2284
|
+
const pair = pairKey(edge.source, edge.target);
|
|
2285
|
+
if (pairs.has(pair) || reverse.has(pairKey(edge.target, edge.source))) return true;
|
|
2286
|
+
pairs.add(pair);
|
|
2287
|
+
reverse.add(pair);
|
|
2288
|
+
}
|
|
2289
|
+
const segments = layoutGraph.edges.flatMap((edge) => edge.points.slice(1).map((b, index) => ({
|
|
2290
|
+
id: edge.id,
|
|
2291
|
+
a: edge.points[index],
|
|
2292
|
+
b,
|
|
2293
|
+
horizontal: edge.points[index].y === b.y
|
|
2294
|
+
})));
|
|
2295
|
+
for (let i = 0; i < segments.length; i += 1) for (let j = i + 1; j < segments.length; j += 1) {
|
|
2296
|
+
const a = segments[i];
|
|
2297
|
+
const b = segments[j];
|
|
2298
|
+
if (a.id === b.id || a.horizontal !== b.horizontal) continue;
|
|
2299
|
+
const fixed = a.horizontal ? "y" : "x";
|
|
2300
|
+
const varying = a.horizontal ? "x" : "y";
|
|
2301
|
+
const distance = Math.abs(a.a[fixed] - b.a[fixed]);
|
|
2302
|
+
const overlap = Math.min(Math.max(a.a[varying], a.b[varying]), Math.max(b.a[varying], b.b[varying])) - Math.max(Math.min(a.a[varying], a.b[varying]), Math.min(b.a[varying], b.b[varying]));
|
|
2303
|
+
if (distance === 1 && overlap >= 1) return true;
|
|
2304
|
+
}
|
|
2305
|
+
return false;
|
|
2306
|
+
}
|
|
2307
|
+
function expandGrid(layoutGraph) {
|
|
2308
|
+
for (const box of layoutGraph.boxes) {
|
|
2309
|
+
box.x *= 2;
|
|
2310
|
+
box.y *= 2;
|
|
2311
|
+
box.width = Math.max(1, (box.width - 1) * 2 + 1);
|
|
2312
|
+
box.height = Math.max(1, (box.height - 1) * 2 + 1);
|
|
2313
|
+
}
|
|
2314
|
+
for (const edge of layoutGraph.edges) {
|
|
2315
|
+
for (const point of edge.points) {
|
|
2316
|
+
point.x *= 2;
|
|
2317
|
+
point.y *= 2;
|
|
2318
|
+
}
|
|
2319
|
+
if (edge.label) {
|
|
2320
|
+
edge.label.x *= 2;
|
|
2321
|
+
edge.label.y *= 2;
|
|
2322
|
+
edge.label.width = Math.max(1, (edge.label.width - 1) * 2 + 1);
|
|
2323
|
+
edge.label.height = Math.max(1, (edge.label.height - 1) * 2 + 1);
|
|
2324
|
+
}
|
|
2325
|
+
}
|
|
2326
|
+
layoutGraph.width = Math.max(1, layoutGraph.width * 2);
|
|
2327
|
+
layoutGraph.height = Math.max(1, layoutGraph.height * 2);
|
|
2328
|
+
}
|
|
2329
|
+
function makeContext(graph) {
|
|
2330
|
+
if (!graph || typeof graph !== "object") invalid("A FlowGraph object is required.");
|
|
2331
|
+
if (!Array.isArray(graph.nodes) || !Array.isArray(graph.edges) || !Array.isArray(graph.subgraphs)) {
|
|
2332
|
+
invalid("FlowGraph must contain nodes, edges, and subgraphs arrays.");
|
|
2333
|
+
}
|
|
2334
|
+
if (!DIRECTIONS[graph.direction]) invalid(`Unsupported flow direction: ${String(graph.direction)}.`);
|
|
2335
|
+
const subgraphs = /* @__PURE__ */ new Map();
|
|
2336
|
+
for (const subgraph of graph.subgraphs) {
|
|
2337
|
+
requireId(subgraph, "subgraph");
|
|
2338
|
+
if (subgraphs.has(subgraph.id)) invalid(`Duplicate graph element id: ${subgraph.id}.`);
|
|
2339
|
+
subgraphs.set(subgraph.id, subgraph);
|
|
2340
|
+
}
|
|
2341
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
2342
|
+
for (const node of graph.nodes) {
|
|
2343
|
+
requireId(node, "node");
|
|
2344
|
+
if (subgraphs.has(node.id)) continue;
|
|
2345
|
+
if (nodes.has(node.id)) invalid(`Duplicate graph element id: ${node.id}.`);
|
|
2346
|
+
nodes.set(node.id, node);
|
|
2347
|
+
}
|
|
2348
|
+
const parent = /* @__PURE__ */ new Map();
|
|
2349
|
+
for (const node of nodes.values()) {
|
|
2350
|
+
if (node.parentId !== void 0 && !subgraphs.has(node.parentId)) {
|
|
2351
|
+
invalid(`Node ${node.id} refers to missing subgraph ${node.parentId}.`);
|
|
2352
|
+
}
|
|
2353
|
+
if (node.parentId !== void 0) parent.set(node.id, node.parentId);
|
|
2354
|
+
}
|
|
2355
|
+
for (const subgraph of subgraphs.values()) {
|
|
2356
|
+
if (subgraph.parentId !== void 0 && !subgraphs.has(subgraph.parentId)) {
|
|
2357
|
+
invalid(`Subgraph ${subgraph.id} refers to missing parent ${subgraph.parentId}.`);
|
|
2358
|
+
}
|
|
2359
|
+
if (subgraph.parentId !== void 0) parent.set(subgraph.id, subgraph.parentId);
|
|
2360
|
+
for (const childId of subgraph.nodeIds ?? []) {
|
|
2361
|
+
if (!nodes.has(childId) && !subgraphs.has(childId)) invalid(`Subgraph ${subgraph.id} refers to missing child ${childId}.`);
|
|
2362
|
+
const previous = parent.get(childId);
|
|
2363
|
+
if (previous !== void 0 && previous !== subgraph.id) {
|
|
2364
|
+
invalid(`Graph element ${childId} has conflicting subgraph parents.`);
|
|
2365
|
+
}
|
|
2366
|
+
parent.set(childId, subgraph.id);
|
|
2367
|
+
}
|
|
2368
|
+
}
|
|
2369
|
+
for (const id of [...nodes.keys(), ...subgraphs.keys()]) {
|
|
2370
|
+
const seen = /* @__PURE__ */ new Set([id]);
|
|
2371
|
+
let current = parent.get(id);
|
|
2372
|
+
while (current !== void 0) {
|
|
2373
|
+
if (seen.has(current)) invalid(`Cyclic subgraph containment involving ${id}.`);
|
|
2374
|
+
seen.add(current);
|
|
2375
|
+
current = parent.get(current);
|
|
2376
|
+
}
|
|
2377
|
+
}
|
|
2378
|
+
for (const edge of graph.edges) {
|
|
2379
|
+
requireId(edge, "edge");
|
|
2380
|
+
if (!nodes.has(edge.source) && !subgraphs.has(edge.source)) invalid(`Edge ${edge.id} has missing source ${edge.source}.`);
|
|
2381
|
+
if (!nodes.has(edge.target) && !subgraphs.has(edge.target)) invalid(`Edge ${edge.id} has missing target ${edge.target}.`);
|
|
2382
|
+
}
|
|
2383
|
+
const children = /* @__PURE__ */ new Map();
|
|
2384
|
+
const order = /* @__PURE__ */ new Map();
|
|
2385
|
+
const put = (id, index) => {
|
|
2386
|
+
const p = parent.get(id);
|
|
2387
|
+
const key3 = p ?? null;
|
|
2388
|
+
if (!children.has(key3)) children.set(key3, []);
|
|
2389
|
+
if (!children.get(key3).includes(id)) children.get(key3).push(id);
|
|
2390
|
+
order.set(id, index);
|
|
2391
|
+
};
|
|
2392
|
+
graph.nodes.forEach((n, i) => put(n.id, i));
|
|
2393
|
+
graph.subgraphs.forEach((s, i) => put(s.id, graph.nodes.length + i));
|
|
2394
|
+
for (const list of children.values()) list.sort((a, b) => order.get(a) - order.get(b) || a.localeCompare(b));
|
|
2395
|
+
const element = new Map([...nodes, ...subgraphs]);
|
|
2396
|
+
const elkIds = /* @__PURE__ */ new Map();
|
|
2397
|
+
let nodeIndex = 0;
|
|
2398
|
+
let groupIndex = 0;
|
|
2399
|
+
for (const id of nodes.keys()) elkIds.set(id, `n${nodeIndex++}`);
|
|
2400
|
+
for (const id of subgraphs.keys()) elkIds.set(id, `g${groupIndex++}`);
|
|
2401
|
+
const edgeElkIds = new Map(graph.edges.map((edge, index) => [edge.id, `e${index}`]));
|
|
2402
|
+
const dimensions = /* @__PURE__ */ new Map();
|
|
2403
|
+
for (const node of nodes.values()) {
|
|
2404
|
+
const prepared = prepareNode(node);
|
|
2405
|
+
const lines = Array.isArray(prepared.lines) ? prepared.lines.map(String) : [String(node.label ?? node.id)];
|
|
2406
|
+
dimensions.set(node.id, {
|
|
2407
|
+
lines,
|
|
2408
|
+
shape: prepared.shape ?? node.shape ?? "rect",
|
|
2409
|
+
width: positiveSize(prepared.width, maxWidth(lines, node.label)),
|
|
2410
|
+
height: positiveSize(prepared.height, Math.max(3, lines.length + 2))
|
|
2411
|
+
});
|
|
2412
|
+
}
|
|
2413
|
+
for (const subgraph of subgraphs.values()) {
|
|
2414
|
+
const text = String(subgraph.label ?? subgraph.id);
|
|
2415
|
+
const lines = labelLines(text, subgraph.metadata?.labelType ?? "text").map(String);
|
|
2416
|
+
dimensions.set(subgraph.id, {
|
|
2417
|
+
lines,
|
|
2418
|
+
shape: "subgraph",
|
|
2419
|
+
width: Math.max(3, maxWidth(lines, text) + 2),
|
|
2420
|
+
height: Math.max(3, lines.length + 2)
|
|
2421
|
+
});
|
|
2422
|
+
}
|
|
2423
|
+
const incident = /* @__PURE__ */ new Map();
|
|
2424
|
+
for (const edge of graph.edges) {
|
|
2425
|
+
incident.set(edge.source, (incident.get(edge.source) ?? 0) + 1);
|
|
2426
|
+
incident.set(edge.target, (incident.get(edge.target) ?? 0) + 1);
|
|
2427
|
+
}
|
|
2428
|
+
for (const [id, count] of incident) {
|
|
2429
|
+
const dim = dimensions.get(id);
|
|
2430
|
+
if (!dim) continue;
|
|
2431
|
+
const direction = contextDirection(graph, parent, subgraphs, id);
|
|
2432
|
+
if (direction === "LR" || direction === "RL") dim.height = Math.max(dim.height, count * 2 + 1);
|
|
2433
|
+
else dim.width = Math.max(dim.width, count * 2 + 1);
|
|
2434
|
+
}
|
|
2435
|
+
return { graph, nodes, subgraphs, element, parent, children, dimensions, order, elkIds, edgeElkIds };
|
|
2436
|
+
}
|
|
2437
|
+
function contextDirection(graph, parent, subgraphs, id) {
|
|
2438
|
+
let current = id;
|
|
2439
|
+
while (current !== void 0) {
|
|
2440
|
+
const direction = subgraphs.get(current)?.direction;
|
|
2441
|
+
if (direction) return direction;
|
|
2442
|
+
current = parent.get(current);
|
|
2443
|
+
}
|
|
2444
|
+
return graph.direction;
|
|
2445
|
+
}
|
|
2446
|
+
function toElkGraph(context) {
|
|
2447
|
+
const { graph } = context;
|
|
2448
|
+
const root = {
|
|
2449
|
+
id: "r0",
|
|
2450
|
+
layoutOptions: commonLayoutOptions(DIRECTIONS[graph.direction]),
|
|
2451
|
+
children: containerChildren(context, null),
|
|
2452
|
+
edges: containerEdges(context, null)
|
|
2453
|
+
};
|
|
2454
|
+
return root;
|
|
2455
|
+
}
|
|
2456
|
+
function containerChildren(context, containerId) {
|
|
2457
|
+
const ids = context.children.get(containerId) ?? [];
|
|
2458
|
+
return ids.map((id) => {
|
|
2459
|
+
const dim = context.dimensions.get(id);
|
|
2460
|
+
if (context.subgraphs.has(id)) {
|
|
2461
|
+
const subgraph = context.subgraphs.get(id);
|
|
2462
|
+
const children = containerChildren(context, id);
|
|
2463
|
+
const result = {
|
|
2464
|
+
id: context.elkIds.get(id),
|
|
2465
|
+
labels: [{ id: `l${context.elkIds.get(id)}`, text: subgraph.label ?? id, width: dim.width - 2, height: Math.max(1, dim.lines.length) }],
|
|
2466
|
+
layoutOptions: commonLayoutOptions(subgraph.direction ? DIRECTIONS[subgraph.direction] : void 0, true, !hasExternalConnection(context, id)),
|
|
2467
|
+
children,
|
|
2468
|
+
edges: containerEdges(context, id)
|
|
2469
|
+
};
|
|
2470
|
+
if (children.length === 0) {
|
|
2471
|
+
result.width = elkSize(dim.width);
|
|
2472
|
+
result.height = elkSize(dim.height);
|
|
2473
|
+
}
|
|
2474
|
+
if (!result.layoutOptions["elk.direction"]) delete result.layoutOptions["elk.direction"];
|
|
2475
|
+
return result;
|
|
2476
|
+
}
|
|
2477
|
+
return { id: context.elkIds.get(id), width: elkSize(dim.width), height: elkSize(dim.height), labels: [] };
|
|
2478
|
+
});
|
|
2479
|
+
}
|
|
2480
|
+
function commonLayoutOptions(direction, nested = false, separateChildren = false) {
|
|
2481
|
+
const options = {
|
|
2482
|
+
"elk.algorithm": "layered",
|
|
2483
|
+
...direction ? { "elk.direction": direction } : {},
|
|
2484
|
+
"elk.edgeRouting": "ORTHOGONAL",
|
|
2485
|
+
"elk.hierarchyHandling": separateChildren ? "SEPARATE_CHILDREN" : "INCLUDE_CHILDREN",
|
|
2486
|
+
"elk.json.shapeCoords": "ROOT",
|
|
2487
|
+
"elk.json.edgeCoords": "ROOT",
|
|
2488
|
+
...nested ? {} : { "elk.layered.considerModelOrder.strategy": "NODES_AND_EDGES" },
|
|
2489
|
+
"elk.layered.considerModelOrder.portModelOrder": "true",
|
|
2490
|
+
"elk.layered.mergeEdges": "false",
|
|
2491
|
+
"elk.layered.mergeHierarchyEdges": "false",
|
|
2492
|
+
"elk.spacing.nodeNode": "2",
|
|
2493
|
+
"elk.layered.spacing.nodeNodeBetweenLayers": "3",
|
|
2494
|
+
"elk.layered.spacing.edgeNodeBetweenLayers": "2",
|
|
2495
|
+
"elk.spacing.edgeEdge": "2",
|
|
2496
|
+
"elk.spacing.edgeNode": "2",
|
|
2497
|
+
"elk.spacing.nodeSelfLoop": "2",
|
|
2498
|
+
"elk.padding": "[top=2,left=2,bottom=2,right=2]"
|
|
2499
|
+
};
|
|
2500
|
+
return options;
|
|
2501
|
+
}
|
|
2502
|
+
function hasExternalConnection(context, subgraphId) {
|
|
2503
|
+
return context.graph.edges.some((edge) => {
|
|
2504
|
+
const sourceInside = isDescendant(context, edge.source, subgraphId);
|
|
2505
|
+
const targetInside = isDescendant(context, edge.target, subgraphId);
|
|
2506
|
+
return sourceInside !== targetInside;
|
|
2507
|
+
});
|
|
2508
|
+
}
|
|
2509
|
+
function isDescendant(context, id, ancestor) {
|
|
2510
|
+
let current = context.parent.get(id);
|
|
2511
|
+
while (current !== void 0) {
|
|
2512
|
+
if (current === ancestor) return true;
|
|
2513
|
+
current = context.parent.get(current);
|
|
2514
|
+
}
|
|
2515
|
+
return false;
|
|
2516
|
+
}
|
|
2517
|
+
function containerEdges(context, containerId) {
|
|
2518
|
+
return context.graph.edges.filter((edge) => lowestCommonContainer(context, edge.source, edge.target) === containerId).map((edge) => {
|
|
2519
|
+
const dim = context.dimensions.get(edge.id);
|
|
2520
|
+
const result = {
|
|
2521
|
+
id: context.edgeElkIds.get(edge.id),
|
|
2522
|
+
sources: [context.elkIds.get(edge.source)],
|
|
2523
|
+
targets: [context.elkIds.get(edge.target)]
|
|
2524
|
+
};
|
|
2525
|
+
if (edge.label) {
|
|
2526
|
+
const lines = labelLines(edge.label, edge.labelType).map(String);
|
|
2527
|
+
result.labels = [{ id: `l${context.edgeElkIds.get(edge.id)}`, text: lines.join("\n"), width: Math.max(1, maxWidth(lines, edge.label)), height: Math.max(1, lines.length) }];
|
|
2528
|
+
}
|
|
2529
|
+
return result;
|
|
2530
|
+
});
|
|
2531
|
+
}
|
|
2532
|
+
function lowestCommonContainer(context, source, target) {
|
|
2533
|
+
if (source === target) return context.parent.get(source) ?? null;
|
|
2534
|
+
const ancestors = /* @__PURE__ */ new Set();
|
|
2535
|
+
let current = source;
|
|
2536
|
+
while (current !== void 0) {
|
|
2537
|
+
ancestors.add(current);
|
|
2538
|
+
current = context.parent.get(current);
|
|
2539
|
+
}
|
|
2540
|
+
ancestors.add(null);
|
|
2541
|
+
current = target;
|
|
2542
|
+
while (current !== void 0 && !ancestors.has(current)) current = context.parent.get(current);
|
|
2543
|
+
const common = ancestors.has(current) ? current : null;
|
|
2544
|
+
if (common !== null && !context.subgraphs.has(common)) return context.parent.get(common) ?? null;
|
|
2545
|
+
return common;
|
|
2546
|
+
}
|
|
2547
|
+
function fromElkGraph(context, result) {
|
|
2548
|
+
const internalElements = /* @__PURE__ */ new Map();
|
|
2549
|
+
const internalFloatBoxes = /* @__PURE__ */ new Map();
|
|
2550
|
+
walkOutput(result, internalElements, internalFloatBoxes, true);
|
|
2551
|
+
const outputElements = /* @__PURE__ */ new Map();
|
|
2552
|
+
const floatBoxes = /* @__PURE__ */ new Map();
|
|
2553
|
+
for (const [publicId, internalId] of context.elkIds) {
|
|
2554
|
+
const element = internalElements.get(internalId);
|
|
2555
|
+
if (element) outputElements.set(publicId, element);
|
|
2556
|
+
const float = internalFloatBoxes.get(internalId);
|
|
2557
|
+
if (float) floatBoxes.set(publicId, float);
|
|
2558
|
+
}
|
|
2559
|
+
const boxes = [];
|
|
2560
|
+
for (const [id, element] of context.element) {
|
|
2561
|
+
const laid = outputElements.get(id);
|
|
2562
|
+
if (!laid || !Number.isFinite(laid.x) || !Number.isFinite(laid.y)) {
|
|
2563
|
+
invalid(`ELK returned no position for ${id}.`, "LAYOUT_MISSING_BOX");
|
|
2564
|
+
}
|
|
2565
|
+
const dim = context.dimensions.get(id);
|
|
2566
|
+
const x = Math.floor(laid.x);
|
|
2567
|
+
const y = Math.floor(laid.y);
|
|
2568
|
+
const width2 = Math.max(dim.width, Math.ceil(laid.x + (laid.width ?? elkSize(dim.width))) - x + 1);
|
|
2569
|
+
const height2 = Math.max(dim.height, Math.ceil(laid.y + (laid.height ?? elkSize(dim.height))) - y + 1);
|
|
2570
|
+
boxes.push({ id, kind: context.subgraphs.has(id) ? "subgraph" : "node", x, y, width: width2, height: height2, lines: dim.lines, shape: dim.shape, ...context.parent.has(id) ? { parentId: context.parent.get(id) } : {} });
|
|
2571
|
+
}
|
|
2572
|
+
const boxById = new Map(boxes.map((box) => [box.id, box]));
|
|
2573
|
+
context.__boxById = boxById;
|
|
2574
|
+
const edgeOutputs = /* @__PURE__ */ new Map();
|
|
2575
|
+
const internalEdges = /* @__PURE__ */ new Map();
|
|
2576
|
+
walkEdges(result, internalEdges);
|
|
2577
|
+
for (const [publicId, internalId] of context.edgeElkIds) {
|
|
2578
|
+
const edge = internalEdges.get(internalId);
|
|
2579
|
+
if (edge) edgeOutputs.set(publicId, edge);
|
|
2580
|
+
}
|
|
2581
|
+
const occupied = /* @__PURE__ */ new Map();
|
|
2582
|
+
const placedLabels = [];
|
|
2583
|
+
const routes = /* @__PURE__ */ new Map();
|
|
2584
|
+
const endpointCounts = /* @__PURE__ */ new Map();
|
|
2585
|
+
for (const item of context.graph.edges) {
|
|
2586
|
+
endpointCounts.set(item.source, (endpointCounts.get(item.source) ?? 0) + 1);
|
|
2587
|
+
endpointCounts.set(item.target, (endpointCounts.get(item.target) ?? 0) + 1);
|
|
2588
|
+
}
|
|
2589
|
+
const endpointRanks = /* @__PURE__ */ new Map();
|
|
2590
|
+
for (const sourceEdge of context.graph.edges) {
|
|
2591
|
+
const output = edgeOutputs.get(sourceEdge.id);
|
|
2592
|
+
if (!output || !Array.isArray(output.sections) || output.sections.length === 0) {
|
|
2593
|
+
invalid(`ELK returned no route for edge ${sourceEdge.id}.`, "LAYOUT_MISSING_EDGE");
|
|
2594
|
+
}
|
|
2595
|
+
const sourceBox = boxById.get(sourceEdge.source);
|
|
2596
|
+
const targetBox = boxById.get(sourceEdge.target);
|
|
2597
|
+
const sourceRank = endpointRanks.get(sourceEdge.source) ?? 0;
|
|
2598
|
+
const targetRank = endpointRanks.get(sourceEdge.target) ?? 0;
|
|
2599
|
+
endpointRanks.set(sourceEdge.source, sourceRank + 1);
|
|
2600
|
+
endpointRanks.set(sourceEdge.target, targetRank + 1);
|
|
2601
|
+
const sourceOffset = 2 * (sourceRank - Math.floor((endpointCounts.get(sourceEdge.source) ?? 1) / 2));
|
|
2602
|
+
const targetOffset = 2 * (targetRank - Math.floor((endpointCounts.get(sourceEdge.target) ?? 1) / 2));
|
|
2603
|
+
const route = routePoints(output, sourceBox, targetBox, floatBoxes, context, occupied, { sourceOffset, targetOffset }, sourceEdge.source === sourceEdge.target ? { rank: targetRank, count: endpointCounts.get(sourceEdge.target) ?? 1 } : void 0, sourceEdge.arrowStart, sourceEdge.arrowEnd);
|
|
2604
|
+
if (route.length < 2) invalid(`ELK returned an empty route for edge ${sourceEdge.id}.`, "LAYOUT_EMPTY_EDGE");
|
|
2605
|
+
routes.set(sourceEdge.id, route);
|
|
2606
|
+
if (sourceEdge.stroke !== "invisible") addRouteToOccupied(occupied, route, sourceEdge, boxById);
|
|
2607
|
+
}
|
|
2608
|
+
const edges = [];
|
|
2609
|
+
for (const sourceEdge of context.graph.edges) {
|
|
2610
|
+
const output = edgeOutputs.get(sourceEdge.id);
|
|
2611
|
+
const sourceBox = boxById.get(sourceEdge.source);
|
|
2612
|
+
const route = routes.get(sourceEdge.id);
|
|
2613
|
+
const label = sourceEdge.label ? edgeLabel(output, sourceEdge, route, sourceBox, boxById, placedLabels, routes) : void 0;
|
|
2614
|
+
if (label) placedLabels.push({ ...label, route });
|
|
2615
|
+
edges.push({ id: sourceEdge.id, points: route, arrowStart: sourceEdge.arrowStart ?? "none", arrowEnd: sourceEdge.arrowEnd ?? "none", stroke: sourceEdge.stroke ?? "normal", ...label ? { label } : {} });
|
|
2616
|
+
}
|
|
2617
|
+
const minX = Math.min(0, ...boxes.map((box) => box.x), ...edges.flatMap((edge) => edge.points.map((point) => point.x)));
|
|
2618
|
+
const minY = Math.min(0, ...boxes.map((box) => box.y), ...edges.flatMap((edge) => edge.points.map((point) => point.y)));
|
|
2619
|
+
if (minX !== 0 || minY !== 0) {
|
|
2620
|
+
for (const box of boxes) {
|
|
2621
|
+
box.x -= minX;
|
|
2622
|
+
box.y -= minY;
|
|
2623
|
+
}
|
|
2624
|
+
for (const edge of edges) for (const point of edge.points) {
|
|
2625
|
+
point.x -= minX;
|
|
2626
|
+
point.y -= minY;
|
|
2627
|
+
}
|
|
2628
|
+
for (const edge of edges) if (edge.label) {
|
|
2629
|
+
edge.label.x -= minX;
|
|
2630
|
+
edge.label.y -= minY;
|
|
2631
|
+
}
|
|
2632
|
+
}
|
|
2633
|
+
const width = Math.max(1, ...boxes.map((box) => box.x + box.width), ...edges.flatMap((edge) => edge.points.map((point) => point.x + 1)));
|
|
2634
|
+
const height = Math.max(1, ...boxes.map((box) => box.y + box.height), ...edges.flatMap((edge) => edge.points.map((point) => point.y + 1)));
|
|
2635
|
+
return { boxes, edges, width, height };
|
|
2636
|
+
}
|
|
2637
|
+
function walkOutput(node, elements, floatBoxes, isRoot = false) {
|
|
2638
|
+
if (node?.id && !isRoot) {
|
|
2639
|
+
elements.set(node.id, node);
|
|
2640
|
+
if (Number.isFinite(node.x) && Number.isFinite(node.y)) floatBoxes.set(node.id, { x: node.x, y: node.y, width: node.width ?? 0, height: node.height ?? 0 });
|
|
2641
|
+
}
|
|
2642
|
+
for (const child of node?.children ?? []) walkOutput(child, elements, floatBoxes, false);
|
|
2643
|
+
}
|
|
2644
|
+
function walkEdges(node, edges) {
|
|
2645
|
+
for (const edge of node?.edges ?? []) edges.set(edge.id, edge);
|
|
2646
|
+
for (const child of node?.children ?? []) walkEdges(child, edges);
|
|
2647
|
+
}
|
|
2648
|
+
function routePoints(edge, sourceBox, targetBox, floatBoxes, context, occupied, endpointOffsets = {}, selfLoop, arrowStart = "none", arrowEnd = "none") {
|
|
2649
|
+
if (!sourceBox || !targetBox) invalid(`An edge endpoint has no layout box.`, "LAYOUT_MISSING_BOX");
|
|
2650
|
+
const sections = edge.sections;
|
|
2651
|
+
if (selfLoop && sourceBox.id === targetBox.id) {
|
|
2652
|
+
const custom = selfLoopRoute(sourceBox, selfLoop.rank, selfLoop.count);
|
|
2653
|
+
if (!routeBlocked(custom, context.__boxById, allowedBoxes(context, sourceBox.id, targetBox.id), occupied, sourceBox.id, targetBox.id, arrowStart, arrowEnd)) return custom;
|
|
2654
|
+
}
|
|
2655
|
+
const raw = [];
|
|
2656
|
+
for (const section of sections) {
|
|
2657
|
+
const points2 = [section.startPoint, ...section.bendPoints ?? [], section.endPoint].filter(Boolean);
|
|
2658
|
+
for (const point of points2) {
|
|
2659
|
+
if (!raw.length || raw[raw.length - 1].x !== point.x || raw[raw.length - 1].y !== point.y) raw.push({ x: point.x, y: point.y });
|
|
2660
|
+
}
|
|
2661
|
+
}
|
|
2662
|
+
if (raw.length < 2) return [];
|
|
2663
|
+
const sourceFloat = floatBoxes.get(sourceBox.id);
|
|
2664
|
+
const targetFloat = floatBoxes.get(targetBox.id);
|
|
2665
|
+
const sourceAnchor = anchor(raw[0], raw[1], sourceFloat, sourceBox, endpointOffsets.sourceOffset ?? 0);
|
|
2666
|
+
const targetAnchor = anchor(raw[raw.length - 1], raw[raw.length - 2], targetFloat, targetBox, endpointOffsets.targetOffset ?? 0);
|
|
2667
|
+
raw[0] = sourceAnchor;
|
|
2668
|
+
raw[raw.length - 1] = targetAnchor;
|
|
2669
|
+
const points = orthogonalRound(raw);
|
|
2670
|
+
points[0] = { ...sourceAnchor };
|
|
2671
|
+
points[points.length - 1] = { ...targetAnchor };
|
|
2672
|
+
restoreEndpointSegment(points, 0, 1);
|
|
2673
|
+
restoreEndpointSegment(points, points.length - 1, -1);
|
|
2674
|
+
nudgeRouteEndpoint(points, sourceBox, 0, 1, 0);
|
|
2675
|
+
nudgeRouteEndpoint(points, targetBox, points.length - 1, -1, 0);
|
|
2676
|
+
simplifyRoute(points);
|
|
2677
|
+
const allowed = allowedBoxes(context, sourceBox.id, targetBox.id);
|
|
2678
|
+
if (routeBlocked(points, context.__boxById, allowed, occupied, sourceBox.id, targetBox.id, arrowStart, arrowEnd)) {
|
|
2679
|
+
const repaired = gridRepair(points[0], points[points.length - 1], context, sourceBox, targetBox, occupied, arrowStart, arrowEnd);
|
|
2680
|
+
if (!repaired) invalid(`Integer grid routing collided while placing edge ${edge.id}.`, "LAYOUT_ROUTE_COLLISION");
|
|
2681
|
+
return repaired;
|
|
2682
|
+
}
|
|
2683
|
+
return points;
|
|
2684
|
+
}
|
|
2685
|
+
function restoreEndpointSegment(points, index, neighborStep) {
|
|
2686
|
+
const point = points[index];
|
|
2687
|
+
const neighbor = points[index + neighborStep];
|
|
2688
|
+
if (!point || !neighbor || point.x === neighbor.x || point.y === neighbor.y) return;
|
|
2689
|
+
if (Math.abs(neighbor.x - point.x) >= Math.abs(neighbor.y - point.y)) neighbor.y = point.y;
|
|
2690
|
+
else neighbor.x = point.x;
|
|
2691
|
+
}
|
|
2692
|
+
function selfLoopRoute(box, rank, count) {
|
|
2693
|
+
const side = rank % 4;
|
|
2694
|
+
const ring = Math.floor(rank / 4) + 2;
|
|
2695
|
+
const left = box.x;
|
|
2696
|
+
const right = box.x + box.width - 1;
|
|
2697
|
+
const top = box.y;
|
|
2698
|
+
const bottom = box.y + box.height - 1;
|
|
2699
|
+
if (side === 0) {
|
|
2700
|
+
const x = left - ring;
|
|
2701
|
+
return [{ x: left, y: top + 1 }, { x, y: top + 1 }, { x, y: bottom - 1 }, { x: left, y: bottom - 1 }];
|
|
2702
|
+
}
|
|
2703
|
+
if (side === 1) {
|
|
2704
|
+
const x = right + ring;
|
|
2705
|
+
return [{ x: right, y: bottom - 1 }, { x, y: bottom - 1 }, { x, y: top + 1 }, { x: right, y: top + 1 }];
|
|
2706
|
+
}
|
|
2707
|
+
if (side === 2) {
|
|
2708
|
+
const y2 = top - ring;
|
|
2709
|
+
return [{ x: left + 1, y: top }, { x: left + 1, y: y2 }, { x: right - 1, y: y2 }, { x: right - 1, y: top }];
|
|
2710
|
+
}
|
|
2711
|
+
const y = bottom + ring;
|
|
2712
|
+
return [{ x: right - 1, y: bottom }, { x: right - 1, y }, { x: left + 1, y }, { x: left + 1, y: bottom }];
|
|
2713
|
+
}
|
|
2714
|
+
function nudgeRouteEndpoint(points, box, index, neighborStep, offset) {
|
|
2715
|
+
if (!offset || points.length < 2) return;
|
|
2716
|
+
const point = points[index];
|
|
2717
|
+
const neighbor = points[index + neighborStep];
|
|
2718
|
+
if (!neighbor) return;
|
|
2719
|
+
if (point.x === box.x || point.x === box.x + box.width - 1) {
|
|
2720
|
+
point.y = Math.max(box.y, Math.min(box.y + box.height - 1, point.y + offset));
|
|
2721
|
+
neighbor.y = point.y;
|
|
2722
|
+
} else if (point.y === box.y || point.y === box.y + box.height - 1) {
|
|
2723
|
+
point.x = Math.max(box.x, Math.min(box.x + box.width - 1, point.x + offset));
|
|
2724
|
+
neighbor.x = point.x;
|
|
2725
|
+
}
|
|
2726
|
+
}
|
|
2727
|
+
function anchor(point, neighbor, floatBox, box, offset = 0) {
|
|
2728
|
+
const left = floatBox?.x ?? box.x;
|
|
2729
|
+
const right = left + (floatBox?.width ?? box.width);
|
|
2730
|
+
const top = floatBox?.y ?? box.y;
|
|
2731
|
+
const bottom = top + (floatBox?.height ?? box.height);
|
|
2732
|
+
const distances = [{ side: "left", value: Math.abs(point.x - left) }, { side: "right", value: Math.abs(point.x - right) }, { side: "top", value: Math.abs(point.y - top) }, { side: "bottom", value: Math.abs(point.y - bottom) }];
|
|
2733
|
+
distances.sort((a, b) => a.value - b.value);
|
|
2734
|
+
const side = distances[0].side;
|
|
2735
|
+
if (side === "left" || side === "right") {
|
|
2736
|
+
const center2 = box.y + Math.floor((box.height - 1) / 2);
|
|
2737
|
+
const y = Math.max(box.y, Math.min(box.y + box.height - 1, center2 + offset));
|
|
2738
|
+
return { x: side === "left" ? box.x : box.x + box.width - 1, y };
|
|
2739
|
+
}
|
|
2740
|
+
const center = box.x + Math.floor((box.width - 1) / 2);
|
|
2741
|
+
const x = Math.max(box.x, Math.min(box.x + box.width - 1, center + offset));
|
|
2742
|
+
return { x, y: side === "top" ? box.y : box.y + box.height - 1 };
|
|
2743
|
+
}
|
|
2744
|
+
function orthogonalRound(raw) {
|
|
2745
|
+
const result = [{ x: Math.round(raw[0].x), y: Math.round(raw[0].y) }];
|
|
2746
|
+
for (let i = 1; i < raw.length; i += 1) {
|
|
2747
|
+
const current = { x: Math.round(raw[i].x), y: Math.round(raw[i].y) };
|
|
2748
|
+
const previous = result[result.length - 1];
|
|
2749
|
+
if (current.x === previous.x || current.y === previous.y) {
|
|
2750
|
+
result.push(current);
|
|
2751
|
+
continue;
|
|
2752
|
+
}
|
|
2753
|
+
if (Math.abs(current.x - previous.x) >= Math.abs(current.y - previous.y)) {
|
|
2754
|
+
result.push({ x: current.x, y: previous.y });
|
|
2755
|
+
} else {
|
|
2756
|
+
result.push({ x: previous.x, y: current.y });
|
|
2757
|
+
}
|
|
2758
|
+
result.push(current);
|
|
2759
|
+
}
|
|
2760
|
+
return result;
|
|
2761
|
+
}
|
|
2762
|
+
function simplifyRoute(points) {
|
|
2763
|
+
for (let i = points.length - 2; i > 0; i -= 1) {
|
|
2764
|
+
const a = points[i - 1];
|
|
2765
|
+
const b = points[i];
|
|
2766
|
+
const c = points[i + 1];
|
|
2767
|
+
if (a.x === b.x && b.x === c.x || a.y === b.y && b.y === c.y) points.splice(i, 1);
|
|
2768
|
+
}
|
|
2769
|
+
return points;
|
|
2770
|
+
}
|
|
2771
|
+
function allowedBoxes(context, sourceId, targetId) {
|
|
2772
|
+
const allowed = /* @__PURE__ */ new Set([sourceId, targetId]);
|
|
2773
|
+
for (const id of context.element.keys()) {
|
|
2774
|
+
if (isAncestor(context, id, sourceId) || isAncestor(context, id, targetId)) allowed.add(id);
|
|
2775
|
+
}
|
|
2776
|
+
return allowed;
|
|
2777
|
+
}
|
|
2778
|
+
function isAncestor(context, candidate, id) {
|
|
2779
|
+
let current = context.parent.get(id);
|
|
2780
|
+
while (current !== void 0) {
|
|
2781
|
+
if (current === candidate) return true;
|
|
2782
|
+
current = context.parent.get(current);
|
|
2783
|
+
}
|
|
2784
|
+
return false;
|
|
2785
|
+
}
|
|
2786
|
+
function routeBlocked(points, boxes, allowed, occupied, sourceId, targetId, arrowStart = "none", arrowEnd = "none") {
|
|
2787
|
+
const pair = pairKey(sourceId, targetId);
|
|
2788
|
+
const arrowCells = routeArrowKeys(points, arrowStart, arrowEnd);
|
|
2789
|
+
for (let i = 1; i < points.length; i += 1) {
|
|
2790
|
+
const orientation = points[i - 1].x === points[i].x ? "v" : "h";
|
|
2791
|
+
for (const cell of segmentCells2(points[i - 1], points[i])) {
|
|
2792
|
+
const existing = occupied.get(key2(cell.x, cell.y));
|
|
2793
|
+
if (existing?.arrow || existing && arrowCells.has(key2(cell.x, cell.y)) || existing?.orientations.has(orientation)) return true;
|
|
2794
|
+
for (const [id, box] of boxes) {
|
|
2795
|
+
if (!box || !inside(cell, box) && !(box.kind === "node" && !allowed.has(id) && insideExpanded(cell, box, 1))) continue;
|
|
2796
|
+
if (box.kind === "subgraph" && headerCell(cell, box)) return true;
|
|
2797
|
+
if (box.kind === "node" && allowed.has(id)) {
|
|
2798
|
+
const endpoint = key2(cell.x, cell.y) === key2(points[0].x, points[0].y) || key2(cell.x, cell.y) === key2(points.at(-1).x, points.at(-1).y);
|
|
2799
|
+
if (!endpoint) return true;
|
|
2800
|
+
} else if (!allowed.has(id)) return true;
|
|
2801
|
+
}
|
|
2802
|
+
}
|
|
2803
|
+
}
|
|
2804
|
+
return false;
|
|
2805
|
+
}
|
|
2806
|
+
function gridRepair(start, end, context, sourceBox, targetBox, occupied, arrowStart = "none", arrowEnd = "none") {
|
|
2807
|
+
const boxes = context.__boxById;
|
|
2808
|
+
if (!boxes) return null;
|
|
2809
|
+
const sourceId = sourceBox.id;
|
|
2810
|
+
const targetId = targetBox.id;
|
|
2811
|
+
const pair = pairKey(sourceId, targetId);
|
|
2812
|
+
const allowed = allowedBoxes(context, sourceId, targetId);
|
|
2813
|
+
const directions = [[1, 0], [-1, 0], [0, 1], [0, -1]];
|
|
2814
|
+
const all = [...boxes.values()];
|
|
2815
|
+
const starts = endpointCandidates(sourceBox, start);
|
|
2816
|
+
const ends = endpointCandidates(targetBox, end);
|
|
2817
|
+
for (const candidateStart of starts) for (const candidateEnd of ends) {
|
|
2818
|
+
if (candidateStart.x === candidateEnd.x && candidateStart.y === candidateEnd.y && sourceId !== targetId) continue;
|
|
2819
|
+
const startPoint = candidateStart;
|
|
2820
|
+
const endPoint = candidateEnd;
|
|
2821
|
+
for (const margin of [8, 16, 32, 64]) {
|
|
2822
|
+
const minX = Math.min(startPoint.x, endPoint.x, ...all.map((b) => b.x)) - margin;
|
|
2823
|
+
const maxX = Math.max(startPoint.x, endPoint.x, ...all.map((b) => b.x + b.width - 1)) + margin;
|
|
2824
|
+
const minY = Math.min(startPoint.y, endPoint.y, ...all.map((b) => b.y)) - margin;
|
|
2825
|
+
const maxY = Math.max(startPoint.y, endPoint.y, ...all.map((b) => b.y + b.height - 1)) + margin;
|
|
2826
|
+
const queue = [startPoint];
|
|
2827
|
+
const previous = /* @__PURE__ */ new Map([[key2(startPoint.x, startPoint.y), null]]);
|
|
2828
|
+
const currentArrows = endpointArrowNeighborhood(startPoint, endPoint, arrowStart, arrowEnd);
|
|
2829
|
+
const blocked = (x, y, orientation) => {
|
|
2830
|
+
const cell = { x, y };
|
|
2831
|
+
const existing = occupied.get(key2(x, y));
|
|
2832
|
+
if (existing?.arrow || existing && currentArrows.has(key2(x, y)) || existing?.orientations.has(orientation)) return true;
|
|
2833
|
+
for (const [id, box] of boxes) {
|
|
2834
|
+
if (!inside(cell, box) && !(box.kind === "node" && !allowed.has(id) && insideExpanded(cell, box, 1))) continue;
|
|
2835
|
+
if (box.kind === "subgraph" && headerCell(cell, box)) return true;
|
|
2836
|
+
if (box.kind === "node" && allowed.has(id)) {
|
|
2837
|
+
if (!(x === startPoint.x && y === startPoint.y) && !(x === endPoint.x && y === endPoint.y)) return true;
|
|
2838
|
+
} else if (!allowed.has(id)) return true;
|
|
2839
|
+
}
|
|
2840
|
+
return false;
|
|
2841
|
+
};
|
|
2842
|
+
let head = 0;
|
|
2843
|
+
while (head < queue.length) {
|
|
2844
|
+
const current = queue[head++];
|
|
2845
|
+
if (current.x === endPoint.x && current.y === endPoint.y) {
|
|
2846
|
+
const path = [];
|
|
2847
|
+
let cursor = current;
|
|
2848
|
+
while (cursor) {
|
|
2849
|
+
path.push(cursor);
|
|
2850
|
+
cursor = previous.get(key2(cursor.x, cursor.y));
|
|
2851
|
+
}
|
|
2852
|
+
path.reverse();
|
|
2853
|
+
return compress(path);
|
|
2854
|
+
}
|
|
2855
|
+
for (const [dx, dy] of directions) {
|
|
2856
|
+
const x = current.x + dx;
|
|
2857
|
+
const y = current.y + dy;
|
|
2858
|
+
if (x < minX || x > maxX || y < minY || y > maxY || blocked(x, y, dx ? "h" : "v")) continue;
|
|
2859
|
+
const k = key2(x, y);
|
|
2860
|
+
if (previous.has(k)) continue;
|
|
2861
|
+
previous.set(k, current);
|
|
2862
|
+
queue.push({ x, y });
|
|
2863
|
+
}
|
|
2864
|
+
}
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
return null;
|
|
2868
|
+
}
|
|
2869
|
+
function endpointCandidates(box, preferred) {
|
|
2870
|
+
const points = [];
|
|
2871
|
+
for (let y = box.y; y < box.y + box.height; y += 1) {
|
|
2872
|
+
for (let x = box.x; x < box.x + box.width; x += 1) {
|
|
2873
|
+
if (x !== box.x && x !== box.x + box.width - 1 && y !== box.y && y !== box.y + box.height - 1) continue;
|
|
2874
|
+
points.push({ x, y });
|
|
2875
|
+
}
|
|
2876
|
+
}
|
|
2877
|
+
points.sort((a, b) => Math.abs(a.x - preferred.x) + Math.abs(a.y - preferred.y) - (Math.abs(b.x - preferred.x) + Math.abs(b.y - preferred.y)) || a.y - b.y || a.x - b.x);
|
|
2878
|
+
return points.slice(0, 32);
|
|
2879
|
+
}
|
|
2880
|
+
function endpointArrowNeighborhood(start, end, arrowStart, arrowEnd) {
|
|
2881
|
+
const cells = /* @__PURE__ */ new Set();
|
|
2882
|
+
const add = (point) => {
|
|
2883
|
+
for (const [dx, dy] of [[1, 0], [-1, 0], [0, 1], [0, -1]]) cells.add(key2(point.x + dx, point.y + dy));
|
|
2884
|
+
};
|
|
2885
|
+
if (arrowStart !== "none" && arrowStart !== void 0) add(start);
|
|
2886
|
+
if (arrowEnd !== "none" && arrowEnd !== void 0) add(end);
|
|
2887
|
+
return cells;
|
|
2888
|
+
}
|
|
2889
|
+
function headerCell(point, box) {
|
|
2890
|
+
if (box.kind !== "subgraph" || point.y < box.y + 1 || point.y >= box.y + 1 + box.lines.length) return false;
|
|
2891
|
+
const line = box.lines[point.y - box.y - 1] ?? "";
|
|
2892
|
+
const left = box.x + 1 + Math.floor((Math.max(0, box.width - 2) - displayWidth(line)) / 2);
|
|
2893
|
+
return point.x >= left && point.x < left + displayWidth(line);
|
|
2894
|
+
}
|
|
2895
|
+
function compress(points) {
|
|
2896
|
+
if (points.length < 2) return points;
|
|
2897
|
+
const result = [points[0]];
|
|
2898
|
+
let dx = points[1].x - points[0].x;
|
|
2899
|
+
let dy = points[1].y - points[0].y;
|
|
2900
|
+
for (let i = 1; i < points.length - 1; i += 1) {
|
|
2901
|
+
const ndx = points[i + 1].x - points[i].x;
|
|
2902
|
+
const ndy = points[i + 1].y - points[i].y;
|
|
2903
|
+
if (dx === 0 !== (ndx === 0)) result.push(points[i]);
|
|
2904
|
+
dx = ndx;
|
|
2905
|
+
dy = ndy;
|
|
2906
|
+
}
|
|
2907
|
+
result.push(points[points.length - 1]);
|
|
2908
|
+
return result;
|
|
2909
|
+
}
|
|
2910
|
+
function addRouteToOccupied(occupied, points, edge, boxes) {
|
|
2911
|
+
const sourceId = edge.source;
|
|
2912
|
+
const targetId = edge.target;
|
|
2913
|
+
for (let i = 1; i < points.length; i += 1) {
|
|
2914
|
+
const orientation = points[i - 1].x === points[i].x ? "v" : "h";
|
|
2915
|
+
for (const cell of segmentCells2(points[i - 1], points[i])) {
|
|
2916
|
+
if (inside(cell, boxes.get(sourceId)) && cell !== points[0] || inside(cell, boxes.get(targetId)) && cell !== points.at(-1)) continue;
|
|
2917
|
+
const cellKey = key2(cell.x, cell.y);
|
|
2918
|
+
if (!occupied.has(cellKey)) occupied.set(cellKey, { orientations: /* @__PURE__ */ new Set(), pairs: /* @__PURE__ */ new Set() });
|
|
2919
|
+
const entry = occupied.get(cellKey);
|
|
2920
|
+
entry.orientations.add(orientation);
|
|
2921
|
+
entry.pairs.add(pairKey(sourceId, targetId));
|
|
2922
|
+
if (!entry.sources) entry.sources = /* @__PURE__ */ new Set();
|
|
2923
|
+
entry.sources.add(sourceId);
|
|
2924
|
+
}
|
|
2925
|
+
}
|
|
2926
|
+
markArrowOccupancy(occupied, points, edge.arrowStart, edge.arrowEnd);
|
|
2927
|
+
}
|
|
2928
|
+
function markArrowOccupancy(occupied, points, arrowStart, arrowEnd) {
|
|
2929
|
+
const first = distinctRoutePair(points, true);
|
|
2930
|
+
const last = distinctRoutePair(points, false);
|
|
2931
|
+
for (const pair of [arrowStart !== "none" && arrowStart !== void 0 ? first : null, arrowEnd !== "none" && arrowEnd !== void 0 ? last : null]) {
|
|
2932
|
+
if (!pair) continue;
|
|
2933
|
+
const cell = key2(pair.next.x, pair.next.y);
|
|
2934
|
+
if (!occupied.has(cell)) occupied.set(cell, { orientations: /* @__PURE__ */ new Set(), pairs: /* @__PURE__ */ new Set(), sources: /* @__PURE__ */ new Set() });
|
|
2935
|
+
occupied.get(cell).arrow = true;
|
|
2936
|
+
}
|
|
2937
|
+
}
|
|
2938
|
+
function distinctRoutePair(points, start) {
|
|
2939
|
+
if (start) {
|
|
2940
|
+
for (let i = 1; i < points.length; i += 1) if (points[i].x !== points[0].x || points[i].y !== points[0].y) return { next: oneStep2(points[0], points[i]) };
|
|
2941
|
+
} else {
|
|
2942
|
+
for (let i = points.length - 2; i >= 0; i -= 1) if (points[i].x !== points.at(-1).x || points[i].y !== points.at(-1).y) return { next: oneStep2(points.at(-1), points[i]) };
|
|
2943
|
+
}
|
|
2944
|
+
return null;
|
|
2945
|
+
}
|
|
2946
|
+
function oneStep2(end, toward) {
|
|
2947
|
+
const dx = toward.x - end.x;
|
|
2948
|
+
const dy = toward.y - end.y;
|
|
2949
|
+
return Math.abs(dx) >= Math.abs(dy) ? { x: end.x + Math.sign(dx), y: end.y } : { x: end.x, y: end.y + Math.sign(dy) };
|
|
2950
|
+
}
|
|
2951
|
+
function routeArrowKeys(points, arrowStart = "none", arrowEnd = "none") {
|
|
2952
|
+
const keys = /* @__PURE__ */ new Set();
|
|
2953
|
+
const first = distinctRoutePair(points, true);
|
|
2954
|
+
const last = distinctRoutePair(points, false);
|
|
2955
|
+
if (arrowStart !== "none" && arrowStart !== void 0 && first) keys.add(key2(first.next.x, first.next.y));
|
|
2956
|
+
if (arrowEnd !== "none" && arrowEnd !== void 0 && last) keys.add(key2(last.next.x, last.next.y));
|
|
2957
|
+
return keys;
|
|
2958
|
+
}
|
|
2959
|
+
function segmentCells2(a, b) {
|
|
2960
|
+
if (a.x !== b.x && a.y !== b.y) {
|
|
2961
|
+
throw new FlowInkError(`Non-orthogonal segment from (${a.x},${a.y}) to (${b.x},${b.y}).`, { code: "NON_ORTHOGONAL_EDGE" });
|
|
2962
|
+
}
|
|
2963
|
+
const cells = [];
|
|
2964
|
+
const dx = Math.sign(b.x - a.x);
|
|
2965
|
+
const dy = Math.sign(b.y - a.y);
|
|
2966
|
+
let x = a.x;
|
|
2967
|
+
let y = a.y;
|
|
2968
|
+
cells.push({ x, y });
|
|
2969
|
+
while (x !== b.x || y !== b.y) {
|
|
2970
|
+
x += dx;
|
|
2971
|
+
y += dy;
|
|
2972
|
+
cells.push({ x, y });
|
|
2973
|
+
}
|
|
2974
|
+
return cells;
|
|
2975
|
+
}
|
|
2976
|
+
function inside(point, box) {
|
|
2977
|
+
return box && point.x >= box.x && point.x < box.x + box.width && point.y >= box.y && point.y < box.y + box.height;
|
|
2978
|
+
}
|
|
2979
|
+
function insideExpanded(point, box, margin) {
|
|
2980
|
+
return point.x >= box.x - margin && point.x <= box.x + box.width - 1 + margin && point.y >= box.y - margin && point.y <= box.y + box.height - 1 + margin;
|
|
2981
|
+
}
|
|
2982
|
+
function edgeLabel(output, edge, route, sourceBox, boxes, placedLabels, routes) {
|
|
2983
|
+
const source = output.labels?.[0];
|
|
2984
|
+
const lines = labelLines(edge.label, edge.labelType).map(String);
|
|
2985
|
+
const width = Math.max(1, Math.ceil(source?.width ?? maxWidth(lines, edge.label)));
|
|
2986
|
+
const height = Math.max(1, Math.ceil(source?.height ?? lines.length));
|
|
2987
|
+
let best = [route[0], route[1]];
|
|
2988
|
+
let bestLength = -1;
|
|
2989
|
+
for (let i = 1; i < route.length; i += 1) {
|
|
2990
|
+
const length = Math.abs(route[i].x - route[i - 1].x) + Math.abs(route[i].y - route[i - 1].y);
|
|
2991
|
+
if (length > bestLength) {
|
|
2992
|
+
best = [route[i - 1], route[i]];
|
|
2993
|
+
bestLength = length;
|
|
2994
|
+
}
|
|
2995
|
+
}
|
|
2996
|
+
const [a, b] = best;
|
|
2997
|
+
const midX = Math.floor((a.x + b.x) / 2);
|
|
2998
|
+
const midY = Math.floor((a.y + b.y) / 2);
|
|
2999
|
+
if (edge.source === edge.target && sourceBox) {
|
|
3000
|
+
const routeMinX = Math.min(...route.map((point) => point.x));
|
|
3001
|
+
const routeMaxX = Math.max(...route.map((point) => point.x));
|
|
3002
|
+
const leftOfBox = routeMinX < sourceBox.x;
|
|
3003
|
+
const y = Math.max(0, midY - Math.floor(height / 2));
|
|
3004
|
+
const candidates2 = [
|
|
3005
|
+
{ x: leftOfBox ? routeMinX - width - 1 : routeMaxX + 2, y },
|
|
3006
|
+
{ x: leftOfBox ? routeMaxX + 2 : routeMinX - width - 1, y: y + height + 1 }
|
|
3007
|
+
];
|
|
3008
|
+
for (const candidate of candidates2) {
|
|
3009
|
+
if (candidate.x < 0 || labelCollides(candidate, width, height, route, boxes, placedLabels, routes)) continue;
|
|
3010
|
+
return { ...candidate, lines, width, height };
|
|
3011
|
+
}
|
|
3012
|
+
return { x: Math.max(0, candidates2[0].x), y, lines, width, height };
|
|
3013
|
+
}
|
|
3014
|
+
const horizontal = b.y === a.y;
|
|
3015
|
+
const centeredX = midX - Math.floor(width / 2);
|
|
3016
|
+
const centeredY = midY - Math.floor(height / 2);
|
|
3017
|
+
const candidates = horizontal ? [{ x: centeredX, y: centeredY - height - 1 }, { x: centeredX, y: centeredY + height + 1 }] : [{ x: centeredX - width - 1, y: centeredY }, { x: centeredX + width + 1, y: centeredY }];
|
|
3018
|
+
candidates.push({ x: centeredX, y: centeredY });
|
|
3019
|
+
for (const candidate of candidates) {
|
|
3020
|
+
if (candidate.x < 0 || candidate.y < 0) continue;
|
|
3021
|
+
if (labelCollides(candidate, width, height, route, boxes, placedLabels, routes)) continue;
|
|
3022
|
+
return { ...candidate, lines, width, height };
|
|
3023
|
+
}
|
|
3024
|
+
return { x: Math.max(0, centeredX), y: Math.max(0, centeredY), lines, width, height };
|
|
3025
|
+
}
|
|
3026
|
+
function labelCollides(candidate, width, height, route, boxes, placedLabels, routes) {
|
|
3027
|
+
const routeCells = /* @__PURE__ */ new Set();
|
|
3028
|
+
for (const candidateRoute of routes.values()) {
|
|
3029
|
+
for (let i = 1; i < candidateRoute.length; i += 1) for (const cell of segmentCells2(candidateRoute[i - 1], candidateRoute[i])) routeCells.add(key2(cell.x, cell.y));
|
|
3030
|
+
}
|
|
3031
|
+
for (let y = candidate.y; y < candidate.y + height; y += 1) {
|
|
3032
|
+
for (let x = candidate.x; x < candidate.x + width; x += 1) {
|
|
3033
|
+
if (routeCells.has(key2(x, y))) return true;
|
|
3034
|
+
for (const box of boxes.values()) {
|
|
3035
|
+
if (inside({ x, y }, box)) return true;
|
|
3036
|
+
}
|
|
3037
|
+
}
|
|
3038
|
+
}
|
|
3039
|
+
for (const label of placedLabels) {
|
|
3040
|
+
if (candidate.x < label.x + label.width && label.x < candidate.x + width && candidate.y < label.y + label.height && label.y < candidate.y + height) return true;
|
|
3041
|
+
}
|
|
3042
|
+
return false;
|
|
3043
|
+
}
|
|
3044
|
+
function maxWidth(lines, fallback) {
|
|
3045
|
+
if (lines.length > 0) return Math.max(1, ...lines.map((line) => Number(displayWidth(line))));
|
|
3046
|
+
return Math.max(1, Number(displayWidth(String(fallback ?? ""))));
|
|
3047
|
+
}
|
|
3048
|
+
function positiveSize(value, fallback) {
|
|
3049
|
+
return Number.isFinite(value) && value > 0 ? Math.max(1, Math.ceil(value)) : Math.max(1, Math.ceil(fallback));
|
|
3050
|
+
}
|
|
3051
|
+
function elkSize(cells) {
|
|
3052
|
+
return Math.max(1, cells - 1);
|
|
3053
|
+
}
|
|
3054
|
+
function requireId(value, type) {
|
|
3055
|
+
if (!value || typeof value.id !== "string" || value.id.length === 0) invalid(`Every ${type} must have a non-empty string id.`);
|
|
3056
|
+
}
|
|
3057
|
+
function invalid(message, code = "INVALID_GRAPH") {
|
|
3058
|
+
throw new FlowInkError(message, { code });
|
|
3059
|
+
}
|
|
3060
|
+
function key2(x, y) {
|
|
3061
|
+
return `${x},${y}`;
|
|
3062
|
+
}
|
|
3063
|
+
function pairKey(source, target) {
|
|
3064
|
+
return `${source}\0${target}`;
|
|
3065
|
+
}
|
|
3066
|
+
|
|
3067
|
+
// src/rasterize.js
|
|
3068
|
+
function rasterize(layout2, options = {}) {
|
|
3069
|
+
const charset = options?.charset ?? "ascii";
|
|
3070
|
+
if (charset !== "ascii" && charset !== "unicode") {
|
|
3071
|
+
throw new FlowInkError('charset must be "ascii" or "unicode".', { code: "INVALID_OPTIONS" });
|
|
3072
|
+
}
|
|
3073
|
+
const checked = validateLayout(layout2);
|
|
3074
|
+
const { boxes, edges, labels, width, height } = checked;
|
|
3075
|
+
const grid = makeGrid(width, height);
|
|
3076
|
+
const interior = buildInteriorMap(boxes, width, height);
|
|
3077
|
+
const nodeBorders = buildNodeBorderMap(boxes, width, height);
|
|
3078
|
+
const boxBorders = buildBoxBorderMap(boxes, width, height);
|
|
3079
|
+
const endpointOwners = buildEndpointOwners(edges);
|
|
3080
|
+
for (const edge of edges) drawEdge(grid, edge, interior, nodeBorders, boxBorders, endpointOwners, labels, charset);
|
|
3081
|
+
for (const box of boxes) drawBox(grid, box, charset);
|
|
3082
|
+
for (const edge of edges) {
|
|
3083
|
+
if (edge.label) drawLabel(grid, edge.label, `edge ${edge.id}`, edge.id);
|
|
3084
|
+
}
|
|
3085
|
+
for (const edge of edges) drawArrows(grid, edge, boxes, charset);
|
|
3086
|
+
return stringifyGrid(grid);
|
|
3087
|
+
}
|
|
3088
|
+
function validateLayout(layout2) {
|
|
3089
|
+
if (!layout2 || typeof layout2 !== "object") fail2("Layout must be an object.", "INVALID_LAYOUT");
|
|
3090
|
+
if (!Array.isArray(layout2.boxes) || !Array.isArray(layout2.edges)) {
|
|
3091
|
+
fail2("Layout must contain boxes and edges arrays.", "INVALID_LAYOUT");
|
|
3092
|
+
}
|
|
3093
|
+
if (!Number.isInteger(layout2.width) || !Number.isInteger(layout2.height) || layout2.width < 0 || layout2.height < 0) {
|
|
3094
|
+
fail2("Layout width and height must be non-negative integers.", "INVALID_LAYOUT");
|
|
3095
|
+
}
|
|
3096
|
+
const boxIds = /* @__PURE__ */ new Set();
|
|
3097
|
+
const boxes = layout2.boxes.map((box, index) => {
|
|
3098
|
+
if (!box || typeof box !== "object") fail2(`Layout box ${index} is invalid.`, "INVALID_LAYOUT");
|
|
3099
|
+
if (typeof box.id !== "string" || boxIds.has(box.id)) fail2(`Layout box id is missing or duplicated: ${box.id ?? index}.`, "INVALID_LAYOUT");
|
|
3100
|
+
boxIds.add(box.id);
|
|
3101
|
+
for (const key3 of ["x", "y", "width", "height"]) {
|
|
3102
|
+
if (!Number.isInteger(box[key3])) fail2(`Layout box ${box.id} has a non-integer ${key3}.`, "INVALID_LAYOUT");
|
|
3103
|
+
}
|
|
3104
|
+
if (box.x < 0 || box.y < 0 || box.width < 1 || box.height < 1) fail2(`Layout box ${box.id} has invalid geometry.`, "INVALID_LAYOUT");
|
|
3105
|
+
if (!Array.isArray(box.lines)) fail2(`Layout box ${box.id} must provide lines.`, "INVALID_LAYOUT");
|
|
3106
|
+
if (box.lines.some((line) => typeof line !== "string")) fail2(`Layout box ${box.id} has a non-string label line.`, "INVALID_LAYOUT");
|
|
3107
|
+
return { ...box, shape: String(box.shape ?? "rect") };
|
|
3108
|
+
});
|
|
3109
|
+
for (let i = 0; i < boxes.length; i += 1) {
|
|
3110
|
+
for (let j = i + 1; j < boxes.length; j += 1) {
|
|
3111
|
+
if (partialBoxOverlap(boxes[i], boxes[j])) {
|
|
3112
|
+
fail2(`Layout boxes ${boxes[i].id} and ${boxes[j].id} overlap.`, "BOX_OVERLAP");
|
|
3113
|
+
}
|
|
3114
|
+
}
|
|
3115
|
+
}
|
|
3116
|
+
const edgeIds = /* @__PURE__ */ new Set();
|
|
3117
|
+
const edges = layout2.edges.map((edge, index) => {
|
|
3118
|
+
if (!edge || typeof edge !== "object") fail2(`Layout edge ${index} is invalid.`, "INVALID_LAYOUT");
|
|
3119
|
+
if (typeof edge.id !== "string" || edgeIds.has(edge.id)) fail2(`Layout edge id is missing or duplicated: ${edge.id ?? index}.`, "INVALID_LAYOUT");
|
|
3120
|
+
edgeIds.add(edge.id);
|
|
3121
|
+
if (!Array.isArray(edge.points) || edge.points.length < 1) fail2(`Layout edge ${edge.id} must have at least one point.`, "INVALID_LAYOUT");
|
|
3122
|
+
const points = edge.points.map((point, pointIndex) => {
|
|
3123
|
+
if (!point || !Number.isInteger(point.x) || !Number.isInteger(point.y) || point.x < 0 || point.y < 0) {
|
|
3124
|
+
fail2(`Layout edge ${edge.id} has an invalid point at ${pointIndex}.`, "INVALID_LAYOUT");
|
|
3125
|
+
}
|
|
3126
|
+
return { x: point.x, y: point.y };
|
|
3127
|
+
});
|
|
3128
|
+
for (let i = 1; i < points.length; i += 1) {
|
|
3129
|
+
if (points[i - 1].x !== points[i].x && points[i - 1].y !== points[i].y) {
|
|
3130
|
+
fail2(`Layout edge ${edge.id} is not orthogonal.`, "NON_ORTHOGONAL_EDGE");
|
|
3131
|
+
}
|
|
3132
|
+
}
|
|
3133
|
+
for (const arrow of [edge.arrowStart, edge.arrowEnd].filter((value) => value !== void 0)) {
|
|
3134
|
+
if (!["none", "point", "circle", "cross"].includes(arrow)) fail2(`Layout edge ${edge.id} has an invalid arrow type.`, "INVALID_LAYOUT");
|
|
3135
|
+
}
|
|
3136
|
+
if (edge.stroke !== void 0 && !["normal", "thick", "dotted", "invisible"].includes(edge.stroke)) {
|
|
3137
|
+
fail2(`Layout edge ${edge.id} has an invalid stroke.`, "INVALID_LAYOUT");
|
|
3138
|
+
}
|
|
3139
|
+
return {
|
|
3140
|
+
...edge,
|
|
3141
|
+
points,
|
|
3142
|
+
arrowStart: edge.arrowStart ?? "none",
|
|
3143
|
+
arrowEnd: edge.arrowEnd ?? "none",
|
|
3144
|
+
stroke: edge.stroke ?? "normal"
|
|
3145
|
+
};
|
|
3146
|
+
});
|
|
3147
|
+
const labels = [];
|
|
3148
|
+
for (const edge of edges) {
|
|
3149
|
+
if (!edge.label) continue;
|
|
3150
|
+
const label = normalizeLabel2(edge.label, `edge ${edge.id}`);
|
|
3151
|
+
labels.push(label);
|
|
3152
|
+
}
|
|
3153
|
+
let width = layout2.width;
|
|
3154
|
+
let height = layout2.height;
|
|
3155
|
+
for (const box of boxes) {
|
|
3156
|
+
width = Math.max(width, box.x + box.width);
|
|
3157
|
+
height = Math.max(height, box.y + box.height);
|
|
3158
|
+
}
|
|
3159
|
+
for (const edge of edges) for (const point of edge.points) {
|
|
3160
|
+
width = Math.max(width, point.x + 1);
|
|
3161
|
+
height = Math.max(height, point.y + 1);
|
|
3162
|
+
}
|
|
3163
|
+
for (const label of labels) {
|
|
3164
|
+
width = Math.max(width, label.x + label.width);
|
|
3165
|
+
height = Math.max(height, label.y + label.height);
|
|
3166
|
+
}
|
|
3167
|
+
return { boxes, edges, labels, width, height };
|
|
3168
|
+
}
|
|
3169
|
+
function normalizeLabel2(label, owner) {
|
|
3170
|
+
if (!label || !Number.isInteger(label.x) || !Number.isInteger(label.y) || label.x < 0 || label.y < 0 || !Array.isArray(label.lines)) {
|
|
3171
|
+
fail2(`Label for ${owner} is invalid.`, "INVALID_LAYOUT");
|
|
3172
|
+
}
|
|
3173
|
+
if (label.lines.some((line) => typeof line !== "string")) fail2(`Label for ${owner} has a non-string line.`, "INVALID_LAYOUT");
|
|
3174
|
+
const measured = Math.max(0, ...label.lines.map((line) => displayWidth(line)));
|
|
3175
|
+
const width = Number.isInteger(label.width) && label.width >= measured ? label.width : measured;
|
|
3176
|
+
const height = Number.isInteger(label.height) && label.height >= label.lines.length ? label.height : label.lines.length;
|
|
3177
|
+
return { ...label, width, height };
|
|
3178
|
+
}
|
|
3179
|
+
function partialBoxOverlap(a, b) {
|
|
3180
|
+
const overlap = a.x < b.x + b.width && b.x < a.x + a.width && a.y < b.y + b.height && b.y < a.y + a.height;
|
|
3181
|
+
if (!overlap) return false;
|
|
3182
|
+
const contains = (outer, inner) => outer.kind === "subgraph" && outer.x <= inner.x && outer.y <= inner.y && outer.x + outer.width >= inner.x + inner.width && outer.y + outer.height >= inner.y + inner.height;
|
|
3183
|
+
return !contains(a, b) && !contains(b, a);
|
|
3184
|
+
}
|
|
3185
|
+
function makeGrid(width, height) {
|
|
3186
|
+
return Array.from({ length: height }, () => Array.from({ length: width }, () => ({ glyph: " ", kind: "empty", wide: false, edge: null })));
|
|
3187
|
+
}
|
|
3188
|
+
function buildInteriorMap(boxes, width, height) {
|
|
3189
|
+
const map = /* @__PURE__ */ new Map();
|
|
3190
|
+
const add = (x, y, box) => {
|
|
3191
|
+
if (x < 0 || y < 0 || x >= width || y >= height) return;
|
|
3192
|
+
const key3 = `${x},${y}`;
|
|
3193
|
+
const old = map.get(key3);
|
|
3194
|
+
if (old && old !== box.id) fail2(`Nested box interiors overlap at (${x},${y}).`, "BOX_OVERLAP");
|
|
3195
|
+
map.set(key3, box.id);
|
|
3196
|
+
};
|
|
3197
|
+
for (const box of boxes) {
|
|
3198
|
+
if (box.kind === "subgraph") continue;
|
|
3199
|
+
for (let y = box.y + 1; y < box.y + box.height - 1; y += 1) {
|
|
3200
|
+
for (let x = box.x + 1; x < box.x + box.width - 1; x += 1) add(x, y, box);
|
|
3201
|
+
}
|
|
3202
|
+
}
|
|
3203
|
+
return map;
|
|
3204
|
+
}
|
|
3205
|
+
function buildNodeBorderMap(boxes, width, height) {
|
|
3206
|
+
const map = /* @__PURE__ */ new Map();
|
|
3207
|
+
for (const box of boxes) {
|
|
3208
|
+
if (box.kind === "subgraph") continue;
|
|
3209
|
+
for (const { x, y } of boxBorderCells(box, "ascii")) {
|
|
3210
|
+
if (x >= 0 && y >= 0 && x < width && y < height) map.set(`${x},${y}`, box.id);
|
|
3211
|
+
}
|
|
3212
|
+
}
|
|
3213
|
+
return map;
|
|
3214
|
+
}
|
|
3215
|
+
function buildBoxBorderMap(boxes, width, height) {
|
|
3216
|
+
const map = /* @__PURE__ */ new Map();
|
|
3217
|
+
for (const box of boxes) {
|
|
3218
|
+
for (const { x, y } of boxBorderCells(box, "ascii")) {
|
|
3219
|
+
if (x >= 0 && y >= 0 && x < width && y < height) map.set(`${x},${y}`, box.id);
|
|
3220
|
+
}
|
|
3221
|
+
}
|
|
3222
|
+
return map;
|
|
3223
|
+
}
|
|
3224
|
+
function buildEndpointOwners(edges) {
|
|
3225
|
+
const map = /* @__PURE__ */ new Map();
|
|
3226
|
+
for (const edge of edges) {
|
|
3227
|
+
for (const point of [edge.points[0], edge.points.at(-1)]) {
|
|
3228
|
+
const key3 = `${point.x},${point.y}`;
|
|
3229
|
+
if (!map.has(key3)) map.set(key3, /* @__PURE__ */ new Set());
|
|
3230
|
+
map.get(key3).add(edge.id);
|
|
3231
|
+
}
|
|
3232
|
+
}
|
|
3233
|
+
return map;
|
|
3234
|
+
}
|
|
3235
|
+
function drawEdge(grid, edge, interior, nodeBorders, boxBorders, endpointOwners, labels, charset) {
|
|
3236
|
+
if (edge.stroke === "invisible") return;
|
|
3237
|
+
const points = edge.points;
|
|
3238
|
+
const endpoints = /* @__PURE__ */ new Set([`${points[0].x},${points[0].y}`, `${points[points.length - 1].x},${points[points.length - 1].y}`]);
|
|
3239
|
+
const legitimateSelfLoop = points[0].x === points.at(-1).x && points[0].y === points.at(-1).y && boxBorders.has(`${points[0].x},${points[0].y}`);
|
|
3240
|
+
const cells = /* @__PURE__ */ new Map();
|
|
3241
|
+
const add = (x, y, directions, segmentIndex = -1) => {
|
|
3242
|
+
const cell = grid[y]?.[x];
|
|
3243
|
+
if (!cell) fail2(`Edge ${edge.id} lies outside the layout.`, "LAYOUT_CLIP");
|
|
3244
|
+
if (interior.has(`${x},${y}`)) fail2(`Edge ${edge.id} passes through a box interior at (${x},${y}).`, "EDGE_BOX_COLLISION");
|
|
3245
|
+
if (nodeBorders.has(`${x},${y}`) && !endpoints.has(`${x},${y}`)) fail2(`Edge ${edge.id} crosses a non-endpoint node border at (${x},${y}).`, "EDGE_BOX_COLLISION");
|
|
3246
|
+
const key3 = `${x},${y}`;
|
|
3247
|
+
let route = cells.get(key3);
|
|
3248
|
+
if (!route) {
|
|
3249
|
+
route = { dirs: /* @__PURE__ */ new Set(), edgeIds: /* @__PURE__ */ new Set(), stroke: edge.stroke, segmentIndices: /* @__PURE__ */ new Set() };
|
|
3250
|
+
cells.set(key3, route);
|
|
3251
|
+
}
|
|
3252
|
+
for (const direction of directions) route.dirs.add(direction);
|
|
3253
|
+
route.edgeIds.add(edge.id);
|
|
3254
|
+
route.segmentIndices.add(segmentIndex);
|
|
3255
|
+
if (strokeRank(edge.stroke) > strokeRank(route.stroke)) route.stroke = edge.stroke;
|
|
3256
|
+
};
|
|
3257
|
+
if (points.length === 1) add(points[0].x, points[0].y, []);
|
|
3258
|
+
for (let i = 1; i < points.length; i += 1) {
|
|
3259
|
+
const a = points[i - 1];
|
|
3260
|
+
const b = points[i];
|
|
3261
|
+
const dx = Math.sign(b.x - a.x);
|
|
3262
|
+
const dy = Math.sign(b.y - a.y);
|
|
3263
|
+
const direction = dx ? dx > 0 ? "right" : "left" : dy > 0 ? "down" : "up";
|
|
3264
|
+
const reverse = opposite(direction);
|
|
3265
|
+
const count = Math.max(Math.abs(b.x - a.x), Math.abs(b.y - a.y));
|
|
3266
|
+
for (let step = 0; step <= count; step += 1) {
|
|
3267
|
+
const x = a.x + dx * step;
|
|
3268
|
+
const y = a.y + dy * step;
|
|
3269
|
+
add(x, y, step === 0 ? [direction] : step === count ? [reverse] : [direction, reverse], i - 1);
|
|
3270
|
+
}
|
|
3271
|
+
}
|
|
3272
|
+
for (const [key3, route] of cells) {
|
|
3273
|
+
const segments = [...route.segmentIndices].filter((index) => index >= 0).sort((a, b) => a - b);
|
|
3274
|
+
const endpointBorder = endpointOwners.get(key3)?.has(edge.id) && boxBorders.has(key3);
|
|
3275
|
+
if (segments.length > 1 && segments.at(-1) - segments[0] > 1 && !endpointBorder && !legitimateSelfLoop) {
|
|
3276
|
+
fail2(`Edge ${edge.id} crosses itself at (${key3.replace(",", ",")}).`, "ROUTE_COLLISION");
|
|
3277
|
+
}
|
|
3278
|
+
}
|
|
3279
|
+
for (const [key3, route] of cells) {
|
|
3280
|
+
const [x, y] = key3.split(",").map(Number);
|
|
3281
|
+
const cell = grid[y][x];
|
|
3282
|
+
if (cell.kind === "label" || cell.kind === "box-label") fail2(`Edge ${edge.id} overwrites a label at (${x},${y}).`, "EDGE_LABEL_COLLISION");
|
|
3283
|
+
if (!cell.edge) cell.edge = { dirs: /* @__PURE__ */ new Set(), edgeIds: /* @__PURE__ */ new Set(), stroke: route.stroke, edgeRoutes: /* @__PURE__ */ new Map() };
|
|
3284
|
+
for (const [otherId, otherRoute] of cell.edge.edgeRoutes) {
|
|
3285
|
+
const allowed = sharedIntersection(key3, edge.id, otherId, boxBorders, endpointOwners);
|
|
3286
|
+
if (!allowed && !compatibleCrossing(route.dirs, otherRoute.dirs)) {
|
|
3287
|
+
fail2(`Edges ${otherId} and ${edge.id} overlap ambiguously at (${x},${y}).`, "ROUTE_COLLISION");
|
|
3288
|
+
}
|
|
3289
|
+
}
|
|
3290
|
+
cell.edge.edgeRoutes.set(edge.id, { dirs: new Set(route.dirs), segmentIndices: new Set(route.segmentIndices) });
|
|
3291
|
+
for (const d of route.dirs) cell.edge.dirs.add(d);
|
|
3292
|
+
for (const id of route.edgeIds) cell.edge.edgeIds.add(id);
|
|
3293
|
+
if (strokeRank(route.stroke) > strokeRank(cell.edge.stroke)) cell.edge.stroke = route.stroke;
|
|
3294
|
+
cell.kind = "edge";
|
|
3295
|
+
cell.glyph = edgeGlyph(cell.edge.dirs, cell.edge.edgeIds, cell.edge.stroke, charset);
|
|
3296
|
+
}
|
|
3297
|
+
for (const label of labels) {
|
|
3298
|
+
for (let y = label.y; y < label.y + label.height; y += 1) for (let x = label.x; x < label.x + label.width; x += 1) {
|
|
3299
|
+
if (grid[y]?.[x]?.kind === "box-label") fail2(`Edge label overlaps a box label at (${x},${y}).`, "LABEL_COLLISION");
|
|
3300
|
+
}
|
|
3301
|
+
}
|
|
3302
|
+
}
|
|
3303
|
+
function sharedIntersection(key3, firstId, secondId, boxBorders, endpointOwners) {
|
|
3304
|
+
const owners = endpointOwners.get(key3);
|
|
3305
|
+
if (owners?.has(firstId) && owners.has(secondId)) return true;
|
|
3306
|
+
return boxBorders.has(key3) && (!owners || owners.size === 0);
|
|
3307
|
+
}
|
|
3308
|
+
function compatibleCrossing(first, second) {
|
|
3309
|
+
const firstHorizontal = first.has("left") && first.has("right") && !first.has("up") && !first.has("down");
|
|
3310
|
+
const firstVertical = first.has("up") && first.has("down") && !first.has("left") && !first.has("right");
|
|
3311
|
+
const secondHorizontal = second.has("left") && second.has("right") && !second.has("up") && !second.has("down");
|
|
3312
|
+
const secondVertical = second.has("up") && second.has("down") && !second.has("left") && !second.has("right");
|
|
3313
|
+
return firstHorizontal && secondVertical || firstVertical && secondHorizontal;
|
|
3314
|
+
}
|
|
3315
|
+
function drawBox(grid, box, charset) {
|
|
3316
|
+
const cells = boxBorderCells(box, charset);
|
|
3317
|
+
for (const { x, y, glyph } of cells) {
|
|
3318
|
+
const cell = grid[y]?.[x];
|
|
3319
|
+
if (!cell) fail2(`Box ${box.id} lies outside the layout.`, "LAYOUT_CLIP");
|
|
3320
|
+
if (cell.kind === "box-label" || cell.kind === "label") fail2(`Box ${box.id} overwrites a label at (${x},${y}).`, "BOX_LABEL_COLLISION");
|
|
3321
|
+
const route = cell.edge;
|
|
3322
|
+
if (route && box.kind !== "subgraph") {
|
|
3323
|
+
cell.edge = null;
|
|
3324
|
+
}
|
|
3325
|
+
cell.kind = "box";
|
|
3326
|
+
cell.glyph = route && box.kind === "subgraph" ? borderWithRoute(glyph, route, charset) : glyph;
|
|
3327
|
+
}
|
|
3328
|
+
const innerWidth = Math.max(0, box.width - 2);
|
|
3329
|
+
const innerHeight = Math.max(0, box.height - 2);
|
|
3330
|
+
const lines = box.lines;
|
|
3331
|
+
if (lines.length > innerHeight) fail2(`Box ${box.id} does not have enough height for its label.`, "BOX_LABEL_COLLISION");
|
|
3332
|
+
const top = box.kind === "subgraph" ? box.y + 1 : box.y + 1 + Math.floor((innerHeight - lines.length) / 2);
|
|
3333
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
3334
|
+
const line = lines[i];
|
|
3335
|
+
const lineWidth = displayWidth(line);
|
|
3336
|
+
if (lineWidth > innerWidth) fail2(`Box ${box.id} does not have enough width for its label.`, "BOX_LABEL_COLLISION");
|
|
3337
|
+
const left = box.x + 1 + Math.floor((innerWidth - lineWidth) / 2);
|
|
3338
|
+
putText(grid, left, top + i, line, "box-label", `box ${box.id}`);
|
|
3339
|
+
}
|
|
3340
|
+
}
|
|
3341
|
+
function boxBorderCells(box, charset) {
|
|
3342
|
+
const out = [];
|
|
3343
|
+
const { x, y, width: w, height: h } = box;
|
|
3344
|
+
const shape = String(box.shape ?? "rect").toLowerCase();
|
|
3345
|
+
const glyphs = charset === "unicode";
|
|
3346
|
+
const put = (xx, yy, glyph) => out.push({ x: xx, y: yy, glyph });
|
|
3347
|
+
if (w === 1 || h === 1) {
|
|
3348
|
+
for (let yy = y; yy < y + h; yy += 1) for (let xx = x; xx < x + w; xx += 1) put(xx, yy, glyphs ? "\u2502" : "|");
|
|
3349
|
+
return out;
|
|
3350
|
+
}
|
|
3351
|
+
const rounded = shape === "round" || shape === "rounded" || shape === "stadium" || shape === "circle";
|
|
3352
|
+
if (rounded) {
|
|
3353
|
+
const c = glyphs ? ["\u256D", "\u256E", "\u2570", "\u256F"] : ["/", "\\", "\\", "/"];
|
|
3354
|
+
put(x, y, c[0]);
|
|
3355
|
+
put(x + w - 1, y, c[1]);
|
|
3356
|
+
put(x, y + h - 1, c[2]);
|
|
3357
|
+
put(x + w - 1, y + h - 1, c[3]);
|
|
3358
|
+
for (let xx = x + 1; xx < x + w - 1; xx += 1) {
|
|
3359
|
+
put(xx, y, glyphs ? "\u2500" : "-");
|
|
3360
|
+
put(xx, y + h - 1, glyphs ? "\u2500" : "-");
|
|
3361
|
+
}
|
|
3362
|
+
for (let yy = y + 1; yy < y + h - 1; yy += 1) {
|
|
3363
|
+
put(x, yy, glyphs ? "\u2502" : "|");
|
|
3364
|
+
put(x + w - 1, yy, glyphs ? "\u2502" : "|");
|
|
3365
|
+
}
|
|
3366
|
+
return out;
|
|
3367
|
+
}
|
|
3368
|
+
if (shape === "diamond" || shape === "rhombus") {
|
|
3369
|
+
const slash = glyphs ? "\u2571" : "/";
|
|
3370
|
+
const back = glyphs ? "\u2572" : "\\";
|
|
3371
|
+
const vertical = glyphs ? "\u2502" : "|";
|
|
3372
|
+
for (let xx = x + 1; xx < x + w - 1; xx += 1) {
|
|
3373
|
+
put(xx, y, glyphs ? "\u2500" : "-");
|
|
3374
|
+
put(xx, y + h - 1, glyphs ? "\u2500" : "-");
|
|
3375
|
+
}
|
|
3376
|
+
put(x, y, slash);
|
|
3377
|
+
put(x + w - 1, y, back);
|
|
3378
|
+
put(x, y + h - 1, back);
|
|
3379
|
+
put(x + w - 1, y + h - 1, slash);
|
|
3380
|
+
for (let yy = y + 1; yy < y + h - 1; yy += 1) {
|
|
3381
|
+
const left = yy === y + Math.floor((h - 1) / 2) ? glyphs ? "\u25C1" : "<" : vertical;
|
|
3382
|
+
const right = yy === y + Math.floor((h - 1) / 2) ? glyphs ? "\u25B7" : ">" : vertical;
|
|
3383
|
+
put(x, yy, left);
|
|
3384
|
+
put(x + w - 1, yy, right);
|
|
3385
|
+
}
|
|
3386
|
+
return out;
|
|
3387
|
+
}
|
|
3388
|
+
const corner = glyphs ? ["\u250C", "\u2510", "\u2514", "\u2518"] : ["+", "+", "+", "+"];
|
|
3389
|
+
put(x, y, corner[0]);
|
|
3390
|
+
put(x + w - 1, y, corner[1]);
|
|
3391
|
+
put(x, y + h - 1, corner[2]);
|
|
3392
|
+
put(x + w - 1, y + h - 1, corner[3]);
|
|
3393
|
+
for (let xx = x + 1; xx < x + w - 1; xx += 1) {
|
|
3394
|
+
put(xx, y, glyphs ? "\u2500" : "-");
|
|
3395
|
+
put(xx, y + h - 1, glyphs ? "\u2500" : "-");
|
|
3396
|
+
}
|
|
3397
|
+
for (let yy = y + 1; yy < y + h - 1; yy += 1) {
|
|
3398
|
+
put(x, yy, glyphs ? "\u2502" : "|");
|
|
3399
|
+
put(x + w - 1, yy, glyphs ? "\u2502" : "|");
|
|
3400
|
+
}
|
|
3401
|
+
return out;
|
|
3402
|
+
}
|
|
3403
|
+
function borderWithRoute(border, route, charset) {
|
|
3404
|
+
const horizontal = route.dirs.has("left") || route.dirs.has("right");
|
|
3405
|
+
const vertical = route.dirs.has("up") || route.dirs.has("down");
|
|
3406
|
+
if (horizontal && vertical) return charset === "unicode" ? "\u253C" : "+";
|
|
3407
|
+
if (horizontal && route.dirs.has("left") && route.dirs.has("right")) return charset === "unicode" ? "\u2500" : "-";
|
|
3408
|
+
if (vertical && route.dirs.has("up") && route.dirs.has("down")) return charset === "unicode" ? "\u2502" : "|";
|
|
3409
|
+
return border;
|
|
3410
|
+
}
|
|
3411
|
+
function drawLabel(grid, label, owner, edgeId) {
|
|
3412
|
+
for (let i = 0; i < label.lines.length; i += 1) putText(grid, label.x, label.y + i, label.lines[i], "label", owner, false, edgeId);
|
|
3413
|
+
}
|
|
3414
|
+
function putText(grid, x, y, text, kind, owner, allowRoute = false, allowedEdgeId = void 0) {
|
|
3415
|
+
if (!grid[y]) fail2(`${owner} lies outside the layout.`, "LAYOUT_CLIP");
|
|
3416
|
+
let column = x;
|
|
3417
|
+
let previous = null;
|
|
3418
|
+
for (const grapheme of segment(text)) {
|
|
3419
|
+
const w = Math.max(0, displayWidth(grapheme));
|
|
3420
|
+
if (w === 0) {
|
|
3421
|
+
if (previous) previous.glyph += grapheme;
|
|
3422
|
+
continue;
|
|
3423
|
+
}
|
|
3424
|
+
if (column < 0 || column + w > grid[y].length) fail2(`${owner} lies outside the layout.`, "LAYOUT_CLIP");
|
|
3425
|
+
for (let offset = 0; offset < w; offset += 1) {
|
|
3426
|
+
const cell = grid[y][column + offset];
|
|
3427
|
+
const routeLabel = (kind === "label" || allowRoute) && cell.kind === "edge" && (!allowedEdgeId || cell.edge?.edgeIds.size === 1 && cell.edge.edgeIds.has(allowedEdgeId));
|
|
3428
|
+
if (!routeLabel && (cell.kind === "box" || cell.kind === "edge" || cell.kind === "arrow" || cell.kind === "label" || cell.kind === "box-label")) {
|
|
3429
|
+
fail2(`${owner} collides at (${column + offset},${y}).`, "LABEL_COLLISION");
|
|
3430
|
+
}
|
|
3431
|
+
cell.kind = kind;
|
|
3432
|
+
cell.glyph = offset === 0 ? grapheme : "";
|
|
3433
|
+
cell.wide = offset === 0 && w > 1;
|
|
3434
|
+
}
|
|
3435
|
+
previous = grid[y][column];
|
|
3436
|
+
column += w;
|
|
3437
|
+
}
|
|
3438
|
+
}
|
|
3439
|
+
function drawArrows(grid, edge, boxes, charset) {
|
|
3440
|
+
if (edge.stroke === "invisible" || edge.points.length < 2) return;
|
|
3441
|
+
const place = (kind, arrow, at, toward) => {
|
|
3442
|
+
if (!arrow || arrow === "none") return;
|
|
3443
|
+
const cell = grid[at.y]?.[at.x];
|
|
3444
|
+
if (!cell) fail2(`Arrow for edge ${edge.id} lies outside the layout.`, "LAYOUT_CLIP");
|
|
3445
|
+
if (cell.kind === "box-label" || cell.kind === "label") fail2(`Arrow for edge ${edge.id} overwrites a label.`, "EDGE_LABEL_COLLISION");
|
|
3446
|
+
if (cell.kind === "box") fail2(`Arrow for edge ${edge.id} overwrites a box border.`, "EDGE_BOX_COLLISION");
|
|
3447
|
+
if (cell.kind === "arrow") fail2(`Arrow for edge ${edge.id} overlaps another arrow.`, "ARROW_COLLISION");
|
|
3448
|
+
if (cell.kind === "edge" && cell.edge && [...cell.edge.edgeIds].some((id) => id !== edge.id)) {
|
|
3449
|
+
fail2(`Arrow for edge ${edge.id} hides another route.`, "ARROW_COLLISION");
|
|
3450
|
+
}
|
|
3451
|
+
const glyph = arrowGlyph(arrow, toward, charset);
|
|
3452
|
+
cell.kind = "arrow";
|
|
3453
|
+
cell.glyph = glyph;
|
|
3454
|
+
cell.wide = false;
|
|
3455
|
+
};
|
|
3456
|
+
const first = distinctPair2(edge.points, true);
|
|
3457
|
+
const last = distinctPair2(edge.points, false);
|
|
3458
|
+
if (first) place("start", edge.arrowStart, first.next, opposite(directionBetween(first.current, first.next)));
|
|
3459
|
+
if (last) place("end", edge.arrowEnd, last.previous, directionBetween(last.previous, last.current));
|
|
3460
|
+
}
|
|
3461
|
+
function distinctPair2(points, start) {
|
|
3462
|
+
if (start) {
|
|
3463
|
+
for (let i = 1; i < points.length; i += 1) if (points[i].x !== points[0].x || points[i].y !== points[0].y) return { current: points[0], next: oneStep3(points[0], points[i]) };
|
|
3464
|
+
} else {
|
|
3465
|
+
for (let i = points.length - 2; i >= 0; i -= 1) if (points[i].x !== points[points.length - 1].x || points[i].y !== points[points.length - 1].y) return { previous: oneStep3(points[points.length - 1], points[i]), current: points[points.length - 1] };
|
|
3466
|
+
}
|
|
3467
|
+
return null;
|
|
3468
|
+
}
|
|
3469
|
+
function oneStep3(end, toward) {
|
|
3470
|
+
return { x: end.x + Math.sign(toward.x - end.x), y: end.y + Math.sign(toward.y - end.y) };
|
|
3471
|
+
}
|
|
3472
|
+
function directionBetween(a, b) {
|
|
3473
|
+
if (b.x > a.x) return "right";
|
|
3474
|
+
if (b.x < a.x) return "left";
|
|
3475
|
+
if (b.y > a.y) return "down";
|
|
3476
|
+
return "up";
|
|
3477
|
+
}
|
|
3478
|
+
function edgeGlyph(dirs, edgeIds, stroke, charset) {
|
|
3479
|
+
if (dirs.size === 0) return charset === "unicode" ? "\xB7" : ".";
|
|
3480
|
+
const has = (d) => dirs.has(d);
|
|
3481
|
+
if (dirs.size >= 4) return charset === "unicode" ? edgeIds.size > 1 ? "\u2573" : "\u253C" : edgeIds.size > 1 ? "#" : "+";
|
|
3482
|
+
if (dirs.size === 3) return charset === "unicode" ? "\u253C" : "+";
|
|
3483
|
+
if (dirs.size === 2 && has("left") && has("right")) return charset === "unicode" ? unicodeStroke(stroke, "h") : asciiStroke(stroke, "h");
|
|
3484
|
+
if (dirs.size === 2 && has("up") && has("down")) return charset === "unicode" ? unicodeStroke(stroke, "v") : asciiStroke(stroke, "v");
|
|
3485
|
+
if (dirs.size === 2) {
|
|
3486
|
+
if (charset === "ascii") return "+";
|
|
3487
|
+
if (has("right") && has("down")) return "\u250C";
|
|
3488
|
+
if (has("left") && has("down")) return "\u2510";
|
|
3489
|
+
if (has("right") && has("up")) return "\u2514";
|
|
3490
|
+
return "\u2518";
|
|
3491
|
+
}
|
|
3492
|
+
return charset === "unicode" ? has("left") || has("right") ? unicodeStroke(stroke, "h") : unicodeStroke(stroke, "v") : has("left") || has("right") ? asciiStroke(stroke, "h") : asciiStroke(stroke, "v");
|
|
3493
|
+
}
|
|
3494
|
+
function asciiStroke(stroke, axis) {
|
|
3495
|
+
return stroke === "thick" ? axis === "h" ? "=" : "#" : stroke === "dotted" ? axis === "h" ? ":" : ":" : axis === "h" ? "-" : "|";
|
|
3496
|
+
}
|
|
3497
|
+
function unicodeStroke(stroke, axis) {
|
|
3498
|
+
return stroke === "thick" ? axis === "h" ? "\u2501" : "\u2503" : stroke === "dotted" ? axis === "h" ? "\u2504" : "\u2506" : axis === "h" ? "\u2500" : "\u2502";
|
|
3499
|
+
}
|
|
3500
|
+
function strokeRank(stroke) {
|
|
3501
|
+
return stroke === "thick" ? 3 : stroke === "normal" ? 2 : stroke === "dotted" ? 1 : 0;
|
|
3502
|
+
}
|
|
3503
|
+
function opposite(direction) {
|
|
3504
|
+
return { left: "right", right: "left", up: "down", down: "up" }[direction];
|
|
3505
|
+
}
|
|
3506
|
+
function arrowGlyph(arrow, direction, charset) {
|
|
3507
|
+
if (arrow === "circle") return charset === "unicode" ? "\u25CB" : "o";
|
|
3508
|
+
if (arrow === "cross") return charset === "unicode" ? "\xD7" : "x";
|
|
3509
|
+
if (charset === "unicode") return { left: "\u25C0", right: "\u25B6", up: "\u25B2", down: "\u25BC" }[direction] ?? "\u25B6";
|
|
3510
|
+
return { left: "<", right: ">", up: "^", down: "v" }[direction] ?? ">";
|
|
3511
|
+
}
|
|
3512
|
+
function stringifyGrid(grid) {
|
|
3513
|
+
if (!grid.length) return "";
|
|
3514
|
+
let left = Infinity;
|
|
3515
|
+
let right = -1;
|
|
3516
|
+
for (const row of grid) {
|
|
3517
|
+
for (let x = 0; x < row.length; x += 1) {
|
|
3518
|
+
if (row[x].glyph && row[x].glyph !== " ") {
|
|
3519
|
+
left = Math.min(left, x);
|
|
3520
|
+
right = Math.max(right, x);
|
|
3521
|
+
}
|
|
3522
|
+
}
|
|
3523
|
+
}
|
|
3524
|
+
if (right < 0) return "";
|
|
3525
|
+
const lines = grid.slice().map((row) => row.slice(left, right + 1).map((cell) => cell.glyph === "" ? "" : cell.glyph || " ").join("").replace(/[ \t]+$/u, ""));
|
|
3526
|
+
while (lines.length && lines[lines.length - 1] === "") lines.pop();
|
|
3527
|
+
while (lines.length && lines[0] === "") lines.shift();
|
|
3528
|
+
return lines.join("\n");
|
|
3529
|
+
}
|
|
3530
|
+
function segment(value) {
|
|
3531
|
+
if (typeof Intl !== "undefined" && Intl.Segmenter) return Array.from(new Intl.Segmenter(void 0, { granularity: "grapheme" }).segment(value), (item) => item.segment);
|
|
3532
|
+
return Array.from(value);
|
|
3533
|
+
}
|
|
3534
|
+
function fail2(message, code) {
|
|
3535
|
+
throw new FlowInkError(message, { code });
|
|
3536
|
+
}
|
|
3537
|
+
|
|
3538
|
+
// src/index.js
|
|
3539
|
+
async function render(source, options = {}) {
|
|
3540
|
+
if (!options || typeof options !== "object") {
|
|
3541
|
+
throw new FlowInkError("Render options must be an object.", { code: "INVALID_OPTIONS" });
|
|
3542
|
+
}
|
|
3543
|
+
const charset = options.charset ?? "ascii";
|
|
3544
|
+
if (charset !== "ascii" && charset !== "unicode") {
|
|
3545
|
+
throw new FlowInkError('charset must be "ascii" or "unicode".', { code: "INVALID_OPTIONS" });
|
|
3546
|
+
}
|
|
3547
|
+
const graph = parse(source);
|
|
3548
|
+
try {
|
|
3549
|
+
return rasterize(await layout(graph), { charset });
|
|
3550
|
+
} catch (cause) {
|
|
3551
|
+
if (cause instanceof FlowInkError) throw cause;
|
|
3552
|
+
throw new FlowInkError(`Cannot lay out this flowchart: ${cause instanceof Error ? cause.message : String(cause)}`, { code: "LAYOUT_ERROR", cause });
|
|
3553
|
+
}
|
|
3554
|
+
}
|
|
3555
|
+
export {
|
|
3556
|
+
FlowInkError,
|
|
3557
|
+
parse,
|
|
3558
|
+
render
|
|
3559
|
+
};
|
|
3560
|
+
//# sourceMappingURL=index.js.map
|