drakongen 1.4.7 → 1.9.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/browser/drakongen.js +959 -469
- package/browsertest.html +20 -5
- package/buildexamples.js +41 -4
- package/exampleproject/foo.txt +2 -0
- package/examples/20. /320/227/320/276/320/273/320/276/321/202/320/276/320/271 - /320/273/320/265/320/262/321/213/320/271 final.drakon" +66 -0
- package/examples/21. /320/227/320/276/320/273/320/276/321/202/320/276/320/271 - /320/277/321/200/320/260/320/262/321/213/320/271 final.drakon" +66 -0
- package/examples/BugBadExit.drakon +69 -0
- package/examples/BugBadExit.txt +16 -0
- package/examples/Complex arrow-parallel.drakon +116 -0
- package/examples/Complex arrow-parallel.txt +40 -0
- package/examples/Complex arrow.txt +1 -0
- package/examples/How to tune PID on a quadcopter.txt +1 -0
- package/examples/NestedArrowLoop.drakon +38 -0
- package/examples/NestedArrowLoop.txt +20 -0
- package/examples/Workout foreach.drakon +7 -2
- package/examples/Workout foreach.txt +1 -0
- package/examples/all icons.drakon +227 -0
- package/examples/all icons.txt +68 -0
- package/examples/ar01-action.drakon +31 -0
- package/examples/ar01-action.txt +9 -0
- package/examples/ar10-parallel.drakon +70 -0
- package/examples/ar10-parallel.txt +20 -0
- package/examples/badShortCircuit.drakon +34 -0
- package/examples/badShortCircuit.txt +7 -0
- package/examples/getToken.txt +2 -0
- package/examples/monitorPaymentStatus.drakon +56 -0
- package/examples/monitorPaymentStatus.txt +25 -0
- package/examples/no-loop/00.Empty.txt +6 -0
- package/examples/no-loop/01. /320/221/320/265/320/273/321/213/320/271.txt" +5 -0
- package/examples/no-loop/02. /320/247/321/221/321/200/320/275/321/213/320/271.txt" +8 -0
- package/examples/no-loop/03. /320/241/320/265/321/200/321/213/320/271.txt" +7 -0
- package/examples/no-loop/04. /320/221/321/203/321/200/321/213/320/271.txt" +7 -0
- package/examples/no-loop/05. /320/226/321/221/320/273/321/202/321/213/320/271.txt" +7 -0
- package/examples/no-loop/06. /320/221/320/260/320/263/321/200/320/276/320/262/321/213/320/271.txt" +9 -0
- package/examples/no-loop/07. /320/244/320/270/320/276/320/273/320/265/321/202/320/276/320/262/321/213/320/271.txt" +12 -0
- package/examples/no-loop/08. /320/221/320/270/321/200/321/216/320/267/320/276/320/262/321/213/320/271.txt" +7 -0
- package/examples/no-loop/09. /320/236/321/200/320/260/320/275/320/266/320/265/320/262/321/213/320/271.txt" +9 -0
- package/examples/no-loop/10. /320/240/320/276/320/267/320/276/320/262/321/213/320/271.txt" +13 -0
- package/examples/no-loop/11. /320/227/320/260/321/211/320/270/321/202/320/275/321/213/320/271.txt" +9 -0
- package/examples/no-loop/12. /320/221/320/276/320/273/320/276/321/202/320/275/321/213/320/271.txt" +9 -0
- package/examples/no-loop/13. /320/241/320/260/320/273/320/260/321/202/320/276/320/262/321/213/320/271.txt" +15 -0
- package/examples/no-loop/14. /320/227/320/276/320/273/320/276/321/202/320/276/320/271.txt" +17 -0
- package/examples/no-loop/15. /320/241/320/270/320/275/320/270/320/271.txt" +20 -0
- package/examples/no-loop/16. /320/223/320/276/320/273/321/203/320/261/320/276/320/271.txt" +11 -0
- package/examples/no-loop/17. /320/241/320/260/320/273/320/260/321/202/320/276/320/262/321/213/320/271.txt" +10 -0
- package/examples/no-loop/18. /320/241/321/202/320/260/320/273/321/214/320/275/320/276/320/271.txt" +15 -0
- package/examples/no-loop/19. Lilla.txt +11 -0
- package/examples/no-loop/20. /320/227/320/276/320/273/320/276/321/202/320/276/320/271 - /320/273/320/265/320/262/321/213/320/271 final.txt" +17 -0
- package/examples/no-loop/21. /320/227/320/276/320/273/320/276/321/202/320/276/320/271 - /320/277/321/200/320/260/320/262/321/213/320/271 final.txt" +16 -0
- package/examples/no-loop/Adaptive design.txt +31 -0
- package/examples/no-loop/And test.txt +9 -0
- package/examples/no-loop/Arrow - double exit.txt +13 -0
- package/examples/no-loop/BugBadExit.txt +16 -0
- package/examples/no-loop/Comments.txt +19 -0
- package/examples/no-loop/Complex arrow-parallel.txt +40 -0
- package/examples/no-loop/Complex arrow.txt +37 -0
- package/examples/no-loop/DoubleArrow.txt +17 -0
- package/examples/no-loop/Find pointing nodes.txt +24 -0
- package/examples/no-loop/How to tune PID on a quadcopter.txt +145 -0
- package/examples/no-loop/Logical_And.txt +9 -0
- package/examples/no-loop/Logical_And_Inv.txt +9 -0
- package/examples/no-loop/Logical_And_Inv_x2.txt +15 -0
- package/examples/no-loop/Logical_Or.txt +9 -0
- package/examples/no-loop/Logical_Or_Inv.txt +9 -0
- package/examples/no-loop/Mind one.txt +18 -0
- package/examples/no-loop/NestedArrowLoop.txt +20 -0
- package/examples/no-loop/Or test.txt +9 -0
- package/examples/no-loop/Silhouette test 1.txt +31 -0
- package/examples/no-loop/Work out action-check.txt +9 -0
- package/examples/no-loop/Workout foreach.txt +13 -0
- package/examples/no-loop/all icons.txt +68 -0
- package/examples/no-loop/ar01-action.txt +9 -0
- package/examples/no-loop/ar01.txt +8 -0
- package/examples/no-loop/ar02.txt +10 -0
- package/examples/no-loop/ar03.txt +8 -0
- package/examples/no-loop/ar04.txt +10 -0
- package/examples/no-loop/ar05.txt +11 -0
- package/examples/no-loop/ar06.txt +13 -0
- package/examples/no-loop/ar07.txt +13 -0
- package/examples/no-loop/ar08.txt +16 -0
- package/examples/no-loop/ar09.txt +16 -0
- package/examples/no-loop/ar10-parallel.txt +20 -0
- package/examples/no-loop/ar10.txt +17 -0
- package/examples/no-loop/ar11.txt +17 -0
- package/examples/no-loop/ar12.txt +10 -0
- package/examples/no-loop/badShortCircuit.txt +7 -0
- package/examples/no-loop/getToken.txt +34 -0
- package/examples/no-loop/monitorPaymentStatus.txt +25 -0
- package/examples/no-loop/parallel-3.txt +12 -0
- package/examples/no-loop/parallel-arrow-loop.txt +12 -0
- package/examples/no-loop/parallel-empty-nested.txt +11 -0
- package/examples/no-loop/parallel-empty.txt +8 -0
- package/examples/no-loop/parallel-nested.txt +16 -0
- package/examples/no-loop/sil2.txt +29 -0
- package/examples/no-loop/tmp.txt +35 -0
- package/examples/no-loop//320/241/320/265/320/274/320/260/320/275/321/202/320/270/321/207/320/265/321/201/320/272/320/276/320/265 /321/217/320/264/321/200/320/276.txt" +36 -0
- package/examples/parallel-3.drakon +49 -0
- package/examples/parallel-3.txt +12 -0
- package/examples/parallel-arrow-loop.drakon +44 -0
- package/examples/parallel-arrow-loop.txt +12 -0
- package/examples/parallel-empty-nested.drakon +40 -0
- package/examples/parallel-empty-nested.txt +11 -0
- package/examples/parallel-empty.drakon +27 -0
- package/examples/parallel-empty.txt +8 -0
- package/examples/parallel-nested.drakon +67 -0
- package/examples/parallel-nested.txt +16 -0
- package/examples/sil2.txt +1 -0
- package/examples/tmp.txt +2 -0
- package/examples//320/241/320/265/320/274/320/260/320/275/321/202/320/270/321/207/320/265/321/201/320/272/320/276/320/265 /321/217/320/264/321/200/320/276.free" +130 -0
- package/examples//320/241/320/265/320/274/320/260/320/275/321/202/320/270/321/207/320/265/321/201/320/272/320/276/320/265 /321/217/320/264/321/200/320/276.txt" +36 -0
- package/package.json +1 -1
- package/secondary/Secondary.drakon +72 -0
- package/src/browserTools.js +1 -1
- package/src/drakonToPromptStruct.js +41 -15
- package/src/drakonToStruct.js +198 -26
- package/src/drakongen.js +50 -19
- package/src/free.js +69 -0
- package/src/index.js +48 -15
- package/src/main.js +12 -3
- package/src/nodeTools.js +1 -1
- package/src/noloop/flow_no_loop.drakon +33 -0
- package/src/noloop/noloop.dtproj +6 -0
- package/src/noloop/private/decrement_arrow_count.drakon +1 -0
- package/src/noloop/private/decrement_if_count.drakon +33 -0
- package/src/noloop/private/group_stack_by_id.drakon +63 -0
- package/src/noloop/private/increment_if_count.drakon +33 -0
- package/src/noloop/private/is_in_map.drakon +1 -0
- package/src/noloop/private/merge_converging_branches.drakon +186 -0
- package/src/noloop/private/recurse_traversal.drakon +152 -0
- package/src/noloop/private/traverse_node.drakon +69 -0
- package/src/noloop.js +135 -0
- package/src/printPseudo.js +29 -3
- package/src/structFlow.js +155 -378
- package/src/technicalTree.js +60 -13
- package/src/translate.js +176 -4
- package/src/treeTools.js +59 -28
- package/test_secondary.js +14 -0
- package/.vscode/launch.json +0 -18
- package/exampleproject/.drakontech/history.json +0 -12
- package/exampleproject/.drakontech/opened.txt +0 -1
- package/examples/.drakontech/history.json +0 -124
- package/examples/.drakontech/opened.txt +0 -1
package/browser/drakongen.js
CHANGED
|
@@ -14,7 +14,7 @@ function htmlToString(html) {
|
|
|
14
14
|
|
|
15
15
|
root.childNodes.forEach((node) => {
|
|
16
16
|
if (node.tagName === 'P') {
|
|
17
|
-
output.push(node.textContent
|
|
17
|
+
output.push(node.textContent);
|
|
18
18
|
} else if (node.tagName === 'UL') {
|
|
19
19
|
node.childNodes.forEach((item) => {
|
|
20
20
|
if (item.tagName === 'LI') {
|
|
@@ -39,16 +39,17 @@ const {drakonToStruct} = require("./drakonToStruct");
|
|
|
39
39
|
const {printPseudo, printWithIndent, makeIndent} = require('./printPseudo');
|
|
40
40
|
const {addRange, sortByProperty} = require("./tools")
|
|
41
41
|
|
|
42
|
-
function drakonToPseudocode(drakonJson, name, filename, htmlToString, translate) {
|
|
43
|
-
var diagram = drakonToStruct(drakonJson, name, filename, translate)
|
|
42
|
+
function drakonToPseudocode(drakonJson, name, filename, htmlToString, translate, options) {
|
|
43
|
+
var diagram = drakonToStruct(drakonJson, name, filename, translate, htmlToString, options)
|
|
44
44
|
var lines = []
|
|
45
45
|
|
|
46
46
|
lines.push("## " + translate("Procedure") + " \"" + diagram.name + "\"")
|
|
47
|
+
lines.push("")
|
|
47
48
|
if (diagram.params) {
|
|
48
49
|
lines.push(translate("Parameters") + ":")
|
|
49
50
|
addRange(lines, htmlToString(diagram.params))
|
|
51
|
+
lines.push("")
|
|
50
52
|
}
|
|
51
|
-
lines.push("")
|
|
52
53
|
lines.push(translate("Algorithm") + ":")
|
|
53
54
|
|
|
54
55
|
if (diagram.branches.length === 0) {
|
|
@@ -80,7 +81,7 @@ function drakonToPseudocode(drakonJson, name, filename, htmlToString, translate)
|
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
|
|
83
|
-
function mindToTree(drakonJson, name, filename, htmlToString) {
|
|
84
|
+
function mindToTree(drakonJson, name, filename, htmlToString, outputToJson) {
|
|
84
85
|
let drakonGraph;
|
|
85
86
|
try {
|
|
86
87
|
drakonJson = drakonJson || ""
|
|
@@ -93,14 +94,40 @@ function mindToTree(drakonJson, name, filename, htmlToString) {
|
|
|
93
94
|
}
|
|
94
95
|
|
|
95
96
|
const nodes = drakonGraph.items || {};
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
97
|
+
for (var id in nodes) {
|
|
98
|
+
var node = nodes[id]
|
|
99
|
+
node.id = id
|
|
100
|
+
delete node.type
|
|
101
|
+
delete node.treeType
|
|
102
|
+
if (node.content) {
|
|
103
|
+
node.content = htmlToString(node.content).join("\n")
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
var text;
|
|
108
|
+
if (outputToJson) {
|
|
109
|
+
var root = createMindNode(name)
|
|
110
|
+
root.name = root.content
|
|
111
|
+
delete root.content
|
|
112
|
+
nodes["root"] = root
|
|
113
|
+
connectMindNodesToParent(nodes)
|
|
114
|
+
sortMindChildren(nodes)
|
|
115
|
+
for (var id in nodes) {
|
|
116
|
+
var node = nodes[id]
|
|
117
|
+
delete node.parent
|
|
118
|
+
delete node.ordinal
|
|
119
|
+
}
|
|
120
|
+
text = JSON.stringify(root, null, 4)
|
|
121
|
+
} else {
|
|
122
|
+
var root = createMindNode("## " + name)
|
|
123
|
+
nodes["root"] = root
|
|
124
|
+
connectMindNodesToParent(nodes)
|
|
125
|
+
sortMindChildren(nodes)
|
|
126
|
+
var lines = []
|
|
127
|
+
printMindNode(root, 0, lines, htmlToString, true)
|
|
128
|
+
lines.push("")
|
|
129
|
+
text = lines.join("\n")
|
|
130
|
+
}
|
|
104
131
|
return {text:text}
|
|
105
132
|
}
|
|
106
133
|
|
|
@@ -144,22 +171,29 @@ function printMindNode(node, depth, lines, htmlToString, first) {
|
|
|
144
171
|
|
|
145
172
|
function createMindNode(name) {
|
|
146
173
|
return {
|
|
147
|
-
"type": "
|
|
148
|
-
"content":
|
|
174
|
+
"type": "graf",
|
|
175
|
+
"content": name,
|
|
149
176
|
"parent": undefined,
|
|
150
|
-
"treeType": "treeview",
|
|
151
177
|
"ordinal": 0
|
|
152
178
|
}
|
|
153
179
|
}
|
|
154
180
|
|
|
155
181
|
module.exports = { drakonToPseudocode, mindToTree };
|
|
156
|
-
},{"./drakonToStruct":3,"./printPseudo":
|
|
182
|
+
},{"./drakonToStruct":3,"./printPseudo":7,"./tools":10}],3:[function(require,module,exports){
|
|
157
183
|
const { structFlow, redirectNode } = require("./structFlow");
|
|
158
184
|
const { createError, remove } = require("./tools");
|
|
159
185
|
|
|
160
186
|
var translate;
|
|
161
187
|
|
|
162
|
-
function drakonToStruct(
|
|
188
|
+
function drakonToStruct(
|
|
189
|
+
drakonJson,
|
|
190
|
+
name,
|
|
191
|
+
filename,
|
|
192
|
+
translateFunction,
|
|
193
|
+
htmlToString,
|
|
194
|
+
options,
|
|
195
|
+
) {
|
|
196
|
+
options = options || {};
|
|
163
197
|
translate = translateFunction;
|
|
164
198
|
let drakonGraph;
|
|
165
199
|
try {
|
|
@@ -175,32 +209,122 @@ function drakonToStruct(drakonJson, name, filename, translateFunction) {
|
|
|
175
209
|
const nodes = drakonGraph.items || {};
|
|
176
210
|
|
|
177
211
|
var branches = [];
|
|
178
|
-
var firstNodeId = findStartNode(nodes, filename, branches);
|
|
212
|
+
var firstNodeId = findStartNode(nodes, filename, branches, htmlToString);
|
|
213
|
+
var params = decodeContent(drakonGraph.params, htmlToString);
|
|
214
|
+
var description = decodeContent(drakonGraph.description, htmlToString);
|
|
215
|
+
|
|
216
|
+
var result = {
|
|
217
|
+
name: name,
|
|
218
|
+
type: "drakon",
|
|
219
|
+
params: params,
|
|
220
|
+
description: description,
|
|
221
|
+
branches: []
|
|
222
|
+
};
|
|
179
223
|
|
|
180
224
|
if (!firstNodeId) {
|
|
181
|
-
return
|
|
182
|
-
name: name,
|
|
183
|
-
params: drakonGraph.params || "",
|
|
184
|
-
description: drakonGraph.description || "",
|
|
185
|
-
branches: [],
|
|
186
|
-
};
|
|
225
|
+
return result
|
|
187
226
|
}
|
|
188
227
|
|
|
228
|
+
handleParallel(nodes, undefined, firstNodeId, {}, undefined);
|
|
189
229
|
buildTwoWayConnections(nodes, firstNodeId);
|
|
190
230
|
|
|
191
231
|
rewireSelectsMarkLoops(nodes, filename);
|
|
192
232
|
branches.forEach((branch) =>
|
|
193
|
-
checkBranchIsReferenced(
|
|
233
|
+
checkBranchIsReferenced(
|
|
234
|
+
branch,
|
|
235
|
+
firstNodeId,
|
|
236
|
+
filename,
|
|
237
|
+
options
|
|
238
|
+
),
|
|
194
239
|
);
|
|
195
240
|
rewireShortcircuit(nodes, filename);
|
|
196
241
|
branches.forEach((branch) => cutOffBranch(nodes, branch));
|
|
197
|
-
var branchTrees = structFlow(nodes, branches, filename, translate);
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
242
|
+
var branchTrees = structFlow(nodes, branches, filename, translate, options);
|
|
243
|
+
|
|
244
|
+
result.branches = branchTrees
|
|
245
|
+
result.secondary = findSecondary(branchTrees, options)
|
|
246
|
+
return result
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function findSecondary(branchTrees, options) {
|
|
250
|
+
if (!options || !options.secondary) {
|
|
251
|
+
return undefined;
|
|
252
|
+
}
|
|
253
|
+
var ordinal = 0;
|
|
254
|
+
for (var branch of branchTrees) {
|
|
255
|
+
var name = branch.name;
|
|
256
|
+
if (name === options.secondary) {
|
|
257
|
+
return ordinal;
|
|
258
|
+
}
|
|
259
|
+
ordinal++;
|
|
260
|
+
}
|
|
261
|
+
return undefined;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function handleParallel(nodes, prevNode, nodeId, visited, proc) {
|
|
265
|
+
if (!nodeId) {
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
var node = nodes[nodeId];
|
|
269
|
+
if (node.type === "parend") {
|
|
270
|
+
if (!proc) {
|
|
271
|
+
throw new Error("handleParallel: no proc for parend");
|
|
272
|
+
}
|
|
273
|
+
var endId = proc.end;
|
|
274
|
+
var end;
|
|
275
|
+
if (endId) {
|
|
276
|
+
end = nodes[endId];
|
|
277
|
+
} else {
|
|
278
|
+
end = {
|
|
279
|
+
type: "end",
|
|
280
|
+
id: proc.id + "-" + proc.ordinal + "-end",
|
|
281
|
+
prev: [],
|
|
282
|
+
};
|
|
283
|
+
nodes[end.id] = end;
|
|
284
|
+
proc.end = end.id;
|
|
285
|
+
proc.next = node.one;
|
|
286
|
+
}
|
|
287
|
+
redirectNode(nodes, prevNode, nodeId, end.id);
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
if (nodeId in visited) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
visited[nodeId] = true;
|
|
294
|
+
if (node.type === "parbegin") {
|
|
295
|
+
node.procs = [];
|
|
296
|
+
var ordinal = 0;
|
|
297
|
+
var current = node;
|
|
298
|
+
while (true) {
|
|
299
|
+
var start = {
|
|
300
|
+
id: nodeId + "-" + ordinal + "-start",
|
|
301
|
+
type: "action",
|
|
302
|
+
prev: [],
|
|
303
|
+
one: current.one,
|
|
304
|
+
};
|
|
305
|
+
nodes[start.id] = start;
|
|
306
|
+
var childProc = {
|
|
307
|
+
id: nodeId,
|
|
308
|
+
ordinal: ordinal,
|
|
309
|
+
start: start.id,
|
|
310
|
+
};
|
|
311
|
+
var next = current.two;
|
|
312
|
+
node.procs.push(childProc);
|
|
313
|
+
handleParallel(nodes, start, start.one, {}, childProc);
|
|
314
|
+
delete current.one;
|
|
315
|
+
delete current.two;
|
|
316
|
+
if (!next) {
|
|
317
|
+
break;
|
|
318
|
+
}
|
|
319
|
+
current = nodes[next];
|
|
320
|
+
ordinal++;
|
|
321
|
+
}
|
|
322
|
+
node.one = node.procs[0].next;
|
|
323
|
+
handleParallel(nodes, node, node.one, visited, proc);
|
|
324
|
+
} else {
|
|
325
|
+
handleParallel(nodes, node, node.one, visited, proc);
|
|
326
|
+
handleParallel(nodes, node, node.two, visited, proc);
|
|
327
|
+
}
|
|
204
328
|
}
|
|
205
329
|
|
|
206
330
|
function drakonToGraph(drakonJson, name, filename, translateFunction) {
|
|
@@ -227,7 +351,13 @@ function drakonToGraph(drakonJson, name, filename, translateFunction) {
|
|
|
227
351
|
rewireSelectsMarkLoops(nodes, filename);
|
|
228
352
|
rewireShortcircuit(nodes, filename);
|
|
229
353
|
branches.forEach((branch) =>
|
|
230
|
-
checkBranchIsReferenced(
|
|
354
|
+
checkBranchIsReferenced(
|
|
355
|
+
branch,
|
|
356
|
+
firstNodeId,
|
|
357
|
+
filename,
|
|
358
|
+
undefined,
|
|
359
|
+
undefined,
|
|
360
|
+
),
|
|
231
361
|
);
|
|
232
362
|
branches.forEach((branch) => cutOffBranch(nodes, branch));
|
|
233
363
|
|
|
@@ -241,16 +371,34 @@ function drakonToGraph(drakonJson, name, filename, translateFunction) {
|
|
|
241
371
|
};
|
|
242
372
|
}
|
|
243
373
|
|
|
244
|
-
function checkBranchIsReferenced(
|
|
374
|
+
function checkBranchIsReferenced(
|
|
375
|
+
branch,
|
|
376
|
+
firstNodeId,
|
|
377
|
+
filename,
|
|
378
|
+
options
|
|
379
|
+
) {
|
|
245
380
|
if (branch.id === firstNodeId) {
|
|
246
381
|
return;
|
|
247
382
|
}
|
|
248
|
-
if (
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
383
|
+
if (options) {
|
|
384
|
+
var branchName = branch.content;
|
|
385
|
+
if (branchName === options.secondary) {
|
|
386
|
+
if (branch.prev.length > 0) {
|
|
387
|
+
throw createError(
|
|
388
|
+
translate("A secondary branch is referenced"),
|
|
389
|
+
filename,
|
|
390
|
+
branch.id,
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
} else {
|
|
394
|
+
if (branch.prev.length === 0) {
|
|
395
|
+
throw createError(
|
|
396
|
+
translate("A silhouette branch is not referenced"),
|
|
397
|
+
filename,
|
|
398
|
+
branch.id,
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
254
402
|
}
|
|
255
403
|
}
|
|
256
404
|
|
|
@@ -334,14 +482,19 @@ function buildTwoWayConnections(nodes, firstNodeId) {
|
|
|
334
482
|
node.prev = [];
|
|
335
483
|
}
|
|
336
484
|
|
|
337
|
-
|
|
485
|
+
var visitor = function (nodes, node) {
|
|
486
|
+
return connectBack(nodes, node);
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
traverse(nodes, firstNodeId, {}, visitor);
|
|
338
490
|
}
|
|
339
491
|
|
|
340
|
-
function findStartNode(nodes, filename, branches) {
|
|
492
|
+
function findStartNode(nodes, filename, branches, htmlToString) {
|
|
341
493
|
var firstNodeId = undefined;
|
|
342
494
|
var minBranchId = 10000;
|
|
343
495
|
for (var id in nodes) {
|
|
344
496
|
var node = nodes[id];
|
|
497
|
+
decodeNodeContent(node, htmlToString);
|
|
345
498
|
if (node.type === "branch") {
|
|
346
499
|
if (node.branchId < minBranchId) {
|
|
347
500
|
firstNodeId = id;
|
|
@@ -373,12 +526,33 @@ function findStartNode(nodes, filename, branches) {
|
|
|
373
526
|
id,
|
|
374
527
|
);
|
|
375
528
|
}
|
|
529
|
+
} else if (node.final) {
|
|
530
|
+
delete node.one
|
|
531
|
+
delete node.two
|
|
376
532
|
}
|
|
377
533
|
}
|
|
378
534
|
|
|
379
535
|
return firstNodeId;
|
|
380
536
|
}
|
|
381
537
|
|
|
538
|
+
function decodeNodeContent(node, htmlToString) {
|
|
539
|
+
if (node.content && typeof node.content === "string") {
|
|
540
|
+
node.content = decodeContent(node.content, htmlToString);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
if (node.secondary && typeof node.secondary === "string") {
|
|
544
|
+
node.secondary = decodeContent(node.secondary, htmlToString);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
function decodeContent(content, htmlToString) {
|
|
549
|
+
if (!content) {
|
|
550
|
+
return ""
|
|
551
|
+
}
|
|
552
|
+
var lines = htmlToString(content);
|
|
553
|
+
return lines.join("\n");
|
|
554
|
+
}
|
|
555
|
+
|
|
382
556
|
function rewireSelectsMarkLoops(nodes, filename) {
|
|
383
557
|
for (var id of Object.keys(nodes)) {
|
|
384
558
|
var node = nodes[id];
|
|
@@ -395,6 +569,7 @@ function rewireSelectsMarkLoops(nodes, filename) {
|
|
|
395
569
|
|
|
396
570
|
function rewireSelect(nodes, selectNode, filename) {
|
|
397
571
|
var caseNodeId = selectNode.one;
|
|
572
|
+
var caseNode0 = nodes[caseNodeId];
|
|
398
573
|
while (caseNodeId) {
|
|
399
574
|
var caseNode = nodes[caseNodeId];
|
|
400
575
|
caseNodeId = caseNode.two;
|
|
@@ -434,6 +609,7 @@ function rewireSelect(nodes, selectNode, filename) {
|
|
|
434
609
|
removeNodeOne(nodes, caseNode.id);
|
|
435
610
|
}
|
|
436
611
|
}
|
|
612
|
+
caseNode0.side = selectNode.side;
|
|
437
613
|
removeNodeOne(nodes, selectNode.id);
|
|
438
614
|
}
|
|
439
615
|
|
|
@@ -608,6 +784,11 @@ function traverse(nodes, nodeId, visited, action) {
|
|
|
608
784
|
action(nodes, node);
|
|
609
785
|
traverse(nodes, node.one, visited, action);
|
|
610
786
|
traverse(nodes, node.two, visited, action);
|
|
787
|
+
if (node.procs) {
|
|
788
|
+
for (var proc of node.procs) {
|
|
789
|
+
traverse(nodes, proc.start, visited, action);
|
|
790
|
+
}
|
|
791
|
+
}
|
|
611
792
|
}
|
|
612
793
|
|
|
613
794
|
function connectBack(nodes, node) {
|
|
@@ -619,6 +800,23 @@ function connectBack(nodes, node) {
|
|
|
619
800
|
var two = nodes[node.two];
|
|
620
801
|
two.prev.push(node.id);
|
|
621
802
|
}
|
|
803
|
+
|
|
804
|
+
if (node.side) {
|
|
805
|
+
var side = nodes[node.side].content;
|
|
806
|
+
if (side) {
|
|
807
|
+
node.side = decodeSide(side);
|
|
808
|
+
} else {
|
|
809
|
+
delete node.side;
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
function decodeSide(content) {
|
|
815
|
+
if (content.indexOf("=") === -1) {
|
|
816
|
+
return translate("Do for") + " " + content;
|
|
817
|
+
} else {
|
|
818
|
+
return translate("Start at") + " " + content;
|
|
819
|
+
}
|
|
622
820
|
}
|
|
623
821
|
|
|
624
822
|
function markLoopBody(nodes, start, filename) {
|
|
@@ -641,32 +839,270 @@ function markLoopBody(nodes, start, filename) {
|
|
|
641
839
|
|
|
642
840
|
module.exports = { drakonToStruct, drakonToGraph };
|
|
643
841
|
|
|
644
|
-
},{"./structFlow":
|
|
645
|
-
const { drakonToPseudocode, mindToTree } = require(
|
|
646
|
-
const { htmlToString } = require("./browserTools")
|
|
647
|
-
const { setUpLanguage, translate } = require("./translate")
|
|
842
|
+
},{"./structFlow":8,"./tools":10}],4:[function(require,module,exports){
|
|
843
|
+
const { drakonToPseudocode, mindToTree } = require("./drakonToPromptStruct");
|
|
844
|
+
const { htmlToString } = require("./browserTools");
|
|
845
|
+
const { setUpLanguage, translate } = require("./translate");
|
|
648
846
|
const { drakonToStruct } = require("./drakonToStruct");
|
|
649
|
-
|
|
847
|
+
const { freeDiagramToText } = require("./free");
|
|
650
848
|
|
|
651
849
|
window.drakongen = {
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
850
|
+
toPseudocode: function (drakonJson, name, filename, language) {
|
|
851
|
+
setUpLanguage(language);
|
|
852
|
+
return drakonToPseudocode(
|
|
853
|
+
drakonJson,
|
|
854
|
+
name,
|
|
855
|
+
filename,
|
|
856
|
+
htmlToString,
|
|
857
|
+
translate,
|
|
858
|
+
).text;
|
|
859
|
+
},
|
|
860
|
+
|
|
861
|
+
toMindTree: function (mindJson, name, filename, language) {
|
|
862
|
+
setUpLanguage(language);
|
|
863
|
+
var result = mindToTree(mindJson, name, filename, htmlToString, false);
|
|
864
|
+
return result.text;
|
|
865
|
+
},
|
|
866
|
+
|
|
867
|
+
toMindTreeJson: function (mindJson, name, filename, language) {
|
|
868
|
+
setUpLanguage(language);
|
|
869
|
+
var result = mindToTree(mindJson, name, filename, htmlToString, true);
|
|
870
|
+
return result.text;
|
|
871
|
+
},
|
|
872
|
+
|
|
873
|
+
freeToText: function (freeJson, name, filename, language) {
|
|
874
|
+
setUpLanguage(language);
|
|
875
|
+
var result = freeDiagramToText(
|
|
876
|
+
freeJson,
|
|
877
|
+
name,
|
|
878
|
+
filename,
|
|
879
|
+
translate,
|
|
880
|
+
htmlToString,
|
|
881
|
+
);
|
|
882
|
+
return result.text;
|
|
883
|
+
},
|
|
884
|
+
|
|
885
|
+
toTree: function (drakonJson, name, filename, language, options) {
|
|
886
|
+
setUpLanguage(language);
|
|
887
|
+
var result = drakonToStruct(
|
|
888
|
+
drakonJson,
|
|
889
|
+
name,
|
|
890
|
+
filename,
|
|
891
|
+
translate,
|
|
892
|
+
htmlToString,
|
|
893
|
+
options,
|
|
894
|
+
);
|
|
895
|
+
return JSON.stringify(result, null, 4);
|
|
896
|
+
},
|
|
897
|
+
};
|
|
898
|
+
|
|
899
|
+
},{"./browserTools":1,"./drakonToPromptStruct":2,"./drakonToStruct":3,"./free":5,"./translate":11}],5:[function(require,module,exports){
|
|
900
|
+
var {addRange} = require("./tools")
|
|
901
|
+
const { createError } = require("./tools");
|
|
902
|
+
|
|
903
|
+
var translate
|
|
904
|
+
|
|
905
|
+
function compareVertically(box1, box2) {
|
|
906
|
+
if (box1.top + box1.height <= box2.top) return -1;
|
|
907
|
+
if (box2.top + box2.height <= box1.top) return 1;
|
|
908
|
+
return 0;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
function compareHorizontally(box1, box2) {
|
|
912
|
+
if (box1.left + box1.width <= box2.left) return -1;
|
|
913
|
+
if (box2.left + box2.width <= box1.left) return 1;
|
|
914
|
+
return 0;
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
function byTopLeft(box1, box2) {
|
|
918
|
+
var vertical = compareVertically(box1, box2)
|
|
919
|
+
if (vertical == 0) {
|
|
920
|
+
return compareHorizontally(box1, box2)
|
|
921
|
+
}
|
|
922
|
+
return vertical
|
|
923
|
+
}
|
|
656
924
|
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
925
|
+
function parseDiagram(freeJson, filename) {
|
|
926
|
+
let diagram;
|
|
927
|
+
try {
|
|
928
|
+
freeJson = freeJson || ""
|
|
929
|
+
freeJson = freeJson.trim()
|
|
930
|
+
freeJson = freeJson || "{}"
|
|
931
|
+
diagram = JSON.parse(freeJson);
|
|
932
|
+
} catch (error) {
|
|
933
|
+
var message = translate("Error parsing JSON") + ": " + error.message
|
|
934
|
+
throw createError(message, filename)
|
|
935
|
+
}
|
|
936
|
+
return diagram
|
|
937
|
+
}
|
|
662
938
|
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
939
|
+
function sortedItems(diagram) {
|
|
940
|
+
var items = diagram.items || {};
|
|
941
|
+
var result = [];
|
|
942
|
+
for (var id in items) {
|
|
943
|
+
var item = items[id];
|
|
944
|
+
if (item.content && item.top && item.left && item.width && item.height) {
|
|
945
|
+
result.push(item);
|
|
946
|
+
}
|
|
667
947
|
}
|
|
948
|
+
result.sort(byTopLeft);
|
|
949
|
+
return result;
|
|
668
950
|
}
|
|
669
|
-
|
|
951
|
+
|
|
952
|
+
function freeDiagramToText(freeJson, name, filename, translateFunction, htmlToString) {
|
|
953
|
+
translate = translateFunction
|
|
954
|
+
var diagram = parseDiagram(freeJson, filename)
|
|
955
|
+
var sorted = sortedItems(diagram)
|
|
956
|
+
var lines = []
|
|
957
|
+
lines.push("## " + name)
|
|
958
|
+
lines.push("")
|
|
959
|
+
for (var item of sorted) {
|
|
960
|
+
var content = htmlToString(item.content)
|
|
961
|
+
addRange(lines, content)
|
|
962
|
+
lines.push("")
|
|
963
|
+
}
|
|
964
|
+
var text = lines.join("\n")
|
|
965
|
+
return {text:text}
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
module.exports = {freeDiagramToText}
|
|
969
|
+
},{"./tools":10}],6:[function(require,module,exports){
|
|
970
|
+
function decrement_arrow_count(context, node) {
|
|
971
|
+
var algonode;
|
|
972
|
+
algonode = context.nodes[node.arrow];
|
|
973
|
+
algonode.branching--;
|
|
974
|
+
}
|
|
975
|
+
function decrement_if_count(context, node) {
|
|
976
|
+
var _collection_12, if_id, if_node;
|
|
977
|
+
_collection_12 = node.stack;
|
|
978
|
+
for (if_id of _collection_12) {
|
|
979
|
+
if_node = context.nodes[if_id];
|
|
980
|
+
if_node.branching--;
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
function flow_no_loop(nodes, start_node_id) {
|
|
984
|
+
var context;
|
|
985
|
+
context = { nodes: nodes };
|
|
986
|
+
traverse_node(context, start_node_id, []);
|
|
987
|
+
}
|
|
988
|
+
function group_stack_by_id(stack) {
|
|
989
|
+
var counts_by_id, element, existing;
|
|
990
|
+
counts_by_id = {};
|
|
991
|
+
for (element of stack) {
|
|
992
|
+
if (element in counts_by_id) {
|
|
993
|
+
existing = counts_by_id[element];
|
|
994
|
+
} else {
|
|
995
|
+
existing = 0;
|
|
996
|
+
}
|
|
997
|
+
counts_by_id[element] = existing + 1;
|
|
998
|
+
}
|
|
999
|
+
return counts_by_id;
|
|
1000
|
+
}
|
|
1001
|
+
function increment_if_count(context, node) {
|
|
1002
|
+
var _collection_14, if_id, if_node;
|
|
1003
|
+
_collection_14 = node.stack;
|
|
1004
|
+
for (if_id of _collection_14) {
|
|
1005
|
+
if_node = context.nodes[if_id];
|
|
1006
|
+
if_node.branching++;
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
function is_in_map(map, key) {
|
|
1010
|
+
if (map) {
|
|
1011
|
+
return key in map;
|
|
1012
|
+
} else {
|
|
1013
|
+
return false;
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
function merge_converging_branches(context, node_id, node, stack) {
|
|
1017
|
+
var algonode, algonode_id, common, count, counts_by_id, processed_stack, stub;
|
|
1018
|
+
common = node.stack.concat(stack);
|
|
1019
|
+
counts_by_id = group_stack_by_id(common);
|
|
1020
|
+
for (algonode_id in counts_by_id) {
|
|
1021
|
+
count = counts_by_id[algonode_id];
|
|
1022
|
+
algonode = context.nodes[algonode_id];
|
|
1023
|
+
if (!algonode.next && algonode.type == 'arrow-loop') {
|
|
1024
|
+
algonode.branching -= count - 1;
|
|
1025
|
+
if (!(algonode.branching > 1 || is_in_map(node.astack, algonode_id))) {
|
|
1026
|
+
stub = context.nodes[algonode.stub];
|
|
1027
|
+
decrement_if_count(context, stub);
|
|
1028
|
+
stub.one = node_id;
|
|
1029
|
+
algonode.next = node_id;
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
processed_stack = [];
|
|
1034
|
+
for (algonode_id in counts_by_id) {
|
|
1035
|
+
count = counts_by_id[algonode_id];
|
|
1036
|
+
algonode = context.nodes[algonode_id];
|
|
1037
|
+
if (!algonode.next) {
|
|
1038
|
+
if (algonode.type == 'question') {
|
|
1039
|
+
algonode.branching -= count - 1;
|
|
1040
|
+
if (algonode.branching > 1) {
|
|
1041
|
+
processed_stack.push(algonode_id);
|
|
1042
|
+
} else {
|
|
1043
|
+
algonode.next = node_id;
|
|
1044
|
+
}
|
|
1045
|
+
} else {
|
|
1046
|
+
processed_stack.push(algonode_id);
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
node.stack = processed_stack;
|
|
1051
|
+
}
|
|
1052
|
+
function recurse_traversal(context, node_id, node) {
|
|
1053
|
+
var _collection_20, _selectValue_18, proc, stack1, stack2;
|
|
1054
|
+
_selectValue_18 = node.type;
|
|
1055
|
+
if (_selectValue_18 === 'question') {
|
|
1056
|
+
increment_if_count(context, node);
|
|
1057
|
+
stack1 = node.stack.slice();
|
|
1058
|
+
stack1.push(node_id);
|
|
1059
|
+
stack2 = node.stack.slice();
|
|
1060
|
+
stack2.push(node_id);
|
|
1061
|
+
traverse_node(context, node.two, stack2);
|
|
1062
|
+
traverse_node(context, node.one, stack1);
|
|
1063
|
+
} else {
|
|
1064
|
+
if (_selectValue_18 === 'arrow-loop') {
|
|
1065
|
+
stack1 = node.stack.slice();
|
|
1066
|
+
stack1.push(node_id);
|
|
1067
|
+
traverse_node(context, node.one, stack1);
|
|
1068
|
+
} else {
|
|
1069
|
+
if (_selectValue_18 === 'arrow-stub') {
|
|
1070
|
+
decrement_arrow_count(context, node);
|
|
1071
|
+
} else {
|
|
1072
|
+
if (_selectValue_18 === 'parbegin') {
|
|
1073
|
+
_collection_20 = node.procs;
|
|
1074
|
+
for (proc of _collection_20) {
|
|
1075
|
+
flow_no_loop(context.nodes, proc.start);
|
|
1076
|
+
}
|
|
1077
|
+
} else {
|
|
1078
|
+
if (node.final) {
|
|
1079
|
+
decrement_if_count(context, node);
|
|
1080
|
+
} else {
|
|
1081
|
+
stack1 = node.stack.slice();
|
|
1082
|
+
traverse_node(context, node.one, stack1);
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
function traverse_node(context, node_id, stack) {
|
|
1090
|
+
var node;
|
|
1091
|
+
if (node_id) {
|
|
1092
|
+
node = context.nodes[node_id];
|
|
1093
|
+
if (!node.stack) {
|
|
1094
|
+
node.stack = [];
|
|
1095
|
+
node.refs = node.prev.length;
|
|
1096
|
+
}
|
|
1097
|
+
node.refs--;
|
|
1098
|
+
merge_converging_branches(context, node_id, node, stack);
|
|
1099
|
+
if (!(node.refs > 0)) {
|
|
1100
|
+
recurse_traversal(context, node_id, node);
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
module.exports = { flow_no_loop };
|
|
1105
|
+
},{}],7:[function(require,module,exports){
|
|
670
1106
|
var {addRange} = require("./tools")
|
|
671
1107
|
|
|
672
1108
|
function makeIndent(depth) {
|
|
@@ -679,8 +1115,11 @@ function printWithIndent(lines, indent, output) {
|
|
|
679
1115
|
}
|
|
680
1116
|
|
|
681
1117
|
function printPseudo(algorithm, translate, output, htmlToString) {
|
|
682
|
-
function printStructuredContent(content, indent, output) {
|
|
1118
|
+
function printStructuredContent(content, indent, output, side) {
|
|
683
1119
|
var lines = printStructuredContentNoIdent(content)
|
|
1120
|
+
if (side) {
|
|
1121
|
+
lines[0] = side + ": " + lines[0]
|
|
1122
|
+
}
|
|
684
1123
|
printWithIndent(lines, indent, output)
|
|
685
1124
|
}
|
|
686
1125
|
|
|
@@ -744,19 +1183,39 @@ function printPseudo(algorithm, translate, output, htmlToString) {
|
|
|
744
1183
|
printError(step, indent, output)
|
|
745
1184
|
} else if (step.type === "break") {
|
|
746
1185
|
output.push(indent + translate("break"))
|
|
1186
|
+
} else if (step.type === "parbegin") {
|
|
1187
|
+
printParbegin(step, depth, output)
|
|
747
1188
|
} else {
|
|
748
1189
|
printOther(step, indent, output)
|
|
749
1190
|
}
|
|
750
1191
|
}
|
|
751
1192
|
}
|
|
1193
|
+
|
|
1194
|
+
function printParbegin(step, depth, output) {
|
|
1195
|
+
const indent2 = makeIndent(depth + 1)
|
|
1196
|
+
const indent = makeIndent(depth)
|
|
1197
|
+
printWithIndent([translate("Group of parallel processes")], indent, output)
|
|
1198
|
+
for (var proc of step.procs) {
|
|
1199
|
+
printWithIndent([translate("Parallel process") + " " + (proc.ordinal + 1)], indent2, output)
|
|
1200
|
+
printSteps(proc.body, depth + 2, output)
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
752
1203
|
|
|
753
1204
|
function printOther(step, indent, output) {
|
|
1205
|
+
var side = step.side
|
|
754
1206
|
if (!step.content && !step.secondary) {return}
|
|
755
1207
|
if (step.secondary) {
|
|
756
|
-
printStructuredContent(step.secondary, indent, output)
|
|
1208
|
+
printStructuredContent(step.secondary, indent, output, side)
|
|
1209
|
+
side = undefined
|
|
757
1210
|
}
|
|
758
1211
|
if (step.content) {
|
|
759
|
-
|
|
1212
|
+
var content = step.content
|
|
1213
|
+
if (step.type === "pause") {
|
|
1214
|
+
content = translate("Pause") + " " + htmlToString(content).join(" ")
|
|
1215
|
+
} else if (step.type === "timer") {
|
|
1216
|
+
content = translate("Start timer") + " " + htmlToString(content).join(" ")
|
|
1217
|
+
}
|
|
1218
|
+
printStructuredContent(content, indent, output, side)
|
|
760
1219
|
}
|
|
761
1220
|
}
|
|
762
1221
|
|
|
@@ -797,6 +1256,9 @@ function printPseudo(algorithm, translate, output, htmlToString) {
|
|
|
797
1256
|
var content = step.content
|
|
798
1257
|
var lines = printStructuredContentNoIdent(content)
|
|
799
1258
|
lines[0] = translate("if") + " " + lines[0]
|
|
1259
|
+
if (step.side) {
|
|
1260
|
+
lines[0] = step.side + ": " + lines[0]
|
|
1261
|
+
}
|
|
800
1262
|
printWithIndent(lines, indent, output)
|
|
801
1263
|
addRange(output, yesBody)
|
|
802
1264
|
if (!empty(noBody)) {
|
|
@@ -825,402 +1287,186 @@ function printPseudo(algorithm, translate, output, htmlToString) {
|
|
|
825
1287
|
}
|
|
826
1288
|
|
|
827
1289
|
module.exports = {printPseudo, printWithIndent, makeIndent}
|
|
828
|
-
},{"./tools":
|
|
829
|
-
var {buildTree} = require("./technicalTree")
|
|
1290
|
+
},{"./tools":10}],8:[function(require,module,exports){
|
|
1291
|
+
var { buildTree } = require("./technicalTree");
|
|
830
1292
|
const { createError, sortByProperty } = require("./tools");
|
|
831
|
-
const { optimizeTree } = require("./treeTools")
|
|
1293
|
+
const { optimizeTree } = require("./treeTools");
|
|
1294
|
+
const { flow_no_loop } = require("./noloop")
|
|
832
1295
|
|
|
833
1296
|
function redirectNode(nodes, node, from, to) {
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
}
|
|
1297
|
+
if (node.one === from) {
|
|
1298
|
+
node.one = to;
|
|
1299
|
+
}
|
|
1300
|
+
if (node.two === from) {
|
|
1301
|
+
node.two = to;
|
|
1302
|
+
}
|
|
1303
|
+
if (node.next === from) {
|
|
1304
|
+
node.next = to;
|
|
1305
|
+
}
|
|
1306
|
+
if (node.start && node.type === "loopend") {
|
|
1307
|
+
start = nodes[node.start];
|
|
1308
|
+
if (start.next === from) {
|
|
1309
|
+
start.next = to;
|
|
848
1310
|
}
|
|
1311
|
+
}
|
|
849
1312
|
}
|
|
850
1313
|
|
|
851
|
-
function structFlow(nodes, branches, filename, translate) {
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
function flowGraph(nodes, nodeId, branchingStack) {
|
|
856
|
-
if (!nodeId) {return;}
|
|
857
|
-
|
|
858
|
-
const node = nodes[nodeId];
|
|
859
|
-
|
|
860
|
-
if (!node.stack) {
|
|
861
|
-
node.stack = [];
|
|
862
|
-
node.remaining = node.prev.length;
|
|
863
|
-
}
|
|
864
|
-
node.remaining--;
|
|
865
|
-
|
|
866
|
-
mergeBranchingStack(nodes, node, branchingStack);
|
|
867
|
-
if (node.remaining > 0) {return;}
|
|
868
|
-
|
|
869
|
-
if (node.type === "question") {
|
|
870
|
-
for (let i = 0; i < node.stack.length; i++) {
|
|
871
|
-
const questionId = node.stack[i];
|
|
872
|
-
const question = nodes[questionId];
|
|
873
|
-
question.branching++;
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
const stackOne = node.stack.slice();
|
|
877
|
-
const stackTwo = node.stack.slice();
|
|
878
|
-
stackOne.push(nodeId);
|
|
879
|
-
stackTwo.push(nodeId);
|
|
880
|
-
|
|
881
|
-
flowGraph(nodes, node.two, stackTwo);
|
|
882
|
-
flowGraph(nodes, node.one, stackOne);
|
|
883
|
-
} else if (node.type === "arrow-loop") {
|
|
884
|
-
const stackOne = node.stack.slice();
|
|
885
|
-
stackOne.push(nodeId);
|
|
886
|
-
flowGraph(nodes, node.one, stackOne);
|
|
887
|
-
} else if (node.type === "arrow-stub") {
|
|
888
|
-
decrementBranchingForArrow(nodes, node)
|
|
889
|
-
} else {
|
|
890
|
-
flowGraph(nodes, node.one, node.stack);
|
|
891
|
-
}
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
function decrementBranchingForArrow(nodes, node) {
|
|
895
|
-
var algonode = nodes[node.arrow]
|
|
896
|
-
algonode.branching--
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
function decrementQuestions(nodes, algonode, dictionary) {
|
|
900
|
-
var stub = nodes[algonode.stub]
|
|
901
|
-
for (var id of stub.stack) {
|
|
902
|
-
var snode = nodes[id]
|
|
903
|
-
if (id != algonode) {
|
|
904
|
-
if (id in dictionary) {
|
|
905
|
-
snode.branching--
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
return stub
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
function mergeBranchingStack(nodes, node, branchingStack) {
|
|
915
|
-
// Append all elements of the branching stack to node.stack
|
|
916
|
-
addRange(node.stack, branchingStack)
|
|
917
|
-
|
|
918
|
-
// Build a dictionary of occurrences
|
|
919
|
-
const dictionary = buildDictionaryOfOccurences(node);
|
|
1314
|
+
function structFlow(nodes, branches, filename, translate, options) {
|
|
920
1315
|
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
node.
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
for (let i = 0; i < src.length; i++) {
|
|
930
|
-
dst.push(src[i]);
|
|
931
|
-
}
|
|
1316
|
+
function prepareQuestions(nodes) {
|
|
1317
|
+
for (const nodeId in nodes) {
|
|
1318
|
+
const node = nodes[nodeId];
|
|
1319
|
+
if (node.type === "question") {
|
|
1320
|
+
node.branching = 2;
|
|
1321
|
+
} else if (node.type === "arrow-loop") {
|
|
1322
|
+
node.branching = 1;
|
|
1323
|
+
}
|
|
932
1324
|
}
|
|
1325
|
+
}
|
|
933
1326
|
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
1327
|
+
function rewireArrows(nodes, branches) {
|
|
1328
|
+
branches.forEach((branch) =>
|
|
1329
|
+
rewireArrowsInBranch(nodes, branch.id, branch.next, []),
|
|
1330
|
+
);
|
|
1331
|
+
for (var id in nodes) {
|
|
1332
|
+
var node = nodes[id];
|
|
1333
|
+
if (node.type === "arrow-loop") {
|
|
1334
|
+
var stub = insertArrowStub(nodes, node);
|
|
1335
|
+
var visited = {};
|
|
1336
|
+
fillAStack(nodes, stub, stub.arrow, visited);
|
|
1337
|
+
}
|
|
942
1338
|
}
|
|
1339
|
+
}
|
|
943
1340
|
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
const id = node.stack[i];
|
|
948
|
-
dictionary[id] = (dictionary[id] || 0) + 1;
|
|
949
|
-
}
|
|
950
|
-
return dictionary;
|
|
1341
|
+
function fillAStack(nodes, node, arrowId, visited) {
|
|
1342
|
+
if (node.id in visited) {
|
|
1343
|
+
return;
|
|
951
1344
|
}
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
const occurrences = dictionary[id];
|
|
956
|
-
const algonode = nodes[id];
|
|
957
|
-
if (occurrences > 1) {
|
|
958
|
-
algonode.branching--;
|
|
959
|
-
dictionary[id] = occurrences - 1;
|
|
960
|
-
}
|
|
961
|
-
if (algonode.branching === 1) {
|
|
962
|
-
if (algonode.type === "arrow-loop" && !algonode.next) {
|
|
963
|
-
if (!isInMap(node.astack, id)) {
|
|
964
|
-
algonode.next = node.id
|
|
965
|
-
dictionary[algonode.id] = 0;
|
|
966
|
-
var stub = decrementQuestions(nodes, algonode, dictionary)
|
|
967
|
-
stub.one = node.id
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
for (const id in dictionary) {
|
|
974
|
-
const algonode = nodes[id];
|
|
975
|
-
if (algonode.branching === 1) {
|
|
976
|
-
if (algonode.type === "question") {
|
|
977
|
-
algonode.next = node.id;
|
|
978
|
-
dictionary[algonode.id] = 0;
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
}
|
|
1345
|
+
visited[node.id] = true;
|
|
1346
|
+
if (!node.astack) {
|
|
1347
|
+
node.astack = {};
|
|
982
1348
|
}
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
1349
|
+
node.astack[arrowId] = true;
|
|
1350
|
+
if (node.id === arrowId) {
|
|
1351
|
+
return;
|
|
986
1352
|
}
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
const node = nodes[nodeId];
|
|
991
|
-
if (node.type === "question") {
|
|
992
|
-
node.branching = 2;
|
|
993
|
-
} else if (node.type === "arrow-loop") {
|
|
994
|
-
node.branching = 1;
|
|
995
|
-
}
|
|
996
|
-
}
|
|
1353
|
+
for (var prevId of node.prev) {
|
|
1354
|
+
var prev = nodes[prevId];
|
|
1355
|
+
fillAStack(nodes, prev, arrowId, visited);
|
|
997
1356
|
}
|
|
1357
|
+
}
|
|
998
1358
|
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
var node = nodes[id]
|
|
1003
|
-
if (node.type === "arrow-loop") {
|
|
1004
|
-
var stub = insertArrowStub(nodes, node)
|
|
1005
|
-
fillAStack(nodes, stub, stub.arrow)
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1359
|
+
function rewireArrowsInBranch(nodes, prevNodeId, nodeId, arrowStack) {
|
|
1360
|
+
if (!nodeId) {
|
|
1361
|
+
return;
|
|
1008
1362
|
}
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
node.astack = {}
|
|
1013
|
-
}
|
|
1014
|
-
node.astack[arrowId] = true
|
|
1015
|
-
if (node.id === arrowId) {
|
|
1016
|
-
return
|
|
1017
|
-
}
|
|
1018
|
-
for (var prevId of node.prev) {
|
|
1019
|
-
var prev = nodes[prevId]
|
|
1020
|
-
fillAStack(nodes, prev, arrowId)
|
|
1021
|
-
}
|
|
1022
|
-
}
|
|
1023
|
-
|
|
1024
|
-
function rewireArrowsInBranch(nodes, prevNodeId, nodeId, arrowStack) {
|
|
1025
|
-
if (!nodeId) {return}
|
|
1026
|
-
var node = nodes[nodeId]
|
|
1027
|
-
if (node.type === "branch") {
|
|
1028
|
-
return
|
|
1029
|
-
}
|
|
1030
|
-
if (node.type === "arrow-loop") {
|
|
1031
|
-
if (!node.noloop) {
|
|
1032
|
-
node.noloop = {}
|
|
1033
|
-
}
|
|
1034
|
-
if (arrowStack.includes(nodeId)) {
|
|
1035
|
-
return
|
|
1036
|
-
}
|
|
1037
|
-
node.noloop[prevNodeId] = true
|
|
1038
|
-
arrowStack = arrowStack.slice()
|
|
1039
|
-
arrowStack.push(nodeId)
|
|
1040
|
-
rewireArrowsInBranch(nodes, nodeId, node.one, arrowStack)
|
|
1041
|
-
} else if (node.type === "question") {
|
|
1042
|
-
var left = arrowStack.slice()
|
|
1043
|
-
var right = arrowStack.slice()
|
|
1044
|
-
rewireArrowsInBranch(nodes, nodeId, node.one, left)
|
|
1045
|
-
rewireArrowsInBranch(nodes, nodeId, node.two, right)
|
|
1046
|
-
} else {
|
|
1047
|
-
rewireArrowsInBranch(nodes, nodeId, node.one, arrowStack)
|
|
1048
|
-
}
|
|
1363
|
+
var node = nodes[nodeId];
|
|
1364
|
+
if (node.type === "branch") {
|
|
1365
|
+
return;
|
|
1049
1366
|
}
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1367
|
+
if (node.type === "arrow-loop") {
|
|
1368
|
+
if (!node.noloop) {
|
|
1369
|
+
node.noloop = {};
|
|
1370
|
+
}
|
|
1371
|
+
if (arrowStack.includes(nodeId)) {
|
|
1372
|
+
return;
|
|
1373
|
+
}
|
|
1374
|
+
node.noloop[prevNodeId] = true;
|
|
1375
|
+
arrowStack = arrowStack.slice();
|
|
1376
|
+
arrowStack.push(nodeId);
|
|
1377
|
+
rewireArrowsInBranch(nodes, nodeId, node.one, arrowStack);
|
|
1378
|
+
} else if (node.type === "question") {
|
|
1379
|
+
var left = arrowStack.slice();
|
|
1380
|
+
var right = arrowStack.slice();
|
|
1381
|
+
rewireArrowsInBranch(nodes, nodeId, node.one, left);
|
|
1382
|
+
rewireArrowsInBranch(nodes, nodeId, node.two, right);
|
|
1383
|
+
} else if (node.type === "parbegin") {
|
|
1384
|
+
for (var proc of node.procs) {
|
|
1385
|
+
rewireArrowsInBranch(nodes, undefined, proc.start, []);
|
|
1386
|
+
}
|
|
1387
|
+
rewireArrowsInBranch(nodes, nodeId, node.one, arrowStack);
|
|
1388
|
+
} else {
|
|
1389
|
+
rewireArrowsInBranch(nodes, nodeId, node.one, arrowStack);
|
|
1072
1390
|
}
|
|
1391
|
+
}
|
|
1073
1392
|
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
|
-
} else if (node.type === "loopbegin") {
|
|
1095
|
-
var body2 = []
|
|
1096
|
-
index = rewriteTree(body, index, node.end, body2)
|
|
1097
|
-
output.push({
|
|
1098
|
-
id: node.id,
|
|
1099
|
-
type: "loop",
|
|
1100
|
-
content: node.content,
|
|
1101
|
-
body: body2
|
|
1102
|
-
})
|
|
1103
|
-
} else {
|
|
1104
|
-
output.push(node)
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
1393
|
+
function insertArrowStub(nodes, node) {
|
|
1394
|
+
var stub = {
|
|
1395
|
+
type: "arrow-stub",
|
|
1396
|
+
id: "arrow-stub-" + node.id,
|
|
1397
|
+
arrow: node.id,
|
|
1398
|
+
prev: [],
|
|
1399
|
+
};
|
|
1400
|
+
nodes[stub.id] = stub;
|
|
1401
|
+
node.stub = stub.id;
|
|
1402
|
+
var prev2 = [];
|
|
1403
|
+
for (var prevId of node.prev) {
|
|
1404
|
+
if (prevId in node.noloop) {
|
|
1405
|
+
prev2.push(prevId);
|
|
1406
|
+
} else {
|
|
1407
|
+
stub.prev.push(prevId);
|
|
1408
|
+
var prev = nodes[prevId];
|
|
1409
|
+
redirectNode(nodes, prev, node.id, stub.id);
|
|
1410
|
+
}
|
|
1107
1411
|
}
|
|
1412
|
+
node.prev = prev2;
|
|
1413
|
+
return stub;
|
|
1414
|
+
}
|
|
1108
1415
|
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
return
|
|
1117
|
-
}
|
|
1118
|
-
if (last.type === "question") {
|
|
1119
|
-
var qends = []
|
|
1120
|
-
findPlacesToBreak(last.yes, endId, qends)
|
|
1121
|
-
findPlacesToBreak(last.no, endId, qends)
|
|
1122
|
-
if (qends.length === 2
|
|
1123
|
-
&& qends[0] === last.yes
|
|
1124
|
-
&& qends[1] === last.no) {
|
|
1125
|
-
output.push(body)
|
|
1126
|
-
} else {
|
|
1127
|
-
addRange(output, qends)
|
|
1128
|
-
}
|
|
1129
|
-
} else {
|
|
1130
|
-
output.push(body)
|
|
1131
|
-
}
|
|
1132
|
-
}
|
|
1416
|
+
function onError(message, nodeId) {
|
|
1417
|
+
throw createError(
|
|
1418
|
+
translate(message),
|
|
1419
|
+
filename,
|
|
1420
|
+
nodeId
|
|
1421
|
+
);
|
|
1422
|
+
}
|
|
1133
1423
|
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
if (i === body.length - 1) {
|
|
1139
|
-
return true
|
|
1140
|
-
} else {
|
|
1141
|
-
throw createError(
|
|
1142
|
-
translate("An exit from the loop must lead to the point right after the loop end"),
|
|
1143
|
-
filename,
|
|
1144
|
-
node.id
|
|
1145
|
-
);
|
|
1146
|
-
}
|
|
1147
|
-
}
|
|
1148
|
-
if (node.type === "question") {
|
|
1149
|
-
if (findLoopEnd(node.yes, endId)) {
|
|
1150
|
-
return true
|
|
1151
|
-
}
|
|
1152
|
-
if (findLoopEnd(node.no, endId)) {
|
|
1153
|
-
return true
|
|
1154
|
-
}
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
return false
|
|
1158
|
-
}
|
|
1424
|
+
function structMain() {
|
|
1425
|
+
rewireArrows(nodes, branches);
|
|
1426
|
+
prepareQuestions(nodes);
|
|
1427
|
+
var result = [];
|
|
1159
1428
|
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
body.push({
|
|
1163
|
-
type: "break"
|
|
1164
|
-
})
|
|
1165
|
-
}
|
|
1429
|
+
for (var branch of branches) {
|
|
1430
|
+
flow_no_loop(nodes, branch.next, []);
|
|
1166
1431
|
}
|
|
1167
1432
|
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
}
|
|
1180
|
-
output.push(transformed)
|
|
1181
|
-
return transformed
|
|
1433
|
+
for (var branch of branches) {
|
|
1434
|
+
var body = [];
|
|
1435
|
+
buildTree(nodes, branch.next, body, "<dummy id>", undefined, onError);
|
|
1436
|
+
|
|
1437
|
+
result.push({
|
|
1438
|
+
name: branch.content,
|
|
1439
|
+
branchId: branch.branchId,
|
|
1440
|
+
id: branch.id,
|
|
1441
|
+
refs: branch.prev.length,
|
|
1442
|
+
body: optimizeTree(body),
|
|
1443
|
+
});
|
|
1182
1444
|
}
|
|
1183
|
-
|
|
1184
1445
|
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
prepareQuestions(nodes)
|
|
1188
|
-
var result = []
|
|
1189
|
-
for (var branch of branches) {
|
|
1190
|
-
flowGraph(nodes, branch.next, [])
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
for (var branch of branches) {
|
|
1194
|
-
var body = []
|
|
1195
|
-
buildTree(nodes, branch.next, body, "<dummy id>")
|
|
1196
|
-
var body2 = []
|
|
1197
|
-
rewriteTree(body, 0, undefined, body2)
|
|
1198
|
-
result.push({
|
|
1199
|
-
name: branch.content,
|
|
1200
|
-
branchId: branch.branchId,
|
|
1201
|
-
start: branch.next,
|
|
1202
|
-
refs: branch.prev.length,
|
|
1203
|
-
body: optimizeTree(body2)
|
|
1204
|
-
})
|
|
1205
|
-
}
|
|
1206
|
-
|
|
1207
|
-
return sortByProperty(result, "branchId")
|
|
1208
|
-
}
|
|
1446
|
+
return sortByProperty(result, "branchId");
|
|
1447
|
+
}
|
|
1209
1448
|
|
|
1210
|
-
|
|
1449
|
+
return structMain();
|
|
1211
1450
|
}
|
|
1212
1451
|
module.exports = { structFlow, redirectNode };
|
|
1213
|
-
|
|
1214
|
-
function
|
|
1452
|
+
|
|
1453
|
+
},{"./noloop":6,"./technicalTree":9,"./tools":10,"./treeTools":12}],9:[function(require,module,exports){
|
|
1454
|
+
function buildTree(nodes, nodeId, body, stopId, afterLoop, onError) {
|
|
1215
1455
|
while (nodeId) {
|
|
1216
|
-
if (nodeId ===
|
|
1456
|
+
if (nodeId === afterLoop) {
|
|
1457
|
+
body.push({type: "break"})
|
|
1458
|
+
return
|
|
1459
|
+
}
|
|
1460
|
+
if (nodeId === stopId) {
|
|
1461
|
+
return;
|
|
1462
|
+
}
|
|
1217
1463
|
const node = nodes[nodeId];
|
|
1218
1464
|
let transformed;
|
|
1219
1465
|
let next;
|
|
1220
1466
|
|
|
1221
1467
|
if (node.type === "question") {
|
|
1222
1468
|
next = reserveNext(nodes, node)
|
|
1223
|
-
|
|
1469
|
+
|
|
1224
1470
|
transformed = {
|
|
1225
1471
|
id: node.id,
|
|
1226
1472
|
type: "question",
|
|
@@ -1232,24 +1478,57 @@ function buildTree(nodes, nodeId, body, stopId) {
|
|
|
1232
1478
|
const yesNodeId = node.flag1 === 1 ? node.one : node.two;
|
|
1233
1479
|
const noNodeId = node.flag1 === 1 ? node.two : node.one;
|
|
1234
1480
|
|
|
1235
|
-
buildTree(nodes, yesNodeId, transformed.yes, node.next);
|
|
1236
|
-
buildTree(nodes, noNodeId, transformed.no, node.next);
|
|
1481
|
+
buildTree(nodes, yesNodeId, transformed.yes, node.next, afterLoop, onError);
|
|
1482
|
+
buildTree(nodes, noNodeId, transformed.no, node.next, afterLoop, onError);
|
|
1483
|
+
if (next === afterLoop) {
|
|
1484
|
+
next = undefined
|
|
1485
|
+
}
|
|
1486
|
+
} else if (node.type == "loopbegin") {
|
|
1487
|
+
transformed = {
|
|
1488
|
+
id: node.id,
|
|
1489
|
+
type: "loopbegin",
|
|
1490
|
+
content: node.content,
|
|
1491
|
+
end: node.end,
|
|
1492
|
+
body: []
|
|
1493
|
+
};
|
|
1494
|
+
var end = nodes[node.end]
|
|
1495
|
+
buildTree(nodes, node.one, transformed.body, node.end, end.one, onError)
|
|
1496
|
+
next = node.next;
|
|
1497
|
+
} else if (node.type == "loopend") {
|
|
1498
|
+
if (stopId !== afterLoop) {
|
|
1499
|
+
onError(
|
|
1500
|
+
"An exit from the loop must lead to the point right after the loop end",
|
|
1501
|
+
node.id
|
|
1502
|
+
)
|
|
1503
|
+
}
|
|
1504
|
+
return
|
|
1237
1505
|
} else if (node.type === "arrow-loop") {
|
|
1238
1506
|
transformed = {
|
|
1239
1507
|
id: node.id,
|
|
1240
1508
|
type: "loopbegin",
|
|
1241
1509
|
content: "",
|
|
1242
|
-
end: node.stub
|
|
1510
|
+
end: node.stub,
|
|
1511
|
+
body: []
|
|
1243
1512
|
};
|
|
1244
|
-
|
|
1245
|
-
|
|
1513
|
+
var end = nodes[node.stub]
|
|
1514
|
+
buildTree(nodes, node.one, transformed.body, node.stub, end.one, onError)
|
|
1515
|
+
next = node.next;
|
|
1246
1516
|
} else if (node.type === "arrow-stub") {
|
|
1517
|
+
return
|
|
1518
|
+
} else if (node.type === "parbegin") {
|
|
1247
1519
|
transformed = {
|
|
1248
1520
|
id: node.id,
|
|
1249
|
-
type:
|
|
1250
|
-
|
|
1251
|
-
}
|
|
1252
|
-
|
|
1521
|
+
type: node.type,
|
|
1522
|
+
procs: []
|
|
1523
|
+
}
|
|
1524
|
+
for (var proc of node.procs) {
|
|
1525
|
+
var childProc = {
|
|
1526
|
+
ordinal: proc.ordinal,
|
|
1527
|
+
body: []
|
|
1528
|
+
}
|
|
1529
|
+
transformed.procs.push(childProc)
|
|
1530
|
+
buildTree(nodes, proc.start, childProc.body, undefined, undefined, buildTree)
|
|
1531
|
+
}
|
|
1253
1532
|
next = node.one;
|
|
1254
1533
|
} else {
|
|
1255
1534
|
transformed = {
|
|
@@ -1268,8 +1547,13 @@ function buildTree(nodes, nodeId, body, stopId) {
|
|
|
1268
1547
|
]
|
|
1269
1548
|
)
|
|
1270
1549
|
next = node.one;
|
|
1550
|
+
if (node.final) {
|
|
1551
|
+
next = undefined
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
if (node.side) {
|
|
1555
|
+
transformed.side = node.side
|
|
1271
1556
|
}
|
|
1272
|
-
|
|
1273
1557
|
body.push(transformed);
|
|
1274
1558
|
nodeId = next;
|
|
1275
1559
|
}
|
|
@@ -1285,6 +1569,9 @@ function copyFields(dst, src, fields) {
|
|
|
1285
1569
|
}
|
|
1286
1570
|
|
|
1287
1571
|
function reserveNext(nodes, node) {
|
|
1572
|
+
if (!node.next) {
|
|
1573
|
+
return undefined
|
|
1574
|
+
}
|
|
1288
1575
|
const target = nodes[node.next];
|
|
1289
1576
|
if (target.targetTaken) {
|
|
1290
1577
|
return undefined;
|
|
@@ -1296,7 +1583,7 @@ function reserveNext(nodes, node) {
|
|
|
1296
1583
|
|
|
1297
1584
|
module.exports = {buildTree}
|
|
1298
1585
|
|
|
1299
|
-
},{}],
|
|
1586
|
+
},{}],10:[function(require,module,exports){
|
|
1300
1587
|
|
|
1301
1588
|
function createError(message, filename, nodeId) {
|
|
1302
1589
|
var error = new Error(message)
|
|
@@ -1337,7 +1624,7 @@ function addRange(to, from) {
|
|
|
1337
1624
|
}
|
|
1338
1625
|
}
|
|
1339
1626
|
module.exports = { createError, sortByProperty, addRange, remove }
|
|
1340
|
-
},{}],
|
|
1627
|
+
},{}],11:[function(require,module,exports){
|
|
1341
1628
|
var translationsRu = {
|
|
1342
1629
|
"error": "ОШИБКА",
|
|
1343
1630
|
"not": "не",
|
|
@@ -1366,7 +1653,13 @@ var translationsRu = {
|
|
|
1366
1653
|
"Description": "Описание",
|
|
1367
1654
|
"Algorithm": "Алгоритм",
|
|
1368
1655
|
Remarks: "Замечания",
|
|
1369
|
-
Parameters: "Параметры"
|
|
1656
|
+
Parameters: "Параметры",
|
|
1657
|
+
"Group of parallel processes": "Группа параллельных процессов",
|
|
1658
|
+
"Parallel process": "Параллельный процесс",
|
|
1659
|
+
"Start at": "Начать в",
|
|
1660
|
+
"Do for": "Делать в течение",
|
|
1661
|
+
"Pause": "Пауза",
|
|
1662
|
+
"Start timer": "Запустить таймер"
|
|
1370
1663
|
}
|
|
1371
1664
|
|
|
1372
1665
|
var translationsEn = {
|
|
@@ -1397,7 +1690,13 @@ var translationsEn = {
|
|
|
1397
1690
|
Description: 'Description',
|
|
1398
1691
|
Algorithm: 'Algorithm',
|
|
1399
1692
|
Remarks: "Remarks",
|
|
1400
|
-
Parameters: "Parameters"
|
|
1693
|
+
Parameters: "Parameters",
|
|
1694
|
+
"Group of parallel processes": "Group of parallel processes",
|
|
1695
|
+
"Parallel process": "Parallel process",
|
|
1696
|
+
"Start at": "Start at",
|
|
1697
|
+
"Do for": "Do for",
|
|
1698
|
+
"Pause": "Pause",
|
|
1699
|
+
"Start timer": "Start timer",
|
|
1401
1700
|
}
|
|
1402
1701
|
|
|
1403
1702
|
var translationsNo = {
|
|
@@ -1428,9 +1727,162 @@ var translationsNo = {
|
|
|
1428
1727
|
Description: 'Beskrivelse',
|
|
1429
1728
|
Algorithm: 'Algoritme',
|
|
1430
1729
|
Remarks: "Bemerkninger",
|
|
1431
|
-
Parameters: "Parametere"
|
|
1730
|
+
Parameters: "Parametere",
|
|
1731
|
+
"Group of parallel processes": "Gruppe av parallelle prosesser",
|
|
1732
|
+
"Parallel process": "Parallell prosess",
|
|
1733
|
+
"Start at": "Start ved",
|
|
1734
|
+
"Do for": "Gjør i",
|
|
1735
|
+
"Pause": "Pause",
|
|
1736
|
+
"Start timer": "Start tidtaker"
|
|
1737
|
+
};
|
|
1738
|
+
|
|
1739
|
+
var translationsFr = {
|
|
1740
|
+
error: 'Erreur',
|
|
1741
|
+
not: 'non',
|
|
1742
|
+
break: 'quitter la boucle',
|
|
1743
|
+
and: 'et',
|
|
1744
|
+
or: 'ou',
|
|
1745
|
+
if: 'Si',
|
|
1746
|
+
else: 'Sinon',
|
|
1747
|
+
empty: 'Vide',
|
|
1748
|
+
'loop forever': 'Boucler indéfiniment',
|
|
1749
|
+
pass: 'Ignorer',
|
|
1750
|
+
'Only the rightmost Case icon can be empty': "Seule l'icône Case la plus à droite peut être vide",
|
|
1751
|
+
'Error parsing JSON': "Erreur lors de l'analyse du JSON",
|
|
1752
|
+
'A Loop begin icon must have content': "Une icône de début de boucle doit avoir un contenu",
|
|
1753
|
+
'A Question icon must have content': "Une icône Question doit avoir un contenu",
|
|
1754
|
+
'A Select icon must have content': "Une icône Select doit avoir un contenu",
|
|
1755
|
+
'Unexpected case value': 'Valeur de cas inattendue',
|
|
1756
|
+
'Loop end expected here': 'Fin de boucle attendue ici',
|
|
1757
|
+
'An exit from the loop must lead to the point right after the loop end': 'Une sortie de boucle doit mener au point situé juste après la fin de la boucle',
|
|
1758
|
+
'A silhouette branch is not referenced': "Une branche de silhouette n'est pas référencée",
|
|
1759
|
+
'Call subroutine': 'Appeler la sous-routine',
|
|
1760
|
+
Procedure: 'Procédure',
|
|
1761
|
+
'End of procedure': 'Fin de la procédure',
|
|
1762
|
+
Subroutine: 'Sous-routine',
|
|
1763
|
+
'End of subroutine': 'Fin de la sous-routine',
|
|
1764
|
+
Description: 'Description',
|
|
1765
|
+
Algorithm: 'Algorithme',
|
|
1766
|
+
Remarks: 'Remarques',
|
|
1767
|
+
Parameters: 'Paramètres',
|
|
1768
|
+
'Group of parallel processes': 'Groupe de processus parallèles',
|
|
1769
|
+
'Parallel process': 'Processus parallèle',
|
|
1770
|
+
'Start at': 'Commencer à',
|
|
1771
|
+
'Do for': 'Exécuter pendant',
|
|
1772
|
+
'Pause': 'Pause',
|
|
1773
|
+
'Start timer': 'Démarrer le minuteur'
|
|
1432
1774
|
};
|
|
1433
1775
|
|
|
1776
|
+
var translationsDe = {
|
|
1777
|
+
error: 'Fehler',
|
|
1778
|
+
not: 'nicht',
|
|
1779
|
+
break: 'Schleife beenden',
|
|
1780
|
+
and: 'und',
|
|
1781
|
+
or: 'oder',
|
|
1782
|
+
if: 'Wenn',
|
|
1783
|
+
else: 'Sonst',
|
|
1784
|
+
empty: 'Leer',
|
|
1785
|
+
'loop forever': 'Endlos wiederholen',
|
|
1786
|
+
pass: 'Überspringen',
|
|
1787
|
+
'Only the rightmost Case icon can be empty': 'Nur das äußerste rechte Case-Symbol darf leer sein',
|
|
1788
|
+
'Error parsing JSON': 'Fehler beim Parsen von JSON',
|
|
1789
|
+
'A Loop begin icon must have content': 'Ein Schleifenstart-Symbol muss Inhalt haben',
|
|
1790
|
+
'A Question icon must have content': 'Ein Frage-Symbol muss Inhalt haben',
|
|
1791
|
+
'A Select icon must have content': 'Ein Auswahl-Symbol muss Inhalt haben',
|
|
1792
|
+
'Unexpected case value': 'Unerwarteter Fallwert',
|
|
1793
|
+
'Loop end expected here': 'Schleifenende wird hier erwartet',
|
|
1794
|
+
'An exit from the loop must lead to the point right after the loop end': 'Ein Ausgang aus der Schleife muss direkt hinter das Schleifenende führen',
|
|
1795
|
+
'A silhouette branch is not referenced': 'Ein Silhouettenzweig wird nicht referenziert',
|
|
1796
|
+
'Call subroutine': 'Unterprogramm aufrufen',
|
|
1797
|
+
Procedure: 'Prozedur',
|
|
1798
|
+
'End of procedure': 'Ende der Prozedur',
|
|
1799
|
+
Subroutine: 'Unterprogramm',
|
|
1800
|
+
'End of subroutine': 'Ende des Unterprogramms',
|
|
1801
|
+
Description: 'Beschreibung',
|
|
1802
|
+
Algorithm: 'Algorithmus',
|
|
1803
|
+
Remarks: 'Bemerkungen',
|
|
1804
|
+
Parameters: 'Parameter',
|
|
1805
|
+
'Group of parallel processes': 'Gruppe paralleler Prozesse',
|
|
1806
|
+
'Parallel process': 'Paralleler Prozess',
|
|
1807
|
+
'Start at': 'Starten bei',
|
|
1808
|
+
'Do for': 'Ausführen für',
|
|
1809
|
+
'Pause': 'Pause',
|
|
1810
|
+
'Start timer': 'Timer starten'
|
|
1811
|
+
};
|
|
1812
|
+
|
|
1813
|
+
var translationsEs = {
|
|
1814
|
+
error: 'Error',
|
|
1815
|
+
not: 'no',
|
|
1816
|
+
break: 'salir del bucle',
|
|
1817
|
+
and: 'y',
|
|
1818
|
+
or: 'o',
|
|
1819
|
+
if: 'Si',
|
|
1820
|
+
else: 'De lo contrario',
|
|
1821
|
+
empty: 'Vacío',
|
|
1822
|
+
'loop forever': 'Repetir para siempre',
|
|
1823
|
+
pass: 'Omitir',
|
|
1824
|
+
'Only the rightmost Case icon can be empty': 'Solo el icono Case más a la derecha puede estar vacío',
|
|
1825
|
+
'Error parsing JSON': 'Error al analizar JSON',
|
|
1826
|
+
'A Loop begin icon must have content': 'Un icono de inicio de bucle debe tener contenido',
|
|
1827
|
+
'A Question icon must have content': 'Un icono de Pregunta debe tener contenido',
|
|
1828
|
+
'A Select icon must have content': 'Un icono de Selección debe tener contenido',
|
|
1829
|
+
'Unexpected case value': 'Valor de caso inesperado',
|
|
1830
|
+
'Loop end expected here': 'Se esperaba el final del bucle aquí',
|
|
1831
|
+
'An exit from the loop must lead to the point right after the loop end': 'Una salida del bucle debe conducir al punto inmediatamente después del final del bucle',
|
|
1832
|
+
'A silhouette branch is not referenced': 'Una rama de silueta no está referenciada',
|
|
1833
|
+
'Call subroutine': 'Llamar subrutina',
|
|
1834
|
+
Procedure: 'Procedimiento',
|
|
1835
|
+
'End of procedure': 'Fin del procedimiento',
|
|
1836
|
+
Subroutine: 'Subrutina',
|
|
1837
|
+
'End of subroutine': 'Fin de la subrutina',
|
|
1838
|
+
Description: 'Descripción',
|
|
1839
|
+
Algorithm: 'Algoritmo',
|
|
1840
|
+
Remarks: 'Observaciones',
|
|
1841
|
+
Parameters: 'Parámetros',
|
|
1842
|
+
'Group of parallel processes': 'Grupo de procesos paralelos',
|
|
1843
|
+
'Parallel process': 'Proceso paralelo',
|
|
1844
|
+
'Start at': 'Comenzar en',
|
|
1845
|
+
'Do for': 'Ejecutar durante',
|
|
1846
|
+
'Pause': 'Pausa',
|
|
1847
|
+
'Start timer': 'Iniciar temporizador'
|
|
1848
|
+
};
|
|
1849
|
+
|
|
1850
|
+
var translationsLt = {
|
|
1851
|
+
error: 'Klaida',
|
|
1852
|
+
not: 'ne',
|
|
1853
|
+
break: 'nutraukti ciklą',
|
|
1854
|
+
and: 'ir',
|
|
1855
|
+
or: 'arba',
|
|
1856
|
+
if: 'Jei',
|
|
1857
|
+
else: 'Kitaip',
|
|
1858
|
+
empty: 'Tuščias',
|
|
1859
|
+
'loop forever': 'Kartoti amžinai',
|
|
1860
|
+
pass: 'Praleisti',
|
|
1861
|
+
'Only the rightmost Case icon can be empty': 'Tik dešiniausia Case piktograma gali būti tuščia',
|
|
1862
|
+
'Error parsing JSON': 'Klaida analizuojant JSON',
|
|
1863
|
+
'A Loop begin icon must have content': 'Ciklo pradžios piktograma turi turėti turinį',
|
|
1864
|
+
'A Question icon must have content': 'Klausimo piktograma turi turėti turinį',
|
|
1865
|
+
'A Select icon must have content': 'Pasirinkimo piktograma turi turėti turinį',
|
|
1866
|
+
'Unexpected case value': 'Netikėta atvejo reikšmė',
|
|
1867
|
+
'Loop end expected here': 'Čia tikimasi ciklo pabaigos',
|
|
1868
|
+
'An exit from the loop must lead to the point right after the loop end': 'Išėjimas iš ciklo turi vesti į tašką iškart po ciklo pabaigos',
|
|
1869
|
+
'A silhouette branch is not referenced': 'Silueto šaka nėra susieta',
|
|
1870
|
+
'Call subroutine': 'Kviesti paprogramę',
|
|
1871
|
+
Procedure: 'Procedūra',
|
|
1872
|
+
'End of procedure': 'Procedūros pabaiga',
|
|
1873
|
+
Subroutine: 'Paprogramė',
|
|
1874
|
+
'End of subroutine': 'Paprogramės pabaiga',
|
|
1875
|
+
Description: 'Aprašymas',
|
|
1876
|
+
Algorithm: 'Algoritmas',
|
|
1877
|
+
Remarks: 'Pastabos',
|
|
1878
|
+
Parameters: 'Parametrai',
|
|
1879
|
+
'Group of parallel processes': 'Lygiagrečių procesų grupė',
|
|
1880
|
+
'Parallel process': 'Lygiagretus procesas',
|
|
1881
|
+
'Start at': 'Pradėti nuo',
|
|
1882
|
+
'Do for': 'Vykdyti',
|
|
1883
|
+
'Pause': 'Pauzė',
|
|
1884
|
+
'Start timer': 'Paleisti laikmatį'
|
|
1885
|
+
};
|
|
1434
1886
|
|
|
1435
1887
|
var translations = translationsEn
|
|
1436
1888
|
|
|
@@ -1445,14 +1897,21 @@ function setUpLanguage(language) {
|
|
|
1445
1897
|
translations = translationsNo
|
|
1446
1898
|
} else if (language === "en") {
|
|
1447
1899
|
translations = translationsEn
|
|
1900
|
+
} else if (language === "fr") {
|
|
1901
|
+
translations = translationsFr
|
|
1902
|
+
} else if (language === "de") {
|
|
1903
|
+
translations = translationsDe
|
|
1904
|
+
} else if (language === "es") {
|
|
1905
|
+
translations = translationsEs
|
|
1906
|
+
} else if (language === "lt") {
|
|
1907
|
+
translations = translationsLt
|
|
1448
1908
|
} else {
|
|
1449
1909
|
translations = {}
|
|
1450
1910
|
}
|
|
1451
1911
|
}
|
|
1452
1912
|
|
|
1453
|
-
|
|
1454
1913
|
module.exports = { setUpLanguage, translate };
|
|
1455
|
-
},{}],
|
|
1914
|
+
},{}],12:[function(require,module,exports){
|
|
1456
1915
|
|
|
1457
1916
|
function optimizeTree(steps) {
|
|
1458
1917
|
var result = []
|
|
@@ -1460,54 +1919,85 @@ function optimizeTree(steps) {
|
|
|
1460
1919
|
for (var step of steps) {
|
|
1461
1920
|
if (step.type === "end" || step.type === "branch" || step.type === "loopend") { continue }
|
|
1462
1921
|
if ((step.type === "action" || step.type === "comment") && !step.content) { continue }
|
|
1463
|
-
var copy
|
|
1464
1922
|
if (step.type === "question") {
|
|
1465
|
-
|
|
1466
|
-
} else if (step.type === "
|
|
1467
|
-
|
|
1923
|
+
optimizeQuestion(step, result)
|
|
1924
|
+
} else if (step.type === "parbegin") {
|
|
1925
|
+
optimizeParbegin(step, result)
|
|
1926
|
+
} else if (step.type === "loop" || step.type === "loopbegin") {
|
|
1927
|
+
optimizeLoop(step, result)
|
|
1468
1928
|
} else {
|
|
1469
|
-
|
|
1929
|
+
result.push(step)
|
|
1470
1930
|
}
|
|
1471
|
-
result.push(copy)
|
|
1472
1931
|
}
|
|
1473
1932
|
|
|
1474
1933
|
return result
|
|
1475
1934
|
}
|
|
1476
1935
|
|
|
1477
|
-
function
|
|
1478
|
-
|
|
1936
|
+
function optimizeParbegin(step, output) {
|
|
1937
|
+
var procs = []
|
|
1938
|
+
for (var proc of step.procs) {
|
|
1939
|
+
var procCopy = {
|
|
1940
|
+
ordinal: proc.ordinal,
|
|
1941
|
+
body: optimizeTree(proc.body)
|
|
1942
|
+
}
|
|
1943
|
+
procs.push(procCopy)
|
|
1944
|
+
}
|
|
1945
|
+
output.push({
|
|
1479
1946
|
id: step.id,
|
|
1480
1947
|
type: step.type,
|
|
1948
|
+
procs: procs
|
|
1949
|
+
})
|
|
1950
|
+
}
|
|
1951
|
+
|
|
1952
|
+
function optimizeLoop(step, output) {
|
|
1953
|
+
output.push({
|
|
1954
|
+
id: step.id,
|
|
1955
|
+
type: "loop",
|
|
1481
1956
|
content: step.content,
|
|
1482
1957
|
body: optimizeTree(step.body)
|
|
1958
|
+
})
|
|
1959
|
+
}
|
|
1960
|
+
|
|
1961
|
+
function endsWithBreak(body) {
|
|
1962
|
+
if (body.length === 0) {
|
|
1963
|
+
return false
|
|
1483
1964
|
}
|
|
1965
|
+
var lastId = body.length - 1
|
|
1966
|
+
return body[lastId].type === "break"
|
|
1484
1967
|
}
|
|
1485
1968
|
|
|
1486
|
-
function optimizeQuestion(step) {
|
|
1969
|
+
function optimizeQuestion(step, output) {
|
|
1487
1970
|
var yes = optimizeTree(step.yes)
|
|
1488
1971
|
var no = optimizeTree(step.no)
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
}
|
|
1497
|
-
if (yes.length === 0) {
|
|
1498
|
-
return {
|
|
1499
|
-
type: step.type,
|
|
1500
|
-
content: {operator:"not",operand:step.content},
|
|
1501
|
-
yes: no,
|
|
1502
|
-
no: []
|
|
1503
|
-
}
|
|
1972
|
+
var breakYes = endsWithBreak(yes)
|
|
1973
|
+
var breakNo = endsWithBreak(no)
|
|
1974
|
+
|
|
1975
|
+
var result = {
|
|
1976
|
+
id: step.id,
|
|
1977
|
+
side: step.side,
|
|
1978
|
+
type: step.type
|
|
1504
1979
|
}
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
yes: yes,
|
|
1509
|
-
no: no
|
|
1980
|
+
if (breakYes && breakNo) {
|
|
1981
|
+
yes.pop()
|
|
1982
|
+
no.pop()
|
|
1510
1983
|
}
|
|
1984
|
+
if (yes.length === 0 && no.length === 0) {
|
|
1985
|
+
result.content = step.content
|
|
1986
|
+
result.yes = []
|
|
1987
|
+
result.no = []
|
|
1988
|
+
} else if (yes.length === 0) {
|
|
1989
|
+
result.content = {operator:"not",operand:step.content}
|
|
1990
|
+
result.yes = no
|
|
1991
|
+
result.no = []
|
|
1992
|
+
} else {
|
|
1993
|
+
result.content = step.content,
|
|
1994
|
+
result.yes = yes,
|
|
1995
|
+
result.no = no
|
|
1996
|
+
}
|
|
1997
|
+
output.push(result)
|
|
1998
|
+
if (breakYes && breakNo) {
|
|
1999
|
+
output.push({type: "break"})
|
|
2000
|
+
}
|
|
1511
2001
|
}
|
|
1512
2002
|
|
|
1513
2003
|
|