@teleporthq/teleport-plugin-next-workflows 0.45.14 → 0.45.15

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teleporthq/teleport-plugin-next-workflows",
3
- "version": "0.45.14",
3
+ "version": "0.45.15",
4
4
  "description": "A plugin for workflow code generation in Next.js projects.",
5
5
  "author": "teleportHQ",
6
6
  "license": "MIT",
@@ -69,5 +69,5 @@
69
69
  "@teleporthq/teleport-shared": "^0.45.0",
70
70
  "@teleporthq/teleport-types": "^0.45.0"
71
71
  },
72
- "gitHead": "c6b7eefde3d386aba19edc7ffa850879d7e1ce23"
72
+ "gitHead": "c93e2bd998c78f667928f7a87b6bb5175de8fea1"
73
73
  }
@@ -479,8 +479,8 @@ module.exports = async function handler(req, res) {
479
479
  continue;
480
480
  }
481
481
 
482
- // Loop nodes must be handled specially: iterate over the collection,
483
- // execute loop body nodes for each item, then continue after the loop.
482
+ // Loop nodes must be handled specially: run the loop body nodes once per
483
+ // pass of the loop type (see createLoopSteps), then continue after the loop.
484
484
  if (node.type === 'general-loop') {
485
485
  const loopEdges = SEGMENT_CONFIG.edges.filter(function(e) { return e.source === node.id; });
486
486
  const loopBodyEdge = loopEdges.find(function(e) { return e.sourceHandle === 'loop'; });
@@ -531,8 +531,9 @@ module.exports = async function handler(req, res) {
531
531
  if (!context.__loopNodeIds) context.__loopNodeIds = {};
532
532
  context.__loopNodeIds[node.id] = true;
533
533
 
534
- for (var li = 0; li < collection.length; li++) {
535
- context[node.id] = utils.loopIterationContext(collection, li);
534
+ var loopSteps = utils.createLoopSteps(node, resolved, context, collection);
535
+ for (var loopPass = loopSteps.next(context); loopPass; loopPass = loopSteps.next(context)) {
536
+ context[loopPass.key] = loopPass.value;
536
537
  for (var bi = 0; bi < bodyNodes.length; bi++) {
537
538
  var bNode = bodyNodes[bi];
538
539
  var bResolved = resolveNodeConfig(bNode, context);
@@ -561,7 +562,7 @@ module.exports = async function handler(req, res) {
561
562
 
562
563
  context.__loopScopeStack.pop();
563
564
 
564
- context[node.id] = { completed: true, iterations: collection.length, results: loopResults };
565
+ context[node.id] = { completed: true, iterations: loopSteps.iterations(), results: loopResults };
565
566
  // Store body node IDs so the outer loop can skip them
566
567
  if (!context.__loopBodyNodeIds) context.__loopBodyNodeIds = {};
567
568
  Object.assign(context.__loopBodyNodeIds, bodyNodeIds);
@@ -916,8 +917,9 @@ module.exports = async function handler(req, res) {
916
917
  context.__loopScopeStack.push({ loopNodeId: node.id, bodyNodeIds: ssBodyNodeIds });
917
918
  if (!context.__loopNodeIds) context.__loopNodeIds = {};
918
919
  context.__loopNodeIds[node.id] = true;
919
- for (var ssli = 0; ssli < ssLoopCollection.length; ssli++) {
920
- context[node.id] = utils.loopIterationContext(ssLoopCollection, ssli);
920
+ var ssLoopSteps = utils.createLoopSteps(node, resolved, context, ssLoopCollection);
921
+ for (var ssLoopPass = ssLoopSteps.next(context); ssLoopPass; ssLoopPass = ssLoopSteps.next(context)) {
922
+ context[ssLoopPass.key] = ssLoopPass.value;
921
923
  for (var ssbi = 0; ssbi < ssBodyNodes.length; ssbi++) {
922
924
  var ssbNode = ssBodyNodes[ssbi];
923
925
  var ssbRes = resolveNodeConfig(ssbNode, context);
@@ -941,7 +943,7 @@ module.exports = async function handler(req, res) {
941
943
  }
942
944
  }
943
945
  context.__loopScopeStack.pop();
944
- context[node.id] = { completed: true, iterations: ssLoopCollection.length, results: ssLoopResults };
946
+ context[node.id] = { completed: true, iterations: ssLoopSteps.iterations(), results: ssLoopResults };
945
947
  Object.keys(ssBodyNodeIds).forEach(function(k) { executed[k] = true; });
946
948
  executed[node.id] = true;
947
949
  if (streamStarted) {
@@ -1750,8 +1752,9 @@ ${resumeBlock}
1750
1752
  if (!context.__loopNodeIds) context.__loopNodeIds = {};
1751
1753
  context.__loopNodeIds[node.id] = true;
1752
1754
 
1753
- for (var li = 0; li < collection.length; li++) {
1754
- context[node.id] = utils.loopIterationContext(collection, li);
1755
+ var loopSteps = utils.createLoopSteps(node, resolved, context, collection);
1756
+ for (var loopPass = loopSteps.next(context); loopPass; loopPass = loopSteps.next(context)) {
1757
+ context[loopPass.key] = loopPass.value;
1755
1758
  for (var bi = 0; bi < bodyNodes.length; bi++) {
1756
1759
  var bNode = bodyNodes[bi];
1757
1760
  var bResolved = resolveNodeConfig(bNode, context);
@@ -1780,7 +1783,7 @@ ${resumeBlock}
1780
1783
 
1781
1784
  context.__loopScopeStack.pop();
1782
1785
 
1783
- context[node.id] = { completed: true, iterations: collection.length, results: loopResults };
1786
+ context[node.id] = { completed: true, iterations: loopSteps.iterations(), results: loopResults };
1784
1787
  if (!context.__loopBodyNodeIds) context.__loopBodyNodeIds = {};
1785
1788
  Object.assign(context.__loopBodyNodeIds, bodyNodeIds);
1786
1789
  continue;
@@ -161,6 +161,60 @@ function loopIterationContext(collection, index) {
161
161
  };
162
162
  }
163
163
 
164
+ // How every loop type steps, for the client executor and for each server
165
+ // route alike. next(context) hands back what one pass publishes before its
166
+ // body runs ({ key, value }, stored as context[key]), or null once the loop is
167
+ // over. A collection is walked under the loop's own id; a counted or a
168
+ // conditional loop publishes its counter under "<loopId>_iter". A while / until
169
+ // condition is tested before every pass, against the context of that pass.
170
+ var DEFAULT_LOOP_MAX_ITERATIONS = 1000;
171
+
172
+ function createLoopSteps(loopNode, config, context, collection) {
173
+ var loopType = config.loopType || 'forEach';
174
+ var iterKey = loopNode.id + '_iter';
175
+ var passes = 0;
176
+ var next;
177
+ if (loopType === 'forEach' || loopType === 'map') {
178
+ next = function() {
179
+ return passes < collection.length
180
+ ? { key: loopNode.id, value: loopIterationContext(collection, passes) }
181
+ : null;
182
+ };
183
+ } else if (loopType === 'for') {
184
+ var cursor = Number(resolveValue(config.startIndex, context)) || 0;
185
+ var end = Number(resolveValue(config.endIndex, context)) || 0;
186
+ var step = Number(resolveValue(config.step, context)) || 1;
187
+ next = function() {
188
+ if (!(step > 0 ? cursor < end : cursor > end)) return null;
189
+ var index = cursor;
190
+ cursor += step;
191
+ return { key: iterKey, value: { index: index } };
192
+ };
193
+ } else {
194
+ var maxIterations = Number(resolveValue(config.maxIterations, context)) || DEFAULT_LOOP_MAX_ITERATIONS;
195
+ var authoredCondition = loopNode.config && loopNode.config.condition;
196
+ next = function(passContext) {
197
+ if (passes >= maxIterations) return null;
198
+ var scaffold = { iteration: passes };
199
+ var testContext = Object.assign({}, passContext);
200
+ testContext[iterKey] = scaffold;
201
+ var condition = resolveValue(config.condition, testContext);
202
+ // Only the authored condition is compiled (see runExpression).
203
+ var holds = runExpression(authoredCondition, condition, ['context'], [testContext], testContext);
204
+ if (loopType === 'until' ? holds : !holds) return null;
205
+ return { key: iterKey, value: scaffold };
206
+ };
207
+ }
208
+ return {
209
+ next: function(passContext) {
210
+ var pass = next(passContext || context);
211
+ if (pass) passes++;
212
+ return pass;
213
+ },
214
+ iterations: function() { return passes; }
215
+ };
216
+ }
217
+
164
218
  function resolveCtxRef(ref, context) {
165
219
  var elem = context.triggerElement;
166
220
  if (!elem || typeof elem.getAttribute !== 'function') return undefined;
@@ -1496,35 +1550,15 @@ async function executeLoop(loopNode, config, allNodes, edges, context, nodeHandl
1496
1550
  context[loopNode.id] = loopType === 'map'
1497
1551
  ? { results: results, iterations: collection.length }
1498
1552
  : { completed: true, iterations: collection.length };
1499
- } else if (loopType === 'for') {
1500
- const start = resolveValue(config.startIndex, context) || 0;
1501
- const end = resolveValue(config.endIndex, context) || 0;
1502
- const step = resolveValue(config.step, context) || 1;
1503
- let count = 0;
1504
- for (let fi = start; step > 0 ? fi < end : fi > end; fi += step) {
1505
- const forCtx = Object.assign({}, context);
1506
- forCtx[loopNode.id + '_iter'] = { index: fi };
1507
- await executeNodes(bodyNodes, edges, forCtx, nodeHandlers, workflowConfig, callServerSegment, executionId);
1508
- Object.assign(context, forCtx);
1509
- count++;
1510
- }
1511
- context[loopNode.id] = { completed: true, iterations: count };
1512
1553
  } else {
1513
- const maxIter = resolveValue(config.maxIterations, context) || 1000;
1514
- let iter = 0;
1515
- while (iter < maxIter) {
1516
- const whileCtx = Object.assign({}, context);
1517
- whileCtx[loopNode.id + '_iter'] = { iteration: iter };
1518
- const condStr = resolveValue(config.condition, whileCtx);
1519
- // Only the authored condition is compiled (see runExpression).
1520
- const condResult = runExpression(loopNode.config && loopNode.config.condition, condStr, ['context'], [whileCtx], whileCtx);
1521
- if (loopType === 'while' && !condResult) break;
1522
- if (loopType === 'until' && condResult) break;
1523
- await executeNodes(bodyNodes, edges, whileCtx, nodeHandlers, workflowConfig, callServerSegment, executionId);
1524
- Object.assign(context, whileCtx);
1525
- iter++;
1554
+ const steps = createLoopSteps(loopNode, config, context);
1555
+ for (let pass = steps.next(context); pass; pass = steps.next(context)) {
1556
+ const passCtx = Object.assign({}, context);
1557
+ passCtx[pass.key] = pass.value;
1558
+ await executeNodes(bodyNodes, edges, passCtx, nodeHandlers, workflowConfig, callServerSegment, executionId);
1559
+ Object.assign(context, passCtx);
1526
1560
  }
1527
- context[loopNode.id] = { completed: true, iterations: iter };
1561
+ context[loopNode.id] = { completed: true, iterations: steps.iterations() };
1528
1562
  }
1529
1563
  } finally {
1530
1564
  context.__loopScopeStack.pop();
@@ -1820,6 +1854,7 @@ module.exports = {
1820
1854
  resolveRichTextContext,
1821
1855
  unwrapWorkflowCollection,
1822
1856
  loopIterationContext,
1857
+ createLoopSteps,
1823
1858
  snapshotIncomingContext,
1824
1859
  segmentReply,
1825
1860
  withoutCredentialColumns,