drakongen 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/.vscode/launch.json +18 -0
  2. package/LICENSE +24 -0
  3. package/README.md +80 -0
  4. package/browser/drakongen.js +1303 -0
  5. package/browsertest.html +84 -0
  6. package/buildbrowser +4 -0
  7. package/buildexamples.js +61 -0
  8. package/examples/00.Empty.drakon +1 -0
  9. package/examples/00.Empty.txt +5 -0
  10. package/examples/01. /320/221/320/265/320/273/321/213/320/270/314/206.drakon" +13 -0
  11. package/examples/01. /320/221/320/265/320/273/321/213/320/271.json" +16 -0
  12. package/examples/01. /320/221/320/265/320/273/321/213/320/271.txt" +4 -0
  13. package/examples/02. /320/247/320/265/314/210/321/200/320/275/321/213/320/270/314/206.drakon" +28 -0
  14. package/examples/02. /320/247/321/221/321/200/320/275/321/213/320/271.json" +31 -0
  15. package/examples/02. /320/247/321/221/321/200/320/275/321/213/320/271.txt" +10 -0
  16. package/examples/03. /320/241/320/265/321/200/321/213/320/270/314/206.drakon" +20 -0
  17. package/examples/03. /320/241/320/265/321/200/321/213/320/271.json" +23 -0
  18. package/examples/03. /320/241/320/265/321/200/321/213/320/271.txt" +6 -0
  19. package/examples/04. /320/221/321/203/321/200/321/213/320/270/314/206.drakon" +25 -0
  20. package/examples/04. /320/221/321/203/321/200/321/213/320/271.json" +29 -0
  21. package/examples/04. /320/221/321/203/321/200/321/213/320/271.txt" +7 -0
  22. package/examples/05. /320/226/320/265/314/210/320/273/321/202/321/213/320/270/314/206.drakon" +25 -0
  23. package/examples/05. /320/226/321/221/320/273/321/202/321/213/320/271.json" +29 -0
  24. package/examples/05. /320/226/321/221/320/273/321/202/321/213/320/271.txt" +7 -0
  25. package/examples/06. /320/221/320/260/320/263/321/200/320/276/320/262/321/213/320/270/314/206.drakon" +30 -0
  26. package/examples/06. /320/221/320/260/320/263/321/200/320/276/320/262/321/213/320/271.json" +35 -0
  27. package/examples/06. /320/221/320/260/320/263/321/200/320/276/320/262/321/213/320/271.txt" +10 -0
  28. package/examples/07. /320/244/320/270/320/276/320/273/320/265/321/202/320/276/320/262/321/213/320/270/314/206.drakon" +42 -0
  29. package/examples/07. /320/244/320/270/320/276/320/273/320/265/321/202/320/276/320/262/321/213/320/271.json" +49 -0
  30. package/examples/07. /320/244/320/270/320/276/320/273/320/265/321/202/320/276/320/262/321/213/320/271.txt" +14 -0
  31. package/examples/08. /320/221/320/270/321/200/321/216/320/267/320/276/320/262/321/213/320/270/314/206.drakon" +27 -0
  32. package/examples/08. /320/221/320/270/321/200/321/216/320/267/320/276/320/262/321/213/320/271.json" +27 -0
  33. package/examples/08. /320/221/320/270/321/200/321/216/320/267/320/276/320/262/321/213/320/271.txt" +6 -0
  34. package/examples/09. /320/236/321/200/320/260/320/275/320/266/320/265/320/262/321/213/320/270/314/206.drakon" +37 -0
  35. package/examples/09. /320/236/321/200/320/260/320/275/320/266/320/265/320/262/321/213/320/271.json" +39 -0
  36. package/examples/09. /320/236/321/200/320/260/320/275/320/266/320/265/320/262/321/213/320/271.txt" +10 -0
  37. package/examples/10. /320/240/320/276/320/267/320/276/320/262/321/213/320/270/314/206.drakon" +42 -0
  38. package/examples/10. /320/240/320/276/320/267/320/276/320/262/321/213/320/271.json" +54 -0
  39. package/examples/10. /320/240/320/276/320/267/320/276/320/262/321/213/320/271.txt" +16 -0
  40. package/examples/11. /320/227/320/260/321/211/320/270/321/202/320/275/321/213/320/270/314/206.drakon" +37 -0
  41. package/examples/11. /320/227/320/260/321/211/320/270/321/202/320/275/321/213/320/271.json" +39 -0
  42. package/examples/11. /320/227/320/260/321/211/320/270/321/202/320/275/321/213/320/271.txt" +10 -0
  43. package/examples/12. /320/221/320/276/320/273/320/276/321/202/320/275/321/213/320/270/314/206.drakon" +44 -0
  44. package/examples/12. /320/221/320/276/320/273/320/276/321/202/320/275/321/213/320/271.json" +43 -0
  45. package/examples/12. /320/221/320/276/320/273/320/276/321/202/320/275/321/213/320/271.txt" +10 -0
  46. package/examples/13. /320/241/320/260/320/273/320/260/321/202/320/276/320/262/321/213/320/270/314/206.drakon" +54 -0
  47. package/examples/13. /320/241/320/260/320/273/320/260/321/202/320/276/320/262/321/213/320/271.json" +63 -0
  48. package/examples/13. /320/241/320/260/320/273/320/260/321/202/320/276/320/262/321/213/320/271.txt" +18 -0
  49. package/examples/14. /320/227/320/276/320/273/320/276/321/202/320/276/320/270/314/206.drakon" +64 -0
  50. package/examples/14. /320/227/320/276/320/273/320/276/321/202/320/276/320/271.json" +73 -0
  51. package/examples/14. /320/227/320/276/320/273/320/276/321/202/320/276/320/271.txt" +22 -0
  52. package/examples/15. /320/241/320/270/320/275/320/270/320/270/314/206.drakon" +54 -0
  53. package/examples/15. /320/241/320/270/320/275/320/270/320/271.json" +87 -0
  54. package/examples/15. /320/241/320/270/320/275/320/270/320/271.txt" +26 -0
  55. package/examples/16. /320/223/320/276/320/273/321/203/320/261/320/276/320/270/314/206.drakon" +37 -0
  56. package/examples/16. /320/223/320/276/320/273/321/203/320/261/320/276/320/271.json" +48 -0
  57. package/examples/16. /320/223/320/276/320/273/321/203/320/261/320/276/320/271.txt" +13 -0
  58. package/examples/17. /320/241/320/260/320/273/320/260/321/202/320/276/320/262/321/213/320/270/314/206.drakon" +39 -0
  59. package/examples/17. /320/241/320/260/320/273/320/260/321/202/320/276/320/262/321/213/320/271.json" +41 -0
  60. package/examples/17. /320/241/320/260/320/273/320/260/321/202/320/276/320/262/321/213/320/271.txt" +10 -0
  61. package/examples/18. /320/241/321/202/320/260/320/273/321/214/320/275/320/276/320/270/314/206.drakon" +49 -0
  62. package/examples/18. /320/241/321/202/320/260/320/273/321/214/320/275/320/276/320/271.json" +67 -0
  63. package/examples/18. /320/241/321/202/320/260/320/273/321/214/320/275/320/276/320/271.txt" +19 -0
  64. package/examples/19. Lilla.drakon +39 -0
  65. package/examples/19. Lilla.json +45 -0
  66. package/examples/19. Lilla.txt +11 -0
  67. package/examples/Adaptive design.drakon +116 -0
  68. package/examples/Adaptive design.json +153 -0
  69. package/examples/Adaptive design.txt +47 -0
  70. package/examples/And test.drakon +46 -0
  71. package/examples/And test.json +46 -0
  72. package/examples/And test.txt +10 -0
  73. package/examples/Arrow - double exit.drakon +41 -0
  74. package/examples/Arrow - double exit.json +62 -0
  75. package/examples/Arrow - double exit.txt +14 -0
  76. package/examples/Complex arrow.drakon +93 -0
  77. package/examples/Complex arrow.json +162 -0
  78. package/examples/Complex arrow.txt +43 -0
  79. package/examples/DoubleArrow.drakon +53 -0
  80. package/examples/DoubleArrow.json +86 -0
  81. package/examples/DoubleArrow.txt +18 -0
  82. package/examples/Find pointing nodes.drakon +104 -0
  83. package/examples/Find pointing nodes.json +137 -0
  84. package/examples/Find pointing nodes.txt +29 -0
  85. package/examples/How to tune PID on a quadcopter.drakon +488 -0
  86. package/examples/How to tune PID on a quadcopter.json +734 -0
  87. package/examples/How to tune PID on a quadcopter.txt +169 -0
  88. package/examples/Or test.drakon +47 -0
  89. package/examples/Or test.json +46 -0
  90. package/examples/Or test.txt +10 -0
  91. package/examples/Silhouette test 1.drakon +47 -0
  92. package/examples/Silhouette test 1.json +82 -0
  93. package/examples/Silhouette test 1.txt +24 -0
  94. package/examples/Work out action-check.drakon +30 -0
  95. package/examples/Work out action-check.json +45 -0
  96. package/examples/Work out action-check.txt +9 -0
  97. package/examples/Workout foreach.drakon +63 -0
  98. package/examples/Workout foreach.json +62 -0
  99. package/examples/Workout foreach.txt +14 -0
  100. package/examples/ar01.drakon +25 -0
  101. package/examples/ar01.json +40 -0
  102. package/examples/ar01.txt +7 -0
  103. package/examples/ar02.drakon +30 -0
  104. package/examples/ar02.json +45 -0
  105. package/examples/ar02.txt +10 -0
  106. package/examples/ar03.drakon +32 -0
  107. package/examples/ar03.json +44 -0
  108. package/examples/ar03.txt +7 -0
  109. package/examples/ar04.drakon +37 -0
  110. package/examples/ar04.json +49 -0
  111. package/examples/ar04.txt +10 -0
  112. package/examples/ar05.drakon +37 -0
  113. package/examples/ar05.json +59 -0
  114. package/examples/ar05.txt +11 -0
  115. package/examples/ar06.drakon +40 -0
  116. package/examples/ar06.json +70 -0
  117. package/examples/ar06.txt +13 -0
  118. package/examples/ar07.drakon +40 -0
  119. package/examples/ar07.json +70 -0
  120. package/examples/ar07.txt +13 -0
  121. package/examples/ar08.drakon +47 -0
  122. package/examples/ar08.json +81 -0
  123. package/examples/ar08.txt +16 -0
  124. package/examples/ar09.drakon +52 -0
  125. package/examples/ar09.json +87 -0
  126. package/examples/ar09.txt +17 -0
  127. package/examples/ar10.drakon +52 -0
  128. package/examples/ar10.json +88 -0
  129. package/examples/ar10.txt +18 -0
  130. package/examples/ar11.drakon +47 -0
  131. package/examples/ar11.json +82 -0
  132. package/examples/ar11.txt +17 -0
  133. package/examples/ar12.drakon +37 -0
  134. package/examples/ar12.json +49 -0
  135. package/examples/ar12.txt +10 -0
  136. package/examples/getToken.drakon +76 -0
  137. package/examples/getToken.json +88 -0
  138. package/examples/getToken.txt +41 -0
  139. package/examples/tmp.drakon +49 -0
  140. package/examples/tmp.json +82 -0
  141. package/examples/tmp.txt +37 -0
  142. package/package.json +21 -0
  143. package/prompts/drakonToPrompt.txt +139 -0
  144. package/prompts/index.txt +17 -0
  145. package/prompts/printPseudo.txt +116 -0
  146. package/src/browserTools.js +39 -0
  147. package/src/drakonToPromptStruct.js +44 -0
  148. package/src/drakonToStruct.js +416 -0
  149. package/src/drakongen.js +16 -0
  150. package/src/index.js +17 -0
  151. package/src/main.js +157 -0
  152. package/src/nodeTools.js +38 -0
  153. package/src/printPseudo.js +167 -0
  154. package/src/structFlow.js +382 -0
  155. package/src/technicalTree.js +84 -0
  156. package/src/tools.js +36 -0
  157. package/src/translate.js +108 -0
@@ -0,0 +1,1303 @@
1
+ (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
2
+
3
+ function htmlToString(html) {
4
+ if (!html) return '';
5
+ if (!html.startsWith('<') || !html.endsWith('>')) {
6
+ return html.split("\n").map(line => {return line.trim()})
7
+ }
8
+
9
+ const parser = new DOMParser();
10
+ const doc = parser.parseFromString(html, "text/html");
11
+
12
+ const root = doc.body
13
+ const output = [];
14
+
15
+ root.childNodes.forEach((node) => {
16
+ if (node.tagName === 'P') {
17
+ output.push(node.textContent.trim());
18
+ } else if (node.tagName === 'UL') {
19
+ output.push('');
20
+ node.childNodes.forEach((item) => {
21
+ if (item.tagName === 'LI') {
22
+ output.push(`- ${item.textContent.trim()}`);
23
+ }
24
+ });
25
+ output.push('');
26
+ } else if (node.tagName === 'OL') {
27
+ output.push('');
28
+ node.childNodes.forEach((item, index) => {
29
+ if (item.tagName === 'LI') {
30
+ output.push(`${index + 1}. ${item.textContent.trim()}`);
31
+ }
32
+ });
33
+ output.push('');
34
+ }
35
+ });
36
+
37
+ return output;
38
+ }
39
+
40
+ module.exports = {htmlToString}
41
+ },{}],2:[function(require,module,exports){
42
+ const {drakonToStruct} = require("./drakonToStruct");
43
+ const {printPseudo} = require('./printPseudo');
44
+ const {addRange} = require("./tools")
45
+
46
+ function drakonToPseudocode(drakonJson, name, filename, htmlToString, translate) {
47
+ var diagram = drakonToStruct(drakonJson, name, filename, translate)
48
+ var lines = []
49
+ if (diagram.params) {
50
+ addRange(lines, htmlToString(diagram.params))
51
+ lines.push("")
52
+ }
53
+
54
+ lines.push(translate("Procedure") + " \"" + diagram.name + "\"")
55
+ lines.push("")
56
+ lines.push(translate("Algorithm") + ":")
57
+
58
+ if (diagram.branches.length === 0) {
59
+ lines.push(translate("Empty"))
60
+ } else if (diagram.branches.length === 1) {
61
+ var first = diagram.branches[0]
62
+ printPseudo(first, translate, lines, htmlToString)
63
+ } else {
64
+ var first = diagram.branches[0]
65
+ lines.push(translate("Call subroutine") + ": \"" + htmlToString(first.name) + "\"")
66
+ diagram.branches.forEach(branch => {
67
+ lines.push("")
68
+ lines.push(translate("Subroutine") + ": \"" + htmlToString(branch.name) + "\"")
69
+ printPseudo(branch, translate, lines, htmlToString)
70
+ lines.push(translate("End of subroutine"))
71
+ })
72
+ }
73
+ lines.push(translate("End of procedure"))
74
+ if (diagram.description) {
75
+ lines.push("")
76
+ addRange(lines, htmlToString(diagram.description))
77
+ lines.push("")
78
+ }
79
+ var text = lines.join("\n")
80
+
81
+ var str = JSON.stringify(diagram, null, 4)
82
+ return {text:text,json:str}
83
+ }
84
+
85
+ module.exports = { drakonToPseudocode };
86
+ },{"./drakonToStruct":3,"./printPseudo":5,"./tools":8}],3:[function(require,module,exports){
87
+ const { structFlow, redirectNode } = require("./structFlow");
88
+ const { createError } = require("./tools");
89
+
90
+ var translate
91
+
92
+ function drakonToStruct(drakonJson, name, filename, translateFunction) {
93
+ translate = translateFunction
94
+ let drakonGraph;
95
+ try {
96
+ drakonJson = drakonJson || ""
97
+ drakonJson = drakonJson.trim()
98
+ drakonJson = drakonJson || "{}"
99
+ drakonGraph = JSON.parse(drakonJson);
100
+ } catch (error) {
101
+ var message = translate("Error parsing JSON") + ": " + error.message
102
+ throw createError(message, filename)
103
+ }
104
+
105
+ const nodes = drakonGraph.items || {};
106
+
107
+ var branches = []
108
+ var firstNodeId = findStartNode(nodes, filename, branches)
109
+
110
+ if (!firstNodeId) {
111
+ return {
112
+ name: name,
113
+ params: drakonGraph.params || "",
114
+ description: drakonGraph.description || "",
115
+ branches: []
116
+ }
117
+ }
118
+
119
+ buildTwoWayConnections(nodes, firstNodeId)
120
+
121
+ rewireSelectsMarkLoops(nodes, filename)
122
+ branches.forEach(branch => checkBranchIsReferenced(branch, firstNodeId, filename))
123
+ rewireShortcircuit(nodes, filename)
124
+ branches.forEach(branch => cutOffBranch(nodes, branch))
125
+
126
+ var branchTrees = structFlow(nodes, branches, filename, translate)
127
+
128
+ return {
129
+ name: name,
130
+ params: drakonGraph.params || "",
131
+ description: drakonGraph.description || "",
132
+ branches: branchTrees
133
+ }
134
+ }
135
+
136
+ function drakonToGraph(drakonJson, name, filename, translateFunction) {
137
+ translate = translateFunction
138
+ let drakonGraph;
139
+ try {
140
+ drakonGraph = JSON.parse(drakonJson);
141
+ } catch (error) {
142
+ var message = translate("Error parsing JSON") + ": " + error.message
143
+ throw createError(message, filename)
144
+ }
145
+
146
+ const nodes = drakonGraph.items || {};
147
+
148
+ var branches = []
149
+ var firstNodeId = findStartNode(nodes, filename, branches)
150
+
151
+ if (!firstNodeId) {
152
+ return undefined
153
+ }
154
+
155
+ buildTwoWayConnections(nodes, firstNodeId)
156
+
157
+ rewireSelectsMarkLoops(nodes, filename)
158
+ rewireShortcircuit(nodes, filename)
159
+ branches.forEach(branch => checkBranchIsReferenced(branch, firstNodeId, filename))
160
+ branches.forEach(branch => cutOffBranch(nodes, branch))
161
+
162
+ var branchTrees = structFlow(nodes, branches, filename, translate)
163
+
164
+ return {
165
+ name: name,
166
+ params: drakonGraph.params || "",
167
+ description: drakonGraph.description || "",
168
+ branches: branchTrees
169
+ }
170
+ }
171
+
172
+
173
+ function checkBranchIsReferenced(branch, firstNodeId, filename) {
174
+ if (branch.id === firstNodeId) {
175
+ return
176
+ }
177
+ if (branch.prev.length === 0) {
178
+ throw createError(translate("A silhouette branch is not referenced"), filename, branch.id)
179
+ }
180
+ }
181
+
182
+ function cutOffBranch(nodes, branch) {
183
+ var end = {
184
+ type: "end",
185
+ id: branch.id + "-end",
186
+ prev: []
187
+ }
188
+ nodes[end.id] = end
189
+ branch.next = branch.one
190
+ var addresses = []
191
+ traverseToHitBranch(nodes, branch.id, {}, (prev, node) => addFakeEnd(nodes, prev, node, end, addresses))
192
+ }
193
+
194
+ function traverseToHitBranch(nodes, nodeId, visited, action) {
195
+ if (!nodeId) {return}
196
+ if (nodeId in visited) {return}
197
+ visited[nodeId] = true
198
+ var node = nodes[nodeId]
199
+ if (!node) {return}
200
+ if (node.one) {
201
+ var one = nodes[node.one]
202
+ if (one.type === "branch") {
203
+ action(node, one)
204
+ } else {
205
+ traverseToHitBranch(nodes, node.one, visited, action)
206
+ }
207
+ }
208
+ if (node.two) {
209
+ var two = nodes[node.two]
210
+ if (two.type === "branch") {
211
+ action(node, two)
212
+ } else {
213
+ traverseToHitBranch(nodes, node.two, visited, action)
214
+ }
215
+ }
216
+ }
217
+
218
+ var idCounter = 1000
219
+ function addFakeEnd(nodes, prev, node, end, addresses) {
220
+ var lastAddress = undefined
221
+ if (addresses.length > 0) {
222
+ lastAddress = addresses[addresses.length - 1]
223
+ }
224
+ var address
225
+ if (lastAddress && lastAddress.branch === node.id) {
226
+ address = lastAddress
227
+ } else {
228
+ address = {
229
+ type: "address",
230
+ content: node.content,
231
+ id: "ad-" + idCounter,
232
+ branch: node.id,
233
+ one: end.id,
234
+ prev: []
235
+ }
236
+ idCounter++
237
+ nodes[address.id] = address
238
+ end.prev.push(address.id)
239
+ addresses.push(address)
240
+ }
241
+ redirectNode(nodes, prev, node.id, address.id)
242
+ }
243
+
244
+ function buildTwoWayConnections(nodes, firstNodeId) {
245
+ for (var id in nodes) {
246
+ var node = nodes[id]
247
+ node.id = id
248
+ node.prev = []
249
+ }
250
+
251
+ traverse(nodes, firstNodeId, {}, connectBack)
252
+ }
253
+
254
+ function findStartNode(nodes, filename, branches) {
255
+ var firstNodeId = undefined
256
+ var minBranchId = 10000
257
+ for (var id in nodes) {
258
+ var node = nodes[id]
259
+ if (node.type === "branch") {
260
+ if (node.branchId < minBranchId) {
261
+ firstNodeId = id
262
+ minBranchId = node.branchId
263
+ }
264
+ branches.push(node)
265
+ } else if (node.type === "select") {
266
+ if (!node.content) {
267
+ throw createError(translate("A Select icon must have content"), filename, id)
268
+ }
269
+ node.cases = [];
270
+ } else if (node.type === "loopbegin") {
271
+ if (!node.content) {
272
+ throw createError(translate("A Loop begin icon must have content"), filename, id)
273
+ }
274
+ } else if (node.type === "question") {
275
+ if (!node.content) {
276
+ throw createError(translate("A Question icon must have content"), filename, id)
277
+ }
278
+ }
279
+ }
280
+
281
+ return firstNodeId
282
+ }
283
+
284
+ function rewireSelectsMarkLoops(nodes, filename) {
285
+ for (var id of Object.keys(nodes)) {
286
+ var node = nodes[id]
287
+ if (!node) { continue }
288
+ if (node.type === "select") {
289
+ rewireSelect(nodes, node, filename)
290
+ } else if (node.type === "loopbegin") {
291
+ markLoopBody(nodes, node, filename)
292
+ }
293
+ }
294
+ }
295
+
296
+ function rewireSelect(nodes, selectNode, filename) {
297
+ var caseNodeId = selectNode.one
298
+ while (caseNodeId) {
299
+ var caseNode = nodes[caseNodeId]
300
+ caseNodeId = caseNode.two
301
+ if (caseNode.content) {
302
+ caseNode.type = "question"
303
+ caseNode.flag1 = 1
304
+ caseNode.content = {operator: "equal", left:selectNode.content, right:caseNode.content}
305
+ if (!caseNode.two) {
306
+ var errorId = caseNode.id + "-unexpected"
307
+ var errorAction = insertIcon(nodes, "error", errorId, selectNode.content)
308
+ errorAction.message = "Unexpected case value"
309
+
310
+ caseNode.two = errorId
311
+ errorAction.prev.push(caseNode.id)
312
+ errorAction.one = caseNode.one
313
+
314
+ var next = nodes[caseNode.one]
315
+ next.prev.push(errorId)
316
+ }
317
+ } else {
318
+ if (caseNode.two) {
319
+ throw createError(translate("Only the rightmost Case icon can be empty"), filename, caseNode.id)
320
+ }
321
+ removeNodeOne(nodes, caseNode.id)
322
+ }
323
+ }
324
+ removeNodeOne(nodes, selectNode.id)
325
+ }
326
+
327
+ function insertIcon(nodes, type, id, content) {
328
+ var node = {
329
+ type: type,
330
+ id: id,
331
+ content: content,
332
+ prev: []
333
+ }
334
+ nodes[id] = node
335
+ return node
336
+ }
337
+
338
+ function removeNodeOne(nodes, nodeId) {
339
+ var node = nodes[nodeId]
340
+ redirectPrev(nodes, node, node.one)
341
+ redirectNext(nodes, node, node.one)
342
+ delete nodes[nodeId]
343
+ }
344
+
345
+ function removeFromNext(node, next) {
346
+ next.prev = next.prev.filter(prevId => prevId !== node.id)
347
+ }
348
+
349
+ function redirectPrev(nodes, node, newTarget) {
350
+ for (var prevId of node.prev) {
351
+ var prev = nodes[prevId]
352
+ if (prev.one === node.id) {
353
+ prev.one = newTarget
354
+ }
355
+ if (prev.two === node.id) {
356
+ prev.two = newTarget
357
+ }
358
+ }
359
+ }
360
+
361
+ function redirectNext(nodes, node, newTarget) {
362
+ var target = nodes[newTarget]
363
+ removeFromNext(node, target)
364
+ for (var prevId of node.prev) {
365
+ target.prev.push(prevId)
366
+ }
367
+ }
368
+
369
+ function rewireShortcircuit(nodes) {
370
+ while (findShortcusts(nodes)) {
371
+
372
+ }
373
+ }
374
+
375
+ function findShortcusts(nodes) {
376
+ for (var id in nodes) {
377
+ var node = nodes[id]
378
+ if (node.type === "question") {
379
+ var andOperand = findAndOperand(nodes, node)
380
+ if (andOperand) {
381
+ writeAndShortcut(nodes, node, andOperand)
382
+ return true
383
+ }
384
+ var orOperand = findOrOperand(nodes, node)
385
+ if (orOperand) {
386
+ writeOrShortcut(nodes, node, orOperand)
387
+ return true
388
+ }
389
+ }
390
+ }
391
+ return false
392
+ }
393
+
394
+ function findAndOperand(nodes, node) {
395
+ var below = nodes[node.one]
396
+ if (below.type === "question") {
397
+ if (below.prev.length === 1 && below.two === node.two) {
398
+ return below
399
+ }
400
+ }
401
+ return undefined
402
+ }
403
+
404
+ function findOrOperand(nodes, node) {
405
+ var right = nodes[node.two]
406
+ if (right.type === "question") {
407
+ if (right.prev.length === 1 && right.one === node.one) {
408
+ return right
409
+ }
410
+ }
411
+ return undefined
412
+ }
413
+
414
+ function writeAndShortcut(nodes, node, andOperand) {
415
+ var right = nodes[node.two]
416
+ var down = nodes[andOperand.one]
417
+ removeFromNext(andOperand, right)
418
+ removeFromNext(andOperand, down)
419
+ node.content = {
420
+ operator: "and",
421
+ left: normalizeContent(node),
422
+ right: normalizeContent(andOperand)
423
+ }
424
+ node.one = down.id
425
+ node.flag1 = 1
426
+ down.prev.push(node.id)
427
+ delete nodes[andOperand.id]
428
+ }
429
+
430
+ function writeOrShortcut(nodes, node, orOperand) {
431
+ var right = nodes[orOperand.two]
432
+ var down = nodes[orOperand.one]
433
+ removeFromNext(orOperand, right)
434
+ removeFromNext(orOperand, down)
435
+ node.content = {
436
+ operator: "or",
437
+ left: normalizeContent(node),
438
+ right: normalizeContent(orOperand)
439
+ }
440
+ node.two = right.id
441
+ node.flag1 = 1
442
+ right.prev.push(node.id)
443
+ delete nodes[orOperand.id]
444
+ }
445
+
446
+ function normalizeContent(question) {
447
+ if (question.flag1 === 1) {
448
+ return question.content
449
+ }
450
+
451
+ return {
452
+ operator: "not",
453
+ operand: question.content
454
+ }
455
+ }
456
+
457
+
458
+ function traverse(nodes, nodeId, visited, action) {
459
+ if (!nodeId) {
460
+ return
461
+ }
462
+
463
+ if (nodeId in visited) {
464
+ return
465
+ }
466
+ visited[nodeId] = true
467
+ var node = nodes[nodeId]
468
+ action(nodes, node)
469
+ traverse(nodes, node.one, visited, action)
470
+ traverse(nodes, node.two, visited, action)
471
+ }
472
+
473
+ function connectBack(nodes, node) {
474
+ if (node.one) {
475
+ var one = nodes[node.one]
476
+ one.prev.push(node.id)
477
+ }
478
+ if (node.two) {
479
+ var two = nodes[node.two]
480
+ two.prev.push(node.id)
481
+ }
482
+ }
483
+
484
+ function markLoopBody(nodes, start, filename) {
485
+ var nextNodeId = start.one
486
+ while (nextNodeId) {
487
+ var current = nodes[nextNodeId]
488
+ nextNodeId = current.one
489
+ current.parentLoopId = start.id
490
+ if (current.type === "loopbegin") {
491
+ nextNodeId = markLoopBody(nodes, current, filename)
492
+ } else if (current.type === "loopend") {
493
+ start.end = current.id
494
+ start.next = current.one
495
+ current.start = start.id
496
+ return nextNodeId
497
+ }
498
+ }
499
+ throw createError(translate("Loop end expected here"), filename, start.one)
500
+ }
501
+
502
+ module.exports = { drakonToStruct, drakonToGraph };
503
+ },{"./structFlow":6,"./tools":8}],4:[function(require,module,exports){
504
+ const { drakonToPseudocode } = require('./drakonToPromptStruct');
505
+ const {htmlToString} = require("./browserTools")
506
+ const { setUpLanguage, translate } = require("./translate")
507
+ const {drakonToStruct} = require("./drakonToStruct");
508
+
509
+
510
+ window.toPseudocode = function(drakonJson, name, filename, language) {
511
+ setUpLanguage(language)
512
+ return drakonToPseudocode(drakonJson, name, filename, htmlToString, translate).text
513
+ }
514
+
515
+ window.toTree = function(drakonJson, name, filename, language) {
516
+ setUpLanguage(language)
517
+ var result = drakonToStruct(drakonJson, name, filename, translate)
518
+ return JSON.stringify(result, null, 4)
519
+ }
520
+ },{"./browserTools":1,"./drakonToPromptStruct":2,"./drakonToStruct":3,"./translate":9}],5:[function(require,module,exports){
521
+ var {addRange} = require("./tools")
522
+
523
+ function printPseudo(algorithm, translate, output, htmlToString) {
524
+
525
+
526
+
527
+ function printStructuredContent(content, indent, output) {
528
+ var lines = printStructuredContentNoIdent(content)
529
+ printWithIndent(lines, indent, output)
530
+ }
531
+
532
+ function printWithIndent(lines, indent, output) {
533
+ lines.forEach(line => output.push(indent + line))
534
+ }
535
+
536
+ function printStructuredContentNoIdent(content) {
537
+ var lines = []
538
+
539
+ if (typeof content === "string") {
540
+ return htmlToString(content);
541
+ } else if (content.operator === "not") {
542
+ lines = printStructuredContentNoIdent(content.operand)
543
+ if (lines.length > 0) {
544
+ lines[0] = translate("not") + " (" + lines[0] + ")"
545
+ }
546
+ } else if (content.operator === "and" || content.operator === "or") {
547
+ var operator = translate(content.operator)
548
+ printBinary(content, operator, lines)
549
+ } else if (content.operator === "equal") {
550
+ var operator = "=="
551
+ printBinary(content, operator, lines)
552
+ }
553
+
554
+ return lines;
555
+ }
556
+
557
+ function printBinary(content, operator, lines) {
558
+ const leftLines = printOperand(content.left);
559
+ const rightLines = printOperand(content.right);
560
+ if (leftLines.length === 1 && rightLines.length === 1) {
561
+ lines.push(leftLines[0] + " " + operator + " " + rightLines[0])
562
+ } else {
563
+ addRange(lines, leftLines)
564
+ lines.push(operator);
565
+ addRange(lines, rightLines)
566
+ }
567
+ }
568
+
569
+ function printOperand(content) {
570
+ var lines = printStructuredContentNoIdent(content)
571
+ if (typeof content === "string" || content.operator === "not") {
572
+ return lines
573
+ }
574
+ if (lines.length > 0) {
575
+ lines[0] = "(" + lines[0]
576
+ last = lines.length - 1
577
+ lines[last] = lines[last] + ")"
578
+ }
579
+ return lines
580
+ }
581
+
582
+ function makeIndent(depth) {
583
+ return " ".repeat(depth * 4);
584
+ }
585
+
586
+ function printSteps(steps, depth, output) {
587
+ const indent = makeIndent(depth)
588
+ for (var step of steps) {
589
+ if (step.type === "end" || step.type === "branch" || step.type === "comment") { continue }
590
+ if (step.type === "question") {
591
+ printQuestion(step, depth, output)
592
+ } else if (step.type === "loop") {
593
+ printLoop(step, depth, output)
594
+ } else if (step.type === "address") {
595
+ printAddress(step, indent, output)
596
+ } else if (step.type === "error") {
597
+ printError(step, indent, output)
598
+ } else if (step.type === "break") {
599
+ output.push(indent + translate("break"))
600
+ } else {
601
+ printOther(step, indent, output)
602
+ }
603
+ }
604
+ }
605
+
606
+ function printOther(step, indent, output) {
607
+ if (!step.content && !step.secondary) {return}
608
+ if (step.secondary) {
609
+ printStructuredContent(step.secondary, indent, output)
610
+ }
611
+ if (step.content) {
612
+ printStructuredContent(step.content, indent, output)
613
+ }
614
+ output.push("")
615
+ }
616
+
617
+ function printAddress(step, indent, output) {
618
+ var label
619
+ if (step.content) {
620
+ label = htmlToString(step.content);
621
+ } else {
622
+ label = translate("Subroutine") + " " + step.branch
623
+ }
624
+ output.push(indent + translate("Call subroutine") + " \"" + label + "\"")
625
+ }
626
+
627
+ function printError(step, indent, output) {
628
+ output.push(indent + translate("error") + ":")
629
+ output.push(indent + step.message)
630
+ if (step.content) {
631
+ printStructuredContent(step.content, indent, output)
632
+ }
633
+ output.push("")
634
+ }
635
+
636
+ function empty(array) {
637
+ return array.length === 0
638
+ }
639
+
640
+ function printQuestion(step, depth, output) {
641
+ const indent = makeIndent(depth)
642
+ const indent2 = makeIndent(depth + 1)
643
+ var yesBody = []
644
+ printSteps(step.yes, depth + 1, yesBody)
645
+ var noBody = []
646
+ printSteps(step.no, depth + 1, noBody)
647
+ if (empty(yesBody) && empty(noBody)) {
648
+ yesBody.push(indent2 + translate("pass"))
649
+ }
650
+ var content = step.content
651
+ if (empty(yesBody)) {
652
+ content = {operator:"not",operand:step.content}
653
+ }
654
+ var lines = printStructuredContentNoIdent(content)
655
+ lines[0] = translate("if") + " " + lines[0]
656
+ printWithIndent(lines, indent, output)
657
+ if (empty(yesBody)) {
658
+ addRange(output, noBody)
659
+ } else {
660
+ addRange(output, yesBody)
661
+ if (!empty(noBody)) {
662
+ output.push(indent + translate("else"))
663
+ addRange(output, noBody)
664
+ }
665
+ }
666
+ }
667
+
668
+ function printLoop(step, depth, output) {
669
+ const indent2 = makeIndent(depth + 1)
670
+ const indent = makeIndent(depth)
671
+ var body = []
672
+ printSteps(step.body, depth + 1, body)
673
+ if (empty(body)) {
674
+ body.push(indent2 + translate("pass"))
675
+ }
676
+ var content = step.content
677
+ if (!content) {
678
+ content = translate("loop forever")
679
+ }
680
+ printStructuredContent(content, indent, output)
681
+ addRange(output, body)
682
+ }
683
+
684
+ printSteps(algorithm.body, 0, output)
685
+ }
686
+
687
+ module.exports = {printPseudo}
688
+ },{"./tools":8}],6:[function(require,module,exports){
689
+ var {buildTree} = require("./technicalTree")
690
+ const { createError, sortByProperty } = require("./tools");
691
+
692
+ function redirectNode(nodes, node, from, to) {
693
+ if (node.one === from) {
694
+ node.one = to;
695
+ }
696
+ if (node.two === from) {
697
+ node.two = to;
698
+ }
699
+ if (node.next === from) {
700
+ node.next = to
701
+ }
702
+ if (node.start && node.type === "loopend") {
703
+ start = nodes[node.start]
704
+ if (start.next === from) {
705
+ start.next = to
706
+ }
707
+ }
708
+ }
709
+
710
+ function structFlow(nodes, branches, filename, translate) {
711
+
712
+
713
+
714
+ function flowGraph(nodes, nodeId, branchingStack) {
715
+ if (!nodeId) {return;}
716
+
717
+ const node = nodes[nodeId];
718
+
719
+ if (!node.stack) {
720
+ node.stack = [];
721
+ node.remaining = node.prev.length;
722
+ }
723
+ node.remaining--;
724
+
725
+ mergeBranchingStack(nodes, node, branchingStack);
726
+ if (node.remaining > 0) {return;}
727
+
728
+ if (node.type === "question") {
729
+ for (let i = 0; i < node.stack.length; i++) {
730
+ const questionId = node.stack[i];
731
+ const question = nodes[questionId];
732
+ question.branching++;
733
+ }
734
+
735
+ const stackOne = node.stack.slice();
736
+ const stackTwo = node.stack.slice();
737
+ stackOne.push(nodeId);
738
+ stackTwo.push(nodeId);
739
+
740
+ flowGraph(nodes, node.two, stackTwo);
741
+ flowGraph(nodes, node.one, stackOne);
742
+ } else if (node.type === "arrow-loop") {
743
+ const stackOne = node.stack.slice();
744
+ stackOne.push(nodeId);
745
+ flowGraph(nodes, node.one, stackOne);
746
+ } else if (node.type === "arrow-stub") {
747
+ decrementBranchingForArrow(nodes, node)
748
+ } else {
749
+ flowGraph(nodes, node.one, node.stack);
750
+ }
751
+ }
752
+
753
+ function decrementBranchingForArrow(nodes, node) {
754
+ var algonode = nodes[node.arrow]
755
+ algonode.branching--
756
+ }
757
+
758
+ function decrementQuestions(nodes, algonode, dictionary) {
759
+ var stub = nodes[algonode.stub]
760
+ for (var id of stub.stack) {
761
+ var snode = nodes[id]
762
+ if (id != algonode) {
763
+ if (id in dictionary) {
764
+ snode.branching--
765
+ }
766
+ }
767
+ }
768
+ return stub
769
+ }
770
+
771
+
772
+
773
+ function mergeBranchingStack(nodes, node, branchingStack) {
774
+ // Append all elements of the branching stack to node.stack
775
+ addRange(node.stack, branchingStack)
776
+
777
+ // Build a dictionary of occurrences
778
+ const dictionary = buildDictionaryOfOccurences(node);
779
+
780
+ // Merge all nodes
781
+ mergeAll(nodes, node, dictionary);
782
+
783
+ // Rebuild the stack
784
+ node.stack = buildStackFromDictionary(dictionary);
785
+ }
786
+
787
+ function addRange(dst, src) {
788
+ for (let i = 0; i < src.length; i++) {
789
+ dst.push(src[i]);
790
+ }
791
+ }
792
+
793
+ function buildStackFromDictionary(dictionary) {
794
+ const rebuiltStack = [];
795
+ for (const id in dictionary) {
796
+ if (dictionary[id] > 0) {
797
+ rebuiltStack.push(id);
798
+ }
799
+ }
800
+ return rebuiltStack;
801
+ }
802
+
803
+ function buildDictionaryOfOccurences(node) {
804
+ const dictionary = {};
805
+ for (let i = 0; i < node.stack.length; i++) {
806
+ const id = node.stack[i];
807
+ dictionary[id] = (dictionary[id] || 0) + 1;
808
+ }
809
+ return dictionary;
810
+ }
811
+
812
+ function mergeAll(nodes, node, dictionary) {
813
+ for (const id in dictionary) {
814
+ const occurrences = dictionary[id];
815
+ const algonode = nodes[id];
816
+ if (occurrences > 1) {
817
+ algonode.branching--;
818
+ dictionary[id] = occurrences - 1;
819
+ }
820
+ if (algonode.branching === 1) {
821
+ if (algonode.type === "arrow-loop" && !algonode.next) {
822
+ if (!isInMap(node.astack, id)) {
823
+ algonode.next = node.id
824
+ dictionary[algonode.id] = 0;
825
+ var stub = decrementQuestions(nodes, algonode, dictionary)
826
+ stub.one = node.id
827
+ }
828
+ }
829
+ }
830
+ }
831
+
832
+ for (const id in dictionary) {
833
+ const algonode = nodes[id];
834
+ if (algonode.branching === 1) {
835
+ if (algonode.type === "question") {
836
+ algonode.next = node.id;
837
+ dictionary[algonode.id] = 0;
838
+ }
839
+ }
840
+ }
841
+ }
842
+ function isInMap(map, key) {
843
+ if (!map) { return false }
844
+ return key in map
845
+ }
846
+
847
+ function prepareQuestions(nodes) {
848
+ for (const nodeId in nodes) {
849
+ const node = nodes[nodeId];
850
+ if (node.type === "question") {
851
+ node.branching = 2;
852
+ } else if (node.type === "arrow-loop") {
853
+ node.branching = 1;
854
+ }
855
+ }
856
+ }
857
+
858
+ function rewireArrows(nodes, branches) {
859
+ branches.forEach(branch => rewireArrowsInBranch(nodes, branch.id, branch.next, []))
860
+ for (var id in nodes) {
861
+ var node = nodes[id]
862
+ if (node.type === "arrow-loop") {
863
+ var stub = insertArrowStub(nodes, node)
864
+ fillAStack(nodes, stub, stub.arrow)
865
+ }
866
+ }
867
+ }
868
+
869
+ function fillAStack(nodes, node, arrowId) {
870
+ if (!node.astack) {
871
+ node.astack = {}
872
+ }
873
+ node.astack[arrowId] = true
874
+ if (node.id === arrowId) {
875
+ return
876
+ }
877
+ for (var prevId of node.prev) {
878
+ var prev = nodes[prevId]
879
+ fillAStack(nodes, prev, arrowId)
880
+ }
881
+ }
882
+
883
+ function rewireArrowsInBranch(nodes, prevNodeId, nodeId, arrowStack) {
884
+ if (!nodeId) {return}
885
+ var node = nodes[nodeId]
886
+ if (node.type === "branch") {
887
+ return
888
+ }
889
+ if (node.type === "arrow-loop") {
890
+ if (!node.noloop) {
891
+ node.noloop = {}
892
+ }
893
+ if (arrowStack.includes(nodeId)) {
894
+ return
895
+ }
896
+ node.noloop[prevNodeId] = true
897
+ arrowStack = arrowStack.slice()
898
+ arrowStack.push(nodeId)
899
+ rewireArrowsInBranch(nodes, nodeId, node.one, arrowStack)
900
+ } else if (node.type === "question") {
901
+ var left = arrowStack.slice()
902
+ var right = arrowStack.slice()
903
+ rewireArrowsInBranch(nodes, nodeId, node.one, left)
904
+ rewireArrowsInBranch(nodes, nodeId, node.two, right)
905
+ } else {
906
+ rewireArrowsInBranch(nodes, nodeId, node.one, arrowStack)
907
+ }
908
+ }
909
+
910
+ function insertArrowStub(nodes, node) {
911
+ var stub = {
912
+ type: "arrow-stub",
913
+ id: "arrow-stub-" + node.id,
914
+ arrow: node.id,
915
+ prev: []
916
+ }
917
+ nodes[stub.id] = stub
918
+ node.stub = stub.id
919
+ var prev2 = []
920
+ for (var prevId of node.prev) {
921
+ if (prevId in node.noloop) {
922
+ prev2.push(prevId)
923
+ } else {
924
+ stub.prev.push(prevId)
925
+ var prev = nodes[prevId]
926
+ redirectNode(nodes, prev, node.id, stub.id)
927
+ }
928
+ }
929
+ node.prev = prev2
930
+ return stub
931
+ }
932
+
933
+ function rewriteTree(body, index, endId, output) {
934
+ while (index < body.length) {
935
+ var node = body[index]
936
+ index++
937
+ if (endId && node.id === endId) {
938
+ return index
939
+ }
940
+ if (node.type === "question") {
941
+ var transformed = rewriteQuestionTree(node, output)
942
+ if (endId) {
943
+ var breakYes = findLoopEnd(transformed.yes, endId)
944
+ var breakNo = findLoopEnd(transformed.no, endId)
945
+ if (breakYes || breakNo) {
946
+ var toBreak = []
947
+ findPlacesToBreak(transformed.yes, endId, toBreak)
948
+ findPlacesToBreak(transformed.no, endId, toBreak)
949
+ addBreaks(toBreak)
950
+ return index
951
+ }
952
+ }
953
+ } else if (node.type === "loopbegin") {
954
+ var body2 = []
955
+ index = rewriteTree(body, index, node.end, body2)
956
+ output.push({
957
+ id: node.id,
958
+ type: "loop",
959
+ content: node.content,
960
+ body: body2
961
+ })
962
+ } else {
963
+ output.push(node)
964
+ }
965
+ }
966
+ }
967
+
968
+ function findPlacesToBreak(body, endId, output) {
969
+ if (body.length === 0) {
970
+ output.push(body)
971
+ return
972
+ }
973
+ var last = body[body.length - 1]
974
+ if (last.id === endId) {
975
+ return
976
+ }
977
+ if (last.type === "question") {
978
+ var qends = []
979
+ findPlacesToBreak(last.yes, endId, qends)
980
+ findPlacesToBreak(last.no, endId, qends)
981
+ if (qends.length === 2
982
+ && qends[0] === last.yes
983
+ && qends[1] === last.no) {
984
+ output.push(body)
985
+ } else {
986
+ addRange(output, qends)
987
+ }
988
+ } else {
989
+ output.push(body)
990
+ }
991
+ }
992
+
993
+ function findLoopEnd(body, endId) {
994
+ for (var i = 0; i < body.length; i++) {
995
+ var node = body[i]
996
+ if (node.id === endId) {
997
+ if (i === body.length - 1) {
998
+ return true
999
+ } else {
1000
+ throw createError(
1001
+ translate("An exit from the loop must lead to the point right after the loop end"),
1002
+ filename,
1003
+ node.id
1004
+ );
1005
+ }
1006
+ }
1007
+ if (node.type === "question") {
1008
+ if (findLoopEnd(node.yes, endId)) {
1009
+ return true
1010
+ }
1011
+ if (findLoopEnd(node.no, endId)) {
1012
+ return true
1013
+ }
1014
+ }
1015
+ }
1016
+ return false
1017
+ }
1018
+
1019
+ function addBreaks(toBreak) {
1020
+ for (var body of toBreak) {
1021
+ body.push({
1022
+ type: "break"
1023
+ })
1024
+ }
1025
+ }
1026
+
1027
+ function rewriteQuestionTree(question, output) {
1028
+ var yes = []
1029
+ var no = []
1030
+ rewriteTree(question.yes, 0, undefined, yes)
1031
+ rewriteTree(question.no, 0, undefined, no)
1032
+ var transformed = {
1033
+ type: "question",
1034
+ id: question.id,
1035
+ content: question.content,
1036
+ yes: yes,
1037
+ no: no
1038
+ }
1039
+ output.push(transformed)
1040
+ return transformed
1041
+ }
1042
+
1043
+
1044
+ function structMain() {
1045
+ rewireArrows(nodes, branches)
1046
+ prepareQuestions(nodes)
1047
+ var result = []
1048
+ for (var branch of branches) {
1049
+ flowGraph(nodes, branch.next, [])
1050
+ }
1051
+
1052
+ for (var branch of branches) {
1053
+ var body = []
1054
+ buildTree(nodes, branch.next, body, "<dummy id>")
1055
+ var body2 = []
1056
+ rewriteTree(body, 0, undefined, body2)
1057
+ result.push({
1058
+ name: branch.content,
1059
+ branchId: branch.branchId,
1060
+ start: branch.next,
1061
+ body: body2
1062
+ })
1063
+ }
1064
+
1065
+ return sortByProperty(result, "branchId")
1066
+ }
1067
+
1068
+ return structMain()
1069
+ }
1070
+ module.exports = { structFlow, redirectNode };
1071
+ },{"./technicalTree":7,"./tools":8}],7:[function(require,module,exports){
1072
+ function buildTree(nodes, nodeId, body, stopId) {
1073
+ while (nodeId) {
1074
+ if (nodeId === stopId) {return;}
1075
+ const node = nodes[nodeId];
1076
+ let transformed;
1077
+ let next;
1078
+
1079
+ if (node.type === "question") {
1080
+ next = reserveNext(nodes, node)
1081
+
1082
+ transformed = {
1083
+ id: node.id,
1084
+ type: "question",
1085
+ content: node.content || "",
1086
+ yes: [],
1087
+ no: []
1088
+ };
1089
+
1090
+ const yesNodeId = node.flag1 === 1 ? node.one : node.two;
1091
+ const noNodeId = node.flag1 === 1 ? node.two : node.one;
1092
+
1093
+ buildTree(nodes, yesNodeId, transformed.yes, node.next);
1094
+ buildTree(nodes, noNodeId, transformed.no, node.next);
1095
+ } else if (node.type === "arrow-loop") {
1096
+ transformed = {
1097
+ id: node.id,
1098
+ type: "loopbegin",
1099
+ content: "",
1100
+ end: node.stub
1101
+ };
1102
+
1103
+ next = node.one;
1104
+ } else if (node.type === "arrow-stub") {
1105
+ transformed = {
1106
+ id: node.id,
1107
+ type: "loopend",
1108
+ start: node.arrow
1109
+ };
1110
+
1111
+ next = node.one;
1112
+ } else {
1113
+ transformed = {
1114
+ id: node.id,
1115
+ type: node.type,
1116
+ }
1117
+ copyFields(
1118
+ transformed,
1119
+ node,
1120
+ [
1121
+ "content",
1122
+ "secondary",
1123
+ "start",
1124
+ "message",
1125
+ "end"
1126
+ ]
1127
+ )
1128
+ next = node.one;
1129
+ }
1130
+
1131
+ body.push(transformed);
1132
+ nodeId = next;
1133
+ }
1134
+ }
1135
+
1136
+ function copyFields(dst, src, fields) {
1137
+ for (var field of fields) {
1138
+ var value = src[field]
1139
+ if (value !== "" && value !== undefined && value !== null) {
1140
+ dst[field] = value
1141
+ }
1142
+ }
1143
+ }
1144
+
1145
+ function reserveNext(nodes, node) {
1146
+ const target = nodes[node.next];
1147
+ if (target.targetTaken) {
1148
+ return undefined;
1149
+ } else {
1150
+ target.targetTaken = true;
1151
+ return node.next;
1152
+ }
1153
+ }
1154
+
1155
+ module.exports = {buildTree}
1156
+
1157
+ },{}],8:[function(require,module,exports){
1158
+
1159
+ function createError(message, filename, nodeId) {
1160
+ var error = new Error(message)
1161
+ error.nodeId = nodeId
1162
+ error.filename = filename
1163
+ return error
1164
+ }
1165
+
1166
+ function sortByProperty(array, property, order = "asc") {
1167
+ if (!Array.isArray(array)) {
1168
+ throw new Error("First argument must be an array");
1169
+ }
1170
+
1171
+ return array.slice().sort((a, b) => {
1172
+ const valA = a[property];
1173
+ const valB = b[property];
1174
+
1175
+ if (valA === null || valB === null || valA === undefined || valB === undefined) {
1176
+ return 0; // Handle null or undefined values
1177
+ }
1178
+
1179
+ if (valA < valB) {
1180
+ return order === "asc" ? -1 : 1;
1181
+ }
1182
+ if (valA > valB) {
1183
+ return order === "asc" ? 1 : -1;
1184
+ }
1185
+ return 0; // Values are equal
1186
+ });
1187
+ }
1188
+ function addRange(to, from) {
1189
+ for (var item of from) {
1190
+ to.push(item)
1191
+ }
1192
+ }
1193
+ module.exports = { createError, sortByProperty, addRange }
1194
+ },{}],9:[function(require,module,exports){
1195
+ var translationsRu = {
1196
+ "error": "ОШИБКА",
1197
+ "not": "не",
1198
+ break: 'выход из цикла',
1199
+ "and": "и",
1200
+ "or": "или",
1201
+ "if": "Если",
1202
+ "else": "Иначе",
1203
+ "empty": "ПУСТОЙ",
1204
+ "loop forever": "Бесконечный цикл",
1205
+ "pass": "Пропустить",
1206
+ "Only the rightmost Case icon can be empty": "Только самая правая икона Вариант может быть пустой",
1207
+ "Error parsing JSON": "Ошибка парсинга JSON",
1208
+ "A Loop begin icon must have content": "Икона начала цикла ДЛЯ должна содержать данные",
1209
+ "A Question icon must have content": "Икона Вопрос должна содержать данные",
1210
+ "A Select icon must have content": "Икона Выбор должна содержать данные",
1211
+ "Loop end expected here": "Здесь ожидается конец цикла",
1212
+ "An exit from the loop must lead to the point right after the loop end": "Выход из цикла должен вести в точку сразу за его концом",
1213
+ "A silhouette branch is not referenced": "Нет ссылок на ветку силуэта",
1214
+ "Call subroutine": "Вызвать подпрограмму",
1215
+ "Procedure": "Процедура",
1216
+ "End of procedure": "Конец процедуры",
1217
+ "Subroutine": "Подпрограмма",
1218
+ "End of subroutine": "Конец подпрограммы",
1219
+ "Description": "Описание",
1220
+ "Algorithm": "Алгоритм",
1221
+ Remarks: "Замечания"
1222
+ }
1223
+
1224
+ var translationsEn = {
1225
+ error: 'Error',
1226
+ not: 'not',
1227
+ break: 'break',
1228
+ and: 'and',
1229
+ or: 'or',
1230
+ if: 'If',
1231
+ else: 'Else',
1232
+ empty: 'Empty',
1233
+ 'loop forever': 'Loop forever',
1234
+ pass: 'Pass',
1235
+ 'Only the rightmost Case icon can be empty': 'Only the rightmost Case icon can be empty',
1236
+ 'Error parsing JSON': 'Error parsing JSON',
1237
+ 'A Loop begin icon must have content': 'A Loop begin icon must have content',
1238
+ 'A Question icon must have content': 'A Question icon must have content',
1239
+ 'A Select icon must have content': 'A Select icon must have content',
1240
+ 'Loop end expected here': 'Loop end expected here',
1241
+ 'An exit from the loop must lead to the point right after the loop end': 'An exit from the loop must lead to the point right after the loop end',
1242
+ 'A silhouette branch is not referenced': 'A silhouette branch is not referenced',
1243
+ 'Call subroutine': 'Call subroutine',
1244
+ Procedure: 'Procedure',
1245
+ 'End of procedure': 'End of procedure',
1246
+ Subroutine: 'Subroutine',
1247
+ 'End of subroutine': 'End of subroutine',
1248
+ Description: 'Description',
1249
+ Algorithm: 'Algorithm',
1250
+ Remarks: "Remarks"
1251
+ }
1252
+
1253
+ var translationsNo = {
1254
+ error: 'Feil',
1255
+ not: 'ikke',
1256
+ break: 'avslutt løkken',
1257
+ and: 'og',
1258
+ or: 'eller',
1259
+ if: 'Hvis',
1260
+ else: 'Ellers',
1261
+ empty: 'Tom',
1262
+ 'loop forever': 'Gjør evig',
1263
+ pass: 'Hopp over',
1264
+ 'Only the rightmost Case icon can be empty': 'Bare den ytterste høyre Case-ikonet kan være tomt',
1265
+ 'Error parsing JSON': 'Feil ved parsing av JSON',
1266
+ 'A Loop begin icon must have content': 'Et Loop-startikon må ha innhold',
1267
+ 'A Question icon must have content': 'Et Spørsmål-ikon må ha innhold',
1268
+ 'A Select icon must have content': 'Et Velg-ikon må ha innhold',
1269
+ 'Loop end expected here': 'Slutt på løkke forventet her',
1270
+ 'An exit from the loop must lead to the point right after the loop end': 'En utgang fra løkken må føre til punktet rett etter løkkens slutt',
1271
+ 'A silhouette branch is not referenced': 'En silhuettgren er ikke referert',
1272
+ 'Call subroutine': 'Kall delprosedyre',
1273
+ Procedure: 'Prosedyre',
1274
+ 'End of procedure': 'Slutt på prosedyre',
1275
+ Subroutine: 'Delprosedyre',
1276
+ 'End of subroutine': 'Slutt på delprosedyre',
1277
+ Description: 'Beskrivelse',
1278
+ Algorithm: 'Algoritme',
1279
+ Remarks: "Bemerkninger"
1280
+ };
1281
+
1282
+
1283
+ var translations = translationsEn
1284
+
1285
+ function translate(text) {
1286
+ return translations[text] || text;
1287
+ }
1288
+
1289
+ function setUpLanguage(language) {
1290
+ if (language === "ru") {
1291
+ translations = translationsRu
1292
+ } else if (language === "no") {
1293
+ translations = translationsNo
1294
+ } else if (language === "en") {
1295
+ translations = translationsEn
1296
+ } else {
1297
+ translations = {}
1298
+ }
1299
+ }
1300
+
1301
+
1302
+ module.exports = { setUpLanguage, translate };
1303
+ },{}]},{},[4]);