drakongen 1.4.4 → 1.4.7

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 (60) hide show
  1. package/browser/drakongen.js +403 -329
  2. package/exampleproject/.drakontech/history.json +12 -0
  3. package/exampleproject/.drakontech/opened.txt +1 -0
  4. package/exampleproject/foo.drakon +23 -10
  5. package/exampleproject/foo.txt +13 -6
  6. package/exampleproject/math/approximately equal.drakon +15 -7
  7. package/exampleproject/solution.json +3 -0
  8. package/examples/.drakontech/history.json +124 -0
  9. package/examples/.drakontech/opened.txt +1 -0
  10. package/examples/01. /320/221/320/265/320/273/321/213/320/271.txt" +1 -1
  11. package/examples/02. /320/247/321/221/321/200/320/275/321/213/320/271.txt" +1 -1
  12. package/examples/03. /320/241/320/265/321/200/321/213/320/271.txt" +1 -1
  13. package/examples/04. /320/221/321/203/321/200/321/213/320/271.txt" +1 -1
  14. package/examples/05. /320/226/321/221/320/273/321/202/321/213/320/271.txt" +1 -1
  15. package/examples/06. /320/221/320/260/320/263/321/200/320/276/320/262/321/213/320/271.txt" +1 -1
  16. package/examples/07. /320/244/320/270/320/276/320/273/320/265/321/202/320/276/320/262/321/213/320/271.txt" +1 -1
  17. package/examples/08. /320/221/320/270/321/200/321/216/320/267/320/276/320/262/321/213/320/271.txt" +1 -1
  18. package/examples/09. /320/236/321/200/320/260/320/275/320/266/320/265/320/262/321/213/320/271.txt" +1 -1
  19. package/examples/10. /320/240/320/276/320/267/320/276/320/262/321/213/320/271.txt" +1 -1
  20. package/examples/11. /320/227/320/260/321/211/320/270/321/202/320/275/321/213/320/271.txt" +1 -1
  21. package/examples/12. /320/221/320/276/320/273/320/276/321/202/320/275/321/213/320/271.txt" +1 -1
  22. package/examples/13. /320/241/320/260/320/273/320/260/321/202/320/276/320/262/321/213/320/271.txt" +1 -1
  23. package/examples/14. /320/227/320/276/320/273/320/276/321/202/320/276/320/271.txt" +1 -1
  24. package/examples/15. /320/241/320/270/320/275/320/270/320/271.txt" +1 -1
  25. package/examples/16. /320/223/320/276/320/273/321/203/320/261/320/276/320/271.txt" +1 -1
  26. package/examples/17. /320/241/320/260/320/273/320/260/321/202/320/276/320/262/321/213/320/271.txt" +1 -1
  27. package/examples/18. /320/241/321/202/320/260/320/273/321/214/320/275/320/276/320/271.txt" +1 -1
  28. package/examples/How to tune PID on a quadcopter.txt +12 -12
  29. package/examples/Logical_And.drakon +37 -0
  30. package/examples/Logical_And.txt +9 -0
  31. package/examples/Logical_And_Inv.drakon +37 -0
  32. package/examples/Logical_And_Inv.txt +9 -0
  33. package/examples/Logical_And_Inv_x2.drakon +91 -0
  34. package/examples/Logical_And_Inv_x2.txt +15 -0
  35. package/examples/Logical_Or.drakon +37 -0
  36. package/examples/Logical_Or.txt +9 -0
  37. package/examples/Logical_Or_Inv.drakon +37 -0
  38. package/examples/Logical_Or_Inv.txt +9 -0
  39. package/package.json +1 -1
  40. package/src/drakonToStruct.js +394 -325
  41. package/src/translate.js +3 -0
  42. package/src/treeTools.js +1 -0
  43. /package/examples/01. /320/221/320/265/320/273/321/213/320/{270/314/206.drakon" → 271.drakon"} +0 -0
  44. /package/examples/02. /320/247/{320/265/314/210/321/200/320/275/321/213/320/270/314/206.drakon" → 321/221/321/200/320/275/321/213/320/271.drakon"} +0 -0
  45. /package/examples/03. /320/241/320/265/321/200/321/213/320/{270/314/206.drakon" → 271.drakon"} +0 -0
  46. /package/examples/04. /320/221/321/203/321/200/321/213/320/{270/314/206.drakon" → 271.drakon"} +0 -0
  47. /package/examples/05. /320/226/{320/265/314/210/320/273/321/202/321/213/320/270/314/206.drakon" → 321/221/320/273/321/202/321/213/320/271.drakon"} +0 -0
  48. /package/examples/06. /320/221/320/260/320/263/321/200/320/276/320/262/321/213/320/{270/314/206.drakon" → 271.drakon"} +0 -0
  49. /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" → 271.drakon"} +0 -0
  50. /package/examples/08. /320/221/320/270/321/200/321/216/320/267/320/276/320/262/321/213/320/{270/314/206.drakon" → 271.drakon"} +0 -0
  51. /package/examples/09. /320/236/321/200/320/260/320/275/320/266/320/265/320/262/321/213/320/{270/314/206.drakon" → 271.drakon"} +0 -0
  52. /package/examples/10. /320/240/320/276/320/267/320/276/320/262/321/213/320/{270/314/206.drakon" → 271.drakon"} +0 -0
  53. /package/examples/11. /320/227/320/260/321/211/320/270/321/202/320/275/321/213/320/{270/314/206.drakon" → 271.drakon"} +0 -0
  54. /package/examples/12. /320/221/320/276/320/273/320/276/321/202/320/275/321/213/320/{270/314/206.drakon" → 271.drakon"} +0 -0
  55. /package/examples/13. /320/241/320/260/320/273/320/260/321/202/320/276/320/262/321/213/320/{270/314/206.drakon" → 271.drakon"} +0 -0
  56. /package/examples/14. /320/227/320/276/320/273/320/276/321/202/320/276/320/{270/314/206.drakon" → 271.drakon"} +0 -0
  57. /package/examples/15. /320/241/320/270/320/275/320/270/320/{270/314/206.drakon" → 271.drakon"} +0 -0
  58. /package/examples/16. /320/223/320/276/320/273/321/203/320/261/320/276/320/{270/314/206.drakon" → 271.drakon"} +0 -0
  59. /package/examples/17. /320/241/320/260/320/273/320/260/321/202/320/276/320/262/321/213/320/{270/314/206.drakon" → 271.drakon"} +0 -0
  60. /package/examples/18. /320/241/321/202/320/260/320/273/321/214/320/275/320/276/320/{270/314/206.drakon" → 271.drakon"} +0 -0
@@ -157,420 +157,490 @@ module.exports = { drakonToPseudocode, mindToTree };
157
157
  const { structFlow, redirectNode } = require("./structFlow");
158
158
  const { createError, remove } = require("./tools");
159
159
 
160
- var translate
160
+ var translate;
161
161
 
162
162
  function drakonToStruct(drakonJson, name, filename, translateFunction) {
163
- translate = translateFunction
164
- let drakonGraph;
165
- try {
166
- drakonJson = drakonJson || ""
167
- drakonJson = drakonJson.trim()
168
- drakonJson = drakonJson || "{}"
169
- drakonGraph = JSON.parse(drakonJson);
170
- } catch (error) {
171
- var message = translate("Error parsing JSON") + ": " + error.message
172
- throw createError(message, filename)
173
- }
174
-
175
- const nodes = drakonGraph.items || {};
176
-
177
- var branches = []
178
- var firstNodeId = findStartNode(nodes, filename, branches)
179
-
180
- if (!firstNodeId) {
181
- return {
182
- name: name,
183
- params: drakonGraph.params || "",
184
- description: drakonGraph.description || "",
185
- branches: []
186
- }
187
- }
188
-
189
- buildTwoWayConnections(nodes, firstNodeId)
190
-
191
- rewireSelectsMarkLoops(nodes, filename)
192
- branches.forEach(branch => checkBranchIsReferenced(branch, firstNodeId, filename))
193
- rewireShortcircuit(nodes, filename)
194
- branches.forEach(branch => cutOffBranch(nodes, branch))
195
- var branchTrees = structFlow(nodes, branches, filename, translate)
163
+ translate = translateFunction;
164
+ let drakonGraph;
165
+ try {
166
+ drakonJson = drakonJson || "";
167
+ drakonJson = drakonJson.trim();
168
+ drakonJson = drakonJson || "{}";
169
+ drakonGraph = JSON.parse(drakonJson);
170
+ } catch (error) {
171
+ var message = translate("Error parsing JSON") + ": " + error.message;
172
+ throw createError(message, filename);
173
+ }
174
+
175
+ const nodes = drakonGraph.items || {};
176
+
177
+ var branches = [];
178
+ var firstNodeId = findStartNode(nodes, filename, branches);
179
+
180
+ if (!firstNodeId) {
196
181
  return {
197
- name: name,
198
- params: drakonGraph.params || "",
199
- description: drakonGraph.description || "",
200
- branches: branchTrees
201
- }
182
+ name: name,
183
+ params: drakonGraph.params || "",
184
+ description: drakonGraph.description || "",
185
+ branches: [],
186
+ };
187
+ }
188
+
189
+ buildTwoWayConnections(nodes, firstNodeId);
190
+
191
+ rewireSelectsMarkLoops(nodes, filename);
192
+ branches.forEach((branch) =>
193
+ checkBranchIsReferenced(branch, firstNodeId, filename),
194
+ );
195
+ rewireShortcircuit(nodes, filename);
196
+ branches.forEach((branch) => cutOffBranch(nodes, branch));
197
+ var branchTrees = structFlow(nodes, branches, filename, translate);
198
+ return {
199
+ name: name,
200
+ params: drakonGraph.params || "",
201
+ description: drakonGraph.description || "",
202
+ branches: branchTrees,
203
+ };
202
204
  }
203
205
 
204
206
  function drakonToGraph(drakonJson, name, filename, translateFunction) {
205
- translate = translateFunction
206
- let drakonGraph;
207
- try {
208
- drakonGraph = JSON.parse(drakonJson);
209
- } catch (error) {
210
- var message = translate("Error parsing JSON") + ": " + error.message
211
- throw createError(message, filename)
212
- }
213
-
214
- const nodes = drakonGraph.items || {};
215
-
216
- var branches = []
217
- var firstNodeId = findStartNode(nodes, filename, branches)
218
-
219
- if (!firstNodeId) {
220
- return undefined
221
- }
222
-
223
- buildTwoWayConnections(nodes, firstNodeId)
224
-
225
- rewireSelectsMarkLoops(nodes, filename)
226
- rewireShortcircuit(nodes, filename)
227
- branches.forEach(branch => checkBranchIsReferenced(branch, firstNodeId, filename))
228
- branches.forEach(branch => cutOffBranch(nodes, branch))
229
-
230
- var branchTrees = structFlow(nodes, branches, filename, translate)
231
-
232
- return {
233
- name: name,
234
- params: drakonGraph.params || "",
235
- description: drakonGraph.description || "",
236
- branches: branchTrees
237
- }
207
+ translate = translateFunction;
208
+ let drakonGraph;
209
+ try {
210
+ drakonGraph = JSON.parse(drakonJson);
211
+ } catch (error) {
212
+ var message = translate("Error parsing JSON") + ": " + error.message;
213
+ throw createError(message, filename);
214
+ }
215
+
216
+ const nodes = drakonGraph.items || {};
217
+
218
+ var branches = [];
219
+ var firstNodeId = findStartNode(nodes, filename, branches);
220
+
221
+ if (!firstNodeId) {
222
+ return undefined;
223
+ }
224
+
225
+ buildTwoWayConnections(nodes, firstNodeId);
226
+
227
+ rewireSelectsMarkLoops(nodes, filename);
228
+ rewireShortcircuit(nodes, filename);
229
+ branches.forEach((branch) =>
230
+ checkBranchIsReferenced(branch, firstNodeId, filename),
231
+ );
232
+ branches.forEach((branch) => cutOffBranch(nodes, branch));
233
+
234
+ var branchTrees = structFlow(nodes, branches, filename, translate);
235
+
236
+ return {
237
+ name: name,
238
+ params: drakonGraph.params || "",
239
+ description: drakonGraph.description || "",
240
+ branches: branchTrees,
241
+ };
238
242
  }
239
243
 
240
-
241
244
  function checkBranchIsReferenced(branch, firstNodeId, filename) {
242
- if (branch.id === firstNodeId) {
243
- return
244
- }
245
- if (branch.prev.length === 0) {
246
- throw createError(translate("A silhouette branch is not referenced"), filename, branch.id)
247
- }
245
+ if (branch.id === firstNodeId) {
246
+ return;
247
+ }
248
+ if (branch.prev.length === 0) {
249
+ throw createError(
250
+ translate("A silhouette branch is not referenced"),
251
+ filename,
252
+ branch.id,
253
+ );
254
+ }
248
255
  }
249
256
 
250
257
  function cutOffBranch(nodes, branch) {
251
- var end = {
252
- type: "end",
253
- id: branch.id + "-end",
254
- prev: []
255
- }
256
- nodes[end.id] = end
257
- branch.next = branch.one
258
- var addresses = []
259
- traverseToHitBranch(nodes, branch.id, {}, (prev, node) => addFakeEnd(nodes, prev, node, end, addresses))
258
+ var end = {
259
+ type: "end",
260
+ id: branch.id + "-end",
261
+ prev: [],
262
+ };
263
+ nodes[end.id] = end;
264
+ branch.next = branch.one;
265
+ var addresses = [];
266
+ traverseToHitBranch(nodes, branch.id, {}, (prev, node) =>
267
+ addFakeEnd(nodes, prev, node, end, addresses),
268
+ );
260
269
  }
261
270
 
262
271
  function traverseToHitBranch(nodes, nodeId, visited, action) {
263
- if (!nodeId) {return}
264
- if (nodeId in visited) {return}
265
- visited[nodeId] = true
266
- var node = nodes[nodeId]
267
- if (!node) {return}
268
- if (node.one) {
269
- var one = nodes[node.one]
270
- if (one.type === "branch") {
271
- action(node, one)
272
- } else {
273
- traverseToHitBranch(nodes, node.one, visited, action)
274
- }
272
+ if (!nodeId) {
273
+ return;
274
+ }
275
+ if (nodeId in visited) {
276
+ return;
277
+ }
278
+ visited[nodeId] = true;
279
+ var node = nodes[nodeId];
280
+ if (!node) {
281
+ return;
282
+ }
283
+ if (node.one) {
284
+ var one = nodes[node.one];
285
+ if (one.type === "branch") {
286
+ action(node, one);
287
+ } else {
288
+ traverseToHitBranch(nodes, node.one, visited, action);
275
289
  }
276
- if (node.two) {
277
- var two = nodes[node.two]
278
- if (two.type === "branch") {
279
- action(node, two)
280
- } else {
281
- traverseToHitBranch(nodes, node.two, visited, action)
282
- }
283
- }
290
+ }
291
+ if (node.two) {
292
+ var two = nodes[node.two];
293
+ if (two.type === "branch") {
294
+ action(node, two);
295
+ } else {
296
+ traverseToHitBranch(nodes, node.two, visited, action);
297
+ }
298
+ }
284
299
  }
285
300
 
286
- var idCounter = 1000
301
+ var idCounter = 1000;
287
302
  function addFakeEnd(nodes, prev, node, end, addresses) {
288
- var lastAddress = undefined
289
- if (addresses.length > 0) {
290
- lastAddress = addresses[addresses.length - 1]
291
- }
292
- var address
293
- if (lastAddress && lastAddress.branch === node.id) {
294
- address = lastAddress
295
- } else {
296
- address = {
297
- type: "address",
298
- content: node.content,
299
- id: "ad-" + idCounter,
300
- branch: node.id,
301
- one: end.id,
302
- prev: []
303
- }
304
- idCounter++
305
- nodes[address.id] = address
306
- end.prev.push(address.id)
307
- addresses.push(address)
308
- node.prev.push(address.id)
309
- }
310
- redirectNode(nodes, prev, node.id, address.id)
311
- address.prev.push(prev.id)
312
- node.prev = remove(node.prev, prev.id)
303
+ var lastAddress = undefined;
304
+ if (addresses.length > 0) {
305
+ lastAddress = addresses[addresses.length - 1];
306
+ }
307
+ var address;
308
+ if (lastAddress && lastAddress.branch === node.id) {
309
+ address = lastAddress;
310
+ } else {
311
+ address = {
312
+ type: "address",
313
+ content: node.content,
314
+ id: "ad-" + idCounter,
315
+ branch: node.id,
316
+ one: end.id,
317
+ prev: [],
318
+ };
319
+ idCounter++;
320
+ nodes[address.id] = address;
321
+ end.prev.push(address.id);
322
+ addresses.push(address);
323
+ node.prev.push(address.id);
324
+ }
325
+ redirectNode(nodes, prev, node.id, address.id);
326
+ address.prev.push(prev.id);
327
+ node.prev = remove(node.prev, prev.id);
313
328
  }
314
329
 
315
330
  function buildTwoWayConnections(nodes, firstNodeId) {
316
- for (var id in nodes) {
317
- var node = nodes[id]
318
- node.id = id
319
- node.prev = []
320
- }
331
+ for (var id in nodes) {
332
+ var node = nodes[id];
333
+ node.id = id;
334
+ node.prev = [];
335
+ }
321
336
 
322
- traverse(nodes, firstNodeId, {}, connectBack)
337
+ traverse(nodes, firstNodeId, {}, connectBack);
323
338
  }
324
339
 
325
340
  function findStartNode(nodes, filename, branches) {
326
- var firstNodeId = undefined
327
- var minBranchId = 10000
328
- for (var id in nodes) {
329
- var node = nodes[id]
330
- if (node.type === "branch") {
331
- if (node.branchId < minBranchId) {
332
- firstNodeId = id
333
- minBranchId = node.branchId
334
- }
335
- branches.push(node)
336
- } else if (node.type === "select") {
337
- if (!node.content) {
338
- throw createError(translate("A Select icon must have content"), filename, id)
339
- }
340
- node.cases = [];
341
- } else if (node.type === "loopbegin") {
342
- if (!node.content) {
343
- throw createError(translate("A Loop begin icon must have content"), filename, id)
344
- }
345
- } else if (node.type === "question") {
346
- if (!node.content) {
347
- throw createError(translate("A Question icon must have content"), filename, id)
348
- }
349
- }
350
- }
351
-
352
- return firstNodeId
341
+ var firstNodeId = undefined;
342
+ var minBranchId = 10000;
343
+ for (var id in nodes) {
344
+ var node = nodes[id];
345
+ if (node.type === "branch") {
346
+ if (node.branchId < minBranchId) {
347
+ firstNodeId = id;
348
+ minBranchId = node.branchId;
349
+ }
350
+ branches.push(node);
351
+ } else if (node.type === "select") {
352
+ if (!node.content) {
353
+ throw createError(
354
+ translate("A Select icon must have content"),
355
+ filename,
356
+ id,
357
+ );
358
+ }
359
+ node.cases = [];
360
+ } else if (node.type === "loopbegin") {
361
+ if (!node.content) {
362
+ throw createError(
363
+ translate("A Loop begin icon must have content"),
364
+ filename,
365
+ id,
366
+ );
367
+ }
368
+ } else if (node.type === "question") {
369
+ if (!node.content) {
370
+ throw createError(
371
+ translate("A Question icon must have content"),
372
+ filename,
373
+ id,
374
+ );
375
+ }
376
+ }
377
+ }
378
+
379
+ return firstNodeId;
353
380
  }
354
381
 
355
382
  function rewireSelectsMarkLoops(nodes, filename) {
356
- for (var id of Object.keys(nodes)) {
357
- var node = nodes[id]
358
- if (!node) { continue }
359
- if (node.type === "select") {
360
- rewireSelect(nodes, node, filename)
361
- } else if (node.type === "loopbegin") {
362
- markLoopBody(nodes, node, filename)
363
- }
383
+ for (var id of Object.keys(nodes)) {
384
+ var node = nodes[id];
385
+ if (!node) {
386
+ continue;
387
+ }
388
+ if (node.type === "select") {
389
+ rewireSelect(nodes, node, filename);
390
+ } else if (node.type === "loopbegin") {
391
+ markLoopBody(nodes, node, filename);
364
392
  }
393
+ }
365
394
  }
366
395
 
367
396
  function rewireSelect(nodes, selectNode, filename) {
368
- var caseNodeId = selectNode.one
369
- while (caseNodeId) {
370
- var caseNode = nodes[caseNodeId]
371
- caseNodeId = caseNode.two
372
- if (caseNode.content) {
373
- caseNode.type = "question"
374
- caseNode.flag1 = 1
375
- caseNode.content = {operator: "equal", left:selectNode.content, right:caseNode.content}
376
- if (!caseNode.two) {
377
- var errorId = caseNode.id + "-unexpected"
378
- var errorAction = insertIcon(nodes, "error", errorId, selectNode.content)
379
- errorAction.message = "Unexpected case value"
380
-
381
- caseNode.two = errorId
382
- errorAction.prev.push(caseNode.id)
383
- errorAction.one = caseNode.one
384
-
385
- var next = nodes[caseNode.one]
386
- next.prev.push(errorId)
387
- }
388
- } else {
389
- if (caseNode.two) {
390
- throw createError(translate("Only the rightmost Case icon can be empty"), filename, caseNode.id)
391
- }
392
- removeNodeOne(nodes, caseNode.id)
393
- }
394
- }
395
- removeNodeOne(nodes, selectNode.id)
397
+ var caseNodeId = selectNode.one;
398
+ while (caseNodeId) {
399
+ var caseNode = nodes[caseNodeId];
400
+ caseNodeId = caseNode.two;
401
+ if (caseNode.content) {
402
+ caseNode.type = "question";
403
+ caseNode.flag1 = 1;
404
+ caseNode.content = {
405
+ operator: "equal",
406
+ left: selectNode.content,
407
+ right: caseNode.content,
408
+ };
409
+ if (!caseNode.two) {
410
+ var errorId = caseNode.id + "-unexpected";
411
+ var errorAction = insertIcon(
412
+ nodes,
413
+ "error",
414
+ errorId,
415
+ selectNode.content,
416
+ );
417
+ errorAction.message = translate("Unexpected case value");
418
+
419
+ caseNode.two = errorId;
420
+ errorAction.prev.push(caseNode.id);
421
+ errorAction.one = caseNode.one;
422
+
423
+ var next = nodes[caseNode.one];
424
+ next.prev.push(errorId);
425
+ }
426
+ } else {
427
+ if (caseNode.two) {
428
+ throw createError(
429
+ translate("Only the rightmost Case icon can be empty"),
430
+ filename,
431
+ caseNode.id,
432
+ );
433
+ }
434
+ removeNodeOne(nodes, caseNode.id);
435
+ }
436
+ }
437
+ removeNodeOne(nodes, selectNode.id);
396
438
  }
397
439
 
398
440
  function insertIcon(nodes, type, id, content) {
399
- var node = {
400
- type: type,
401
- id: id,
402
- content: content,
403
- prev: []
404
- }
405
- nodes[id] = node
406
- return node
441
+ var node = {
442
+ type: type,
443
+ id: id,
444
+ content: content,
445
+ prev: [],
446
+ };
447
+ nodes[id] = node;
448
+ return node;
407
449
  }
408
450
 
409
451
  function removeNodeOne(nodes, nodeId) {
410
- var node = nodes[nodeId]
411
- redirectPrev(nodes, node, node.one)
412
- redirectNext(nodes, node, node.one)
413
- delete nodes[nodeId]
452
+ var node = nodes[nodeId];
453
+ redirectPrev(nodes, node, node.one);
454
+ redirectNext(nodes, node, node.one);
455
+ delete nodes[nodeId];
414
456
  }
415
457
 
416
458
  function removeFromNext(node, next) {
417
- next.prev = next.prev.filter(prevId => prevId !== node.id)
459
+ next.prev = next.prev.filter((prevId) => prevId !== node.id);
418
460
  }
419
461
 
420
462
  function redirectPrev(nodes, node, newTarget) {
421
- for (var prevId of node.prev) {
422
- var prev = nodes[prevId]
423
- if (prev.one === node.id) {
424
- prev.one = newTarget
425
- }
426
- if (prev.two === node.id) {
427
- prev.two = newTarget
428
- }
463
+ for (var prevId of node.prev) {
464
+ var prev = nodes[prevId];
465
+ if (prev.one === node.id) {
466
+ prev.one = newTarget;
429
467
  }
468
+ if (prev.two === node.id) {
469
+ prev.two = newTarget;
470
+ }
471
+ }
430
472
  }
431
473
 
432
474
  function redirectNext(nodes, node, newTarget) {
433
- var target = nodes[newTarget]
434
- removeFromNext(node, target)
435
- for (var prevId of node.prev) {
436
- target.prev.push(prevId)
437
- }
475
+ var target = nodes[newTarget];
476
+ removeFromNext(node, target);
477
+ for (var prevId of node.prev) {
478
+ target.prev.push(prevId);
479
+ }
438
480
  }
439
481
 
440
482
  function rewireShortcircuit(nodes) {
441
- while (findShortcusts(nodes)) {
442
-
443
- }
483
+ while (findShortcusts(nodes)) {}
444
484
  }
445
485
 
446
486
  function findShortcusts(nodes) {
447
- for (var id in nodes) {
448
- var node = nodes[id]
449
- if (node.type === "question") {
450
- var andOperand = findAndOperand(nodes, node)
451
- if (andOperand) {
452
- writeAndShortcut(nodes, node, andOperand)
453
- return true
454
- }
455
- var orOperand = findOrOperand(nodes, node)
456
- if (orOperand) {
457
- writeOrShortcut(nodes, node, orOperand)
458
- return true
459
- }
460
- }
461
- }
462
- return false
487
+ for (var id in nodes) {
488
+ var node = nodes[id];
489
+ if (node.type === "question") {
490
+ var andOperand = findAndOperand(nodes, node);
491
+ if (andOperand) {
492
+ writeAndShortcut(nodes, node, andOperand);
493
+ return true;
494
+ }
495
+ var orOperand = findOrOperand(nodes, node);
496
+ if (orOperand) {
497
+ writeOrShortcut(nodes, node, orOperand);
498
+ return true;
499
+ }
500
+ }
501
+ }
502
+ return false;
463
503
  }
464
504
 
465
505
  function findAndOperand(nodes, node) {
466
- var below = nodes[node.one]
467
- if (below.type === "question") {
468
- if (below.prev.length === 1 && below.two === node.two) {
469
- return below
470
- }
506
+ var below = nodes[node.one];
507
+ if (below.type === "question") {
508
+ if (below.prev.length === 1 && below.two === node.two) {
509
+ return below;
471
510
  }
472
- return undefined
511
+ }
512
+ return undefined;
473
513
  }
474
514
 
475
515
  function findOrOperand(nodes, node) {
476
- var right = nodes[node.two]
477
- if (right.type === "question") {
478
- if (right.prev.length === 1 && right.one === node.one) {
479
- return right
480
- }
516
+ var right = nodes[node.two];
517
+ if (right.type === "question") {
518
+ if (right.prev.length === 1 && right.one === node.one) {
519
+ return right;
481
520
  }
482
- return undefined
521
+ }
522
+ return undefined;
483
523
  }
484
524
 
485
525
  function writeAndShortcut(nodes, node, andOperand) {
486
- var right = nodes[node.two]
487
- var down = nodes[andOperand.one]
488
- removeFromNext(andOperand, right)
489
- removeFromNext(andOperand, down)
490
- node.content = {
491
- operator: "and",
492
- left: normalizeContent(node),
493
- right: normalizeContent(andOperand)
494
- }
495
- node.one = down.id
496
- node.flag1 = 1
497
- down.prev.push(node.id)
498
- delete nodes[andOperand.id]
526
+ var right = nodes[node.two];
527
+ var down = nodes[andOperand.one];
528
+ removeFromNext(andOperand, right);
529
+ removeFromNext(andOperand, down);
530
+ node.content = {
531
+ operator: "and",
532
+ left: normalizeContent(node),
533
+ right: normalizeContent(andOperand),
534
+ };
535
+ node.one = down.id;
536
+ node.flag1 = 1;
537
+ normalizeAnd(node);
538
+ down.prev.push(node.id);
539
+ delete nodes[andOperand.id];
499
540
  }
500
541
 
501
542
  function writeOrShortcut(nodes, node, orOperand) {
502
- var right = nodes[orOperand.two]
503
- var down = nodes[orOperand.one]
504
- removeFromNext(orOperand, right)
505
- removeFromNext(orOperand, down)
506
- node.content = {
507
- operator: "or",
508
- left: normalizeContent(node),
509
- right: normalizeContent(orOperand)
510
- }
511
- node.two = right.id
512
- node.flag1 = 1
513
- right.prev.push(node.id)
514
- delete nodes[orOperand.id]
543
+ var right = nodes[orOperand.two];
544
+ var down = nodes[orOperand.one];
545
+ removeFromNext(orOperand, right);
546
+ removeFromNext(orOperand, down);
547
+ node.content = {
548
+ operator: "or",
549
+ left: normalizeContent(node),
550
+ right: normalizeContent(orOperand),
551
+ };
552
+ node.two = right.id;
553
+ node.flag1 = 1;
554
+ normalizeOr(node);
555
+ right.prev.push(node.id);
556
+ delete nodes[orOperand.id];
515
557
  }
516
558
 
517
- function normalizeContent(question) {
518
- if (question.flag1 === 1) {
519
- return question.content
520
- }
559
+ function normalizeAnd(node) {
560
+ var op = node.content;
561
+ var left = op.left;
562
+ var right = op.right;
563
+ if (left.operator === "not" && right.operator === "not") {
564
+ node.content = {
565
+ operator: "or",
566
+ left: left.operand,
567
+ right: right.operand,
568
+ };
569
+ node.flag1 = 0;
570
+ }
571
+ }
521
572
 
522
- return {
523
- operator: "not",
524
- operand: question.content
525
- }
573
+ function normalizeOr(node) {
574
+ var op = node.content;
575
+ var left = op.left;
576
+ var right = op.right;
577
+ if (left.operator === "not" && right.operator === "not") {
578
+ node.content = {
579
+ operator: "and",
580
+ left: left.operand,
581
+ right: right.operand,
582
+ };
583
+ node.flag1 = 0;
584
+ }
526
585
  }
527
586
 
587
+ function normalizeContent(question) {
588
+ if (question.flag1 === 1) {
589
+ return question.content;
590
+ }
591
+
592
+ return {
593
+ operator: "not",
594
+ operand: question.content,
595
+ };
596
+ }
528
597
 
529
598
  function traverse(nodes, nodeId, visited, action) {
530
- if (!nodeId) {
531
- return
532
- }
533
-
534
- if (nodeId in visited) {
535
- return
536
- }
537
- visited[nodeId] = true
538
- var node = nodes[nodeId]
539
- action(nodes, node)
540
- traverse(nodes, node.one, visited, action)
541
- traverse(nodes, node.two, visited, action)
599
+ if (!nodeId) {
600
+ return;
601
+ }
602
+
603
+ if (nodeId in visited) {
604
+ return;
605
+ }
606
+ visited[nodeId] = true;
607
+ var node = nodes[nodeId];
608
+ action(nodes, node);
609
+ traverse(nodes, node.one, visited, action);
610
+ traverse(nodes, node.two, visited, action);
542
611
  }
543
612
 
544
613
  function connectBack(nodes, node) {
545
- if (node.one) {
546
- var one = nodes[node.one]
547
- one.prev.push(node.id)
548
- }
549
- if (node.two) {
550
- var two = nodes[node.two]
551
- two.prev.push(node.id)
552
- }
614
+ if (node.one) {
615
+ var one = nodes[node.one];
616
+ one.prev.push(node.id);
617
+ }
618
+ if (node.two) {
619
+ var two = nodes[node.two];
620
+ two.prev.push(node.id);
621
+ }
553
622
  }
554
623
 
555
624
  function markLoopBody(nodes, start, filename) {
556
- var nextNodeId = start.one
557
- while (nextNodeId) {
558
- var current = nodes[nextNodeId]
559
- nextNodeId = current.one
560
- current.parentLoopId = start.id
561
- if (current.type === "loopbegin") {
562
- nextNodeId = markLoopBody(nodes, current, filename)
563
- } else if (current.type === "loopend") {
564
- start.end = current.id
565
- start.next = current.one
566
- current.start = start.id
567
- return nextNodeId
568
- }
569
- }
570
- throw createError(translate("Loop end expected here"), filename, start.one)
625
+ var nextNodeId = start.one;
626
+ while (nextNodeId) {
627
+ var current = nodes[nextNodeId];
628
+ nextNodeId = current.one;
629
+ current.parentLoopId = start.id;
630
+ if (current.type === "loopbegin") {
631
+ nextNodeId = markLoopBody(nodes, current, filename);
632
+ } else if (current.type === "loopend") {
633
+ start.end = current.id;
634
+ start.next = current.one;
635
+ current.start = start.id;
636
+ return nextNodeId;
637
+ }
638
+ }
639
+ throw createError(translate("Loop end expected here"), filename, start.one);
571
640
  }
572
641
 
573
642
  module.exports = { drakonToStruct, drakonToGraph };
643
+
574
644
  },{"./structFlow":6,"./tools":8}],4:[function(require,module,exports){
575
645
  const { drakonToPseudocode, mindToTree } = require('./drakonToPromptStruct');
576
646
  const { htmlToString } = require("./browserTools")
@@ -1284,6 +1354,7 @@ var translationsRu = {
1284
1354
  "A Loop begin icon must have content": "Икона начала цикла ДЛЯ должна содержать данные",
1285
1355
  "A Question icon must have content": "Икона Вопрос должна содержать данные",
1286
1356
  "A Select icon must have content": "Икона Выбор должна содержать данные",
1357
+ "Unexpected case value": "Неожиданное значение иконы Вариант",
1287
1358
  "Loop end expected here": "Здесь ожидается конец цикла",
1288
1359
  "An exit from the loop must lead to the point right after the loop end": "Выход из цикла должен вести в точку сразу за его концом",
1289
1360
  "A silhouette branch is not referenced": "Нет ссылок на ветку силуэта",
@@ -1314,6 +1385,7 @@ var translationsEn = {
1314
1385
  'A Loop begin icon must have content': 'A Loop begin icon must have content',
1315
1386
  'A Question icon must have content': 'A Question icon must have content',
1316
1387
  'A Select icon must have content': 'A Select icon must have content',
1388
+ "Unexpected case value": "Unexpected case value",
1317
1389
  'Loop end expected here': 'Loop end expected here',
1318
1390
  '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',
1319
1391
  'A silhouette branch is not referenced': 'A silhouette branch is not referenced',
@@ -1344,6 +1416,7 @@ var translationsNo = {
1344
1416
  'A Loop begin icon must have content': 'Et Loop-startikon må ha innhold',
1345
1417
  'A Question icon must have content': 'Et Spørsmål-ikon må ha innhold',
1346
1418
  'A Select icon must have content': 'Et Velg-ikon må ha innhold',
1419
+ "Unexpected case value": "Uventet tilfelle verdi",
1347
1420
  'Loop end expected here': 'Slutt på løkke forventet her',
1348
1421
  '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',
1349
1422
  'A silhouette branch is not referenced': 'En silhuettgren er ikke referert',
@@ -1403,6 +1476,7 @@ function optimizeTree(steps) {
1403
1476
 
1404
1477
  function optimizeLoop(step) {
1405
1478
  return {
1479
+ id: step.id,
1406
1480
  type: step.type,
1407
1481
  content: step.content,
1408
1482
  body: optimizeTree(step.body)