ts2workflows 0.7.0 → 0.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.
@@ -1,19 +1,18 @@
1
+ import * as R from 'ramda';
1
2
  import { AST_NODE_TYPES } from '@typescript-eslint/typescript-estree';
2
- import { AssignStepAST, CallStepAST, ForStepAST, JumpTargetAST, NextStepAST, ParallelStepAST, RaiseStepAST, ReturnStepAST, StepsStepAST, SwitchStepAST, TryStepAST, } from '../ast/steps.js';
3
- import { BinaryExpression, FunctionInvocationExpression, PrimitiveExpression, VariableReferenceExpression, isExpression, isFullyQualifiedName, isLiteral, } from '../ast/expressions.js';
3
+ import { AssignStepAST, CallStepAST, ForRangeStepAST, ForStepAST, JumpTargetAST, NextStepAST, ParallelStepAST, RaiseStepAST, ReturnStepAST, StepsStepAST, SwitchStepAST, TryStepAST, } from '../ast/steps.js';
4
+ import { BinaryExpression, FunctionInvocationExpression, MemberExpression, PrimitiveExpression, VariableReferenceExpression, asExpression, isExpression, isFullyQualifiedName, isLiteral, isPure, nullEx, safeAsExpression, trueEx, } from '../ast/expressions.js';
4
5
  import { InternalTranspilingError, WorkflowSyntaxError } from '../errors.js';
5
- import { flatMapPair, isRecord, mapRecordValues } from '../utils.js';
6
- import { transformAST } from './transformations.js';
7
- import { convertExpression, convertMemberExpression, convertObjectExpression, convertObjectAsExpressionValues, isMagicFunction, throwIfSpread, isMagicFunctionStatmentOnly, asExpression, } from './expressions.js';
6
+ import { chainPairs, isRecord } from '../utils.js';
7
+ import { convertExpression, convertMemberExpression, convertObjectExpression, convertObjectAsExpressionValues, isMagicFunction, throwIfSpread, isMagicFunctionStatmentOnly, } from './expressions.js';
8
8
  import { blockingFunctions } from './generated/functionMetadata.js';
9
- export function parseStatement(node, ctx, postSteps) {
10
- const steps = parseStatementRecursively(node, undefined, ctx);
11
- return transformAST(steps.concat(postSteps ?? []));
9
+ export function parseStatement(node, ctx) {
10
+ return parseStatementRecursively(node, undefined, ctx);
12
11
  }
13
12
  function parseStatementRecursively(node, nextNode, ctx) {
14
13
  switch (node.type) {
15
14
  case AST_NODE_TYPES.BlockStatement:
16
- return flatMapPair(node.body, (statement, nextStatement) => parseStatementRecursively(statement, nextStatement, ctx));
15
+ return chainPairs(R.partialRight(parseStatementRecursively, [ctx]), node.body);
17
16
  case AST_NODE_TYPES.VariableDeclaration:
18
17
  return convertVariableDeclarations(node.declarations, ctx);
19
18
  case AST_NODE_TYPES.ExpressionStatement:
@@ -24,7 +23,7 @@ function parseStatementRecursively(node, nextNode, ctx) {
24
23
  return callExpressionToStep(node.expression, undefined, ctx);
25
24
  }
26
25
  else {
27
- return [generalExpressionToAssignStep(node.expression)];
26
+ return [generalExpressionToAssignStep(node.expression, ctx)];
28
27
  }
29
28
  case AST_NODE_TYPES.ReturnStatement:
30
29
  return [returnStatementToReturnStep(node, ctx)];
@@ -71,27 +70,279 @@ function parseStatementRecursively(node, nextNode, ctx) {
71
70
  }
72
71
  function convertVariableDeclarations(declarations, ctx) {
73
72
  return declarations.flatMap((decl) => {
74
- if (decl.id.type !== AST_NODE_TYPES.Identifier) {
75
- throw new WorkflowSyntaxError('Expected Identifier', decl.loc);
76
- }
77
- const targetName = decl.id.name;
78
- if (decl.init?.type === AST_NODE_TYPES.CallExpression) {
79
- const calleeName = decl.init.callee.type === AST_NODE_TYPES.Identifier
80
- ? decl.init.callee.name
81
- : undefined;
82
- if (calleeName && isMagicFunctionStatmentOnly(calleeName)) {
83
- throw new WorkflowSyntaxError(`"${calleeName}" can't be called as part of an expression`, decl.init.callee.loc);
73
+ if (decl.id.type === AST_NODE_TYPES.Identifier) {
74
+ return convertInitializer(decl.id.name, decl.init, ctx);
75
+ }
76
+ else if (decl.id.type === AST_NODE_TYPES.ArrayPattern) {
77
+ return convertArrayDestructuring(decl.id, decl.init, ctx);
78
+ }
79
+ else if (decl.id.type === AST_NODE_TYPES.ObjectPattern) {
80
+ return convertObjectDestructuring(decl.id, decl.init, ctx);
81
+ }
82
+ else {
83
+ throw new WorkflowSyntaxError('Unsupported pattern', decl.loc);
84
+ }
85
+ });
86
+ }
87
+ function convertInitializer(targetVariableName, initializer, ctx) {
88
+ if (initializer?.type === AST_NODE_TYPES.CallExpression) {
89
+ const calleeName = initializer.callee.type === AST_NODE_TYPES.Identifier
90
+ ? initializer.callee.name
91
+ : undefined;
92
+ if (calleeName && isMagicFunctionStatmentOnly(calleeName)) {
93
+ throw new WorkflowSyntaxError(`"${calleeName}" can't be called as part of an expression`, initializer.callee.loc);
94
+ }
95
+ return callExpressionToStep(initializer, targetVariableName, ctx);
96
+ }
97
+ else {
98
+ const value = initializer === null ? nullEx : convertExpression(initializer);
99
+ return [new AssignStepAST([[targetVariableName, value]])];
100
+ }
101
+ }
102
+ function convertArrayDestructuring(arrayPattern, initializer, ctx) {
103
+ let initExpression;
104
+ const steps = [];
105
+ if (initializer?.type === AST_NODE_TYPES.Identifier ||
106
+ initializer?.type === AST_NODE_TYPES.MemberExpression) {
107
+ // If the initializer is an Identifier or MemberExpression (array variable?),
108
+ // use it directly. This ensures that the recursive variables gets initialized
109
+ // in the correct order. For example:
110
+ // const arr = [1, 2]
111
+ // [arr[1], arr[0]] = arr
112
+ initExpression = convertExpression(initializer);
113
+ }
114
+ else {
115
+ // Otherwise, assign the expression to a temporary variable first.
116
+ const initName = tempName(ctx);
117
+ steps.push(...convertInitializer(initName, initializer, ctx));
118
+ initExpression = new VariableReferenceExpression(initName);
119
+ }
120
+ steps.push(...arrayDestructuringSteps(arrayPattern.elements, initExpression, ctx));
121
+ return steps;
122
+ }
123
+ function arrayDestructuringSteps(patterns, initializerExpression, ctx) {
124
+ if (patterns.filter((p) => p !== null).length === 0) {
125
+ return [];
126
+ }
127
+ const __temp_len = `${tempName(ctx)}_len`;
128
+ const initializeVariables = [
129
+ [
130
+ __temp_len,
131
+ new FunctionInvocationExpression('len', [initializerExpression]),
132
+ ],
133
+ ];
134
+ const branches = R.reverse(patterns).flatMap((pat, i) => {
135
+ if (pat === null) {
136
+ return [];
137
+ }
138
+ else {
139
+ return [
140
+ {
141
+ condition: new BinaryExpression(new VariableReferenceExpression(__temp_len), '>=', new PrimitiveExpression(patterns.length - i)),
142
+ steps: arrayElementsDestructuringSteps(patterns, initializerExpression, patterns.length - i, ctx),
143
+ },
144
+ ];
145
+ }
146
+ });
147
+ branches.push({
148
+ condition: trueEx,
149
+ steps: arrayElementsDestructuringSteps(patterns, initializerExpression, 0, ctx),
150
+ });
151
+ return [new AssignStepAST(initializeVariables), new SwitchStepAST(branches)];
152
+ }
153
+ function arrayElementsDestructuringSteps(patterns, initializerExpression, take, ctx) {
154
+ return patterns.flatMap((pat, i) => {
155
+ if (i >= take) {
156
+ return [
157
+ new AssignStepAST(extractDefaultAssignmentsFromDestructuringPattern(pat)),
158
+ ];
159
+ }
160
+ const iElement = new MemberExpression(initializerExpression, new PrimitiveExpression(i), true);
161
+ switch (pat?.type) {
162
+ case AST_NODE_TYPES.MemberExpression:
163
+ case AST_NODE_TYPES.Identifier: {
164
+ const name = convertExpression(pat).toString();
165
+ return [new AssignStepAST([[name, iElement]])];
166
+ }
167
+ case AST_NODE_TYPES.AssignmentPattern: {
168
+ if (pat.left.type !== AST_NODE_TYPES.Identifier) {
169
+ throw new WorkflowSyntaxError('Default value can be used only with an identifier', pat.left.loc);
170
+ }
171
+ return [new AssignStepAST([[pat.left.name, iElement]])];
84
172
  }
85
- return callExpressionToStep(decl.init, targetName, ctx);
173
+ case AST_NODE_TYPES.ObjectPattern:
174
+ return objectDestructuringSteps(pat.properties, iElement, ctx);
175
+ case AST_NODE_TYPES.ArrayPattern:
176
+ return arrayDestructuringSteps(pat.elements, iElement, ctx);
177
+ case AST_NODE_TYPES.RestElement:
178
+ return arrayRestDestructuringSteps(patterns, pat, initializerExpression, patterns.length - 1, ctx);
179
+ default: // pat === null
180
+ return [];
181
+ }
182
+ });
183
+ }
184
+ function extractDefaultAssignmentsFromDestructuringPattern(pat) {
185
+ if (pat === null) {
186
+ return [];
187
+ }
188
+ switch (pat.type) {
189
+ case AST_NODE_TYPES.ArrayPattern:
190
+ return pat.elements.flatMap(extractDefaultAssignmentsFromDestructuringPattern);
191
+ case AST_NODE_TYPES.AssignmentPattern:
192
+ if (pat.left.type !== AST_NODE_TYPES.Identifier) {
193
+ throw new WorkflowSyntaxError('Default value can be used only with an identifier', pat.left.loc);
194
+ }
195
+ return [[pat.left.name, convertExpression(pat.right)]];
196
+ case AST_NODE_TYPES.Identifier:
197
+ return [[pat.name, nullEx]];
198
+ case AST_NODE_TYPES.MemberExpression:
199
+ return [[convertExpression(pat).toString(), nullEx]];
200
+ case AST_NODE_TYPES.ObjectPattern:
201
+ return pat.properties.flatMap((p) => {
202
+ if (p.type === AST_NODE_TYPES.RestElement) {
203
+ return extractDefaultAssignmentsFromDestructuringPattern(p);
204
+ }
205
+ else if (p.value.type === AST_NODE_TYPES.ArrayPattern ||
206
+ p.value.type === AST_NODE_TYPES.AssignmentPattern ||
207
+ p.value.type === AST_NODE_TYPES.Identifier ||
208
+ p.value.type === AST_NODE_TYPES.MemberExpression ||
209
+ p.value.type === AST_NODE_TYPES.ObjectPattern) {
210
+ return extractDefaultAssignmentsFromDestructuringPattern(p.value);
211
+ }
212
+ else {
213
+ throw new WorkflowSyntaxError('Destructuring pattern expected', p.value.loc);
214
+ }
215
+ });
216
+ case AST_NODE_TYPES.RestElement:
217
+ if (pat.argument.type !== AST_NODE_TYPES.Identifier) {
218
+ throw new WorkflowSyntaxError('Identifier expected', pat.argument.loc);
219
+ }
220
+ return [[pat.argument.name, new PrimitiveExpression([])]];
221
+ default:
222
+ return [];
223
+ }
224
+ }
225
+ function throwIfInvalidRestElement(patterns) {
226
+ const i = patterns.findIndex((p) => p?.type === AST_NODE_TYPES.RestElement);
227
+ if (i >= 0 && i !== patterns.length - 1) {
228
+ throw new WorkflowSyntaxError('A rest element must be last in a destructuring pattern', patterns[i].loc);
229
+ }
230
+ }
231
+ function arrayRestDestructuringSteps(patterns, rest, initializerExpression, startIndex, ctx) {
232
+ throwIfInvalidRestElement(patterns);
233
+ if (rest.argument.type !== AST_NODE_TYPES.Identifier) {
234
+ throw new WorkflowSyntaxError('Identifier expected', rest.argument.loc);
235
+ }
236
+ const restName = rest.argument.name;
237
+ const __temp_len = new VariableReferenceExpression(`${tempName(ctx)}_len`);
238
+ const __temp_index = `${tempName(ctx)}_index`;
239
+ const one = new PrimitiveExpression(1);
240
+ const emptyArray = new PrimitiveExpression([]);
241
+ const copyLoop = new ForRangeStepAST([
242
+ new AssignStepAST([
243
+ [
244
+ restName,
245
+ new FunctionInvocationExpression('list.concat', [
246
+ new VariableReferenceExpression(restName),
247
+ new MemberExpression(initializerExpression, new VariableReferenceExpression(__temp_index), true),
248
+ ]),
249
+ ],
250
+ ]),
251
+ ], __temp_index, startIndex, new BinaryExpression(__temp_len, '-', one));
252
+ return [new AssignStepAST([[restName, emptyArray]]), copyLoop];
253
+ }
254
+ function convertObjectDestructuring(objectPattern, initializer, ctx) {
255
+ let initExpression;
256
+ const steps = [];
257
+ if (initializer?.type === AST_NODE_TYPES.Identifier ||
258
+ (initializer?.type === AST_NODE_TYPES.MemberExpression &&
259
+ isPure(convertExpression(initializer)))) {
260
+ // If the initializer is an Identifier or MemberExpression (object variable?), use it directly.
261
+ initExpression = convertExpression(initializer);
262
+ }
263
+ else {
264
+ // Otherwise, assign the expression to a temporary variable first.
265
+ const initName = tempName(ctx);
266
+ steps.push(...convertInitializer(initName, initializer, ctx));
267
+ initExpression = new VariableReferenceExpression(initName);
268
+ }
269
+ steps.push(...objectDestructuringSteps(objectPattern.properties, initExpression, ctx));
270
+ return steps;
271
+ }
272
+ function objectDestructuringSteps(properties, initializerExpression, ctx) {
273
+ return properties.flatMap((prop) => {
274
+ if (prop.type === AST_NODE_TYPES.RestElement) {
275
+ return objectDestructuringRestSteps(properties, prop, initializerExpression);
276
+ }
277
+ if (prop.key.type !== AST_NODE_TYPES.Identifier) {
278
+ throw new WorkflowSyntaxError('Identifier expected', prop.key.loc);
279
+ }
280
+ const keyExpression = new MemberExpression(initializerExpression, new VariableReferenceExpression(prop.key.name), false);
281
+ if (prop.value.type === AST_NODE_TYPES.ObjectPattern) {
282
+ return objectDestructuringSteps(prop.value.properties, keyExpression, ctx);
283
+ }
284
+ else if (prop.value.type === AST_NODE_TYPES.ArrayPattern) {
285
+ return arrayDestructuringSteps(prop.value.elements, keyExpression, ctx);
286
+ }
287
+ else if (prop.value.type === AST_NODE_TYPES.Identifier) {
288
+ const safeKeyExpression = new FunctionInvocationExpression('map.get', [
289
+ initializerExpression,
290
+ new PrimitiveExpression(prop.key.name),
291
+ ]);
292
+ return [new AssignStepAST([[prop.value.name, safeKeyExpression]])];
293
+ }
294
+ else if (prop.value.type === AST_NODE_TYPES.AssignmentPattern) {
295
+ return objectAssignmentPatternSteps(prop.value, initializerExpression, keyExpression);
86
296
  }
87
297
  else {
88
- const value = decl.init == null
89
- ? new PrimitiveExpression(null)
90
- : convertExpression(decl.init);
91
- return [new AssignStepAST([[targetName, value]])];
298
+ throw new WorkflowSyntaxError(`${prop.value.type} is not allowed in object destructuring`, prop.value.loc);
92
299
  }
93
300
  });
94
301
  }
302
+ function objectAssignmentPatternSteps(pat, initializerExpression, keyExpression) {
303
+ if (pat.left.type !== AST_NODE_TYPES.Identifier) {
304
+ throw new WorkflowSyntaxError('Default value can be used only with an identifier', pat.left.loc);
305
+ }
306
+ // Using Switch step instead of default() because pat.right must be evaluated only
307
+ // in the default value branch (in case it has side effects)
308
+ return [
309
+ new SwitchStepAST([
310
+ {
311
+ condition: new BinaryExpression(new PrimitiveExpression(pat.left.name), 'in', initializerExpression),
312
+ steps: [new AssignStepAST([[pat.left.name, keyExpression]])],
313
+ },
314
+ {
315
+ condition: trueEx,
316
+ steps: [
317
+ new AssignStepAST([[pat.left.name, convertExpression(pat.right)]]),
318
+ ],
319
+ },
320
+ ]),
321
+ ];
322
+ }
323
+ function objectDestructuringRestSteps(properties, rest, initializerExpression) {
324
+ throwIfInvalidRestElement(properties);
325
+ if (rest.argument.type !== AST_NODE_TYPES.Identifier) {
326
+ throw new WorkflowSyntaxError('Identifier expected', rest.argument.loc);
327
+ }
328
+ const nonRestProperties = properties.filter((x) => x.type !== AST_NODE_TYPES.RestElement);
329
+ const nonRestKeys = nonRestProperties
330
+ .map((p) => p.key)
331
+ .map((p) => {
332
+ if (p.type !== AST_NODE_TYPES.Identifier) {
333
+ throw new WorkflowSyntaxError('Identifier expected', p.loc);
334
+ }
335
+ return p;
336
+ })
337
+ .map((p) => p.name);
338
+ const value = nonRestKeys.reduce((acc, propertyName) =>
339
+ // map.delete returns a copy of the object and removes the specified property
340
+ new FunctionInvocationExpression('map.delete', [
341
+ acc,
342
+ new PrimitiveExpression(propertyName),
343
+ ]), initializerExpression);
344
+ return [new AssignStepAST([[rest.argument.name, value]])];
345
+ }
95
346
  function assignmentExpressionToSteps(node, ctx) {
96
347
  let compoundOperator = undefined;
97
348
  switch (node.operator) {
@@ -122,6 +373,22 @@ function assignmentExpressionToSteps(node, ctx) {
122
373
  default:
123
374
  throw new WorkflowSyntaxError(`Operator ${node.operator} is not supported in assignment expressions`, node.loc);
124
375
  }
376
+ if (node.left.type === AST_NODE_TYPES.ArrayPattern) {
377
+ if (node.operator === '=') {
378
+ return convertArrayDestructuring(node.left, node.right, ctx);
379
+ }
380
+ else {
381
+ throw new WorkflowSyntaxError(`Invalid left-hand side in assignment`, node.left.loc);
382
+ }
383
+ }
384
+ else if (node.left.type === AST_NODE_TYPES.ObjectPattern) {
385
+ if (node.operator === '=') {
386
+ return convertObjectDestructuring(node.left, node.right, ctx);
387
+ }
388
+ else {
389
+ throw new WorkflowSyntaxError(`Invalid left-hand side in assignment`, node.left.loc);
390
+ }
391
+ }
125
392
  const targetExpression = convertExpression(node.left);
126
393
  if (!isFullyQualifiedName(targetExpression)) {
127
394
  throw new WorkflowSyntaxError('The left-hand side of an assignment must be an identifier or a property access', node.loc);
@@ -138,12 +405,12 @@ function assignmentExpressionToSteps(node, ctx) {
138
405
  }
139
406
  const needsTempVariable = compoundOperator === undefined ||
140
407
  node.left.type !== AST_NODE_TYPES.Identifier;
141
- const resultVariable = needsTempVariable ? '__temp' : targetName;
408
+ const resultVariable = needsTempVariable ? tempName(ctx) : targetName;
142
409
  steps.push(...callExpressionToStep(node.right, resultVariable, ctx));
143
410
  if (!needsTempVariable) {
144
411
  return steps;
145
412
  }
146
- valueExpression = new VariableReferenceExpression('__temp');
413
+ valueExpression = new VariableReferenceExpression(tempName(ctx));
147
414
  }
148
415
  else {
149
416
  valueExpression = convertExpression(node.right);
@@ -159,7 +426,7 @@ function callExpressionToStep(node, resultVariable, ctx) {
159
426
  if (isFullyQualifiedName(calleeExpression)) {
160
427
  const calleeName = calleeExpression.toString();
161
428
  if (calleeName === 'parallel') {
162
- // A custom implementation for "parallel"
429
+ // A handle the "parallel" intrinsic
163
430
  return [callExpressionToParallelStep(node, ctx)];
164
431
  }
165
432
  else if (calleeName === 'retry_policy') {
@@ -176,8 +443,9 @@ function callExpressionToStep(node, resultVariable, ctx) {
176
443
  ];
177
444
  }
178
445
  else {
446
+ const resultVariable2 = resultVariable ?? tempName(ctx);
179
447
  return [
180
- callExpressionAssignStep(calleeName, node.arguments, resultVariable),
448
+ callExpressionAssignStep(calleeName, node.arguments, resultVariable2),
181
449
  ];
182
450
  }
183
451
  }
@@ -189,7 +457,7 @@ function callExpressionAssignStep(functionName, argumentsNode, resultVariable) {
189
457
  const argumentExpressions = throwIfSpread(argumentsNode).map(convertExpression);
190
458
  return new AssignStepAST([
191
459
  [
192
- resultVariable ?? '__temp',
460
+ resultVariable,
193
461
  new FunctionInvocationExpression(functionName, argumentExpressions),
194
462
  ],
195
463
  ]);
@@ -199,18 +467,21 @@ function createCallStep(node, argumentsNode, resultVariable) {
199
467
  throw new WorkflowSyntaxError('The first argument must be a Function', node.loc);
200
468
  }
201
469
  let functionName;
202
- if (argumentsNode[0].type === AST_NODE_TYPES.Identifier) {
203
- functionName = argumentsNode[0].name;
204
- }
205
- else if (argumentsNode[0].type === AST_NODE_TYPES.MemberExpression) {
206
- const memberExp = convertMemberExpression(argumentsNode[0]);
470
+ const argNode = argumentsNode[0].type === AST_NODE_TYPES.TSInstantiationExpression
471
+ ? argumentsNode[0].expression
472
+ : argumentsNode[0];
473
+ if (argNode.type === AST_NODE_TYPES.Identifier) {
474
+ functionName = argNode.name;
475
+ }
476
+ else if (argNode.type === AST_NODE_TYPES.MemberExpression) {
477
+ const memberExp = convertMemberExpression(argNode);
207
478
  if (!isFullyQualifiedName(memberExp)) {
208
- throw new WorkflowSyntaxError('Function name must be a fully-qualified name', argumentsNode[0].loc);
479
+ throw new WorkflowSyntaxError('Function name must be a fully-qualified name', argNode.loc);
209
480
  }
210
481
  functionName = memberExp.toString();
211
482
  }
212
483
  else {
213
- throw new WorkflowSyntaxError('Expected an identifier or a member expression', argumentsNode[0].loc);
484
+ throw new WorkflowSyntaxError('Expected an identifier or a member expression', argNode.loc);
214
485
  }
215
486
  let args = {};
216
487
  if (argumentsNode.length >= 2) {
@@ -242,14 +513,19 @@ function callExpressionToParallelStep(node, ctx) {
242
513
  node.callee.name !== 'parallel') {
243
514
  throw new InternalTranspilingError(`The parameter must be a call to "parallel"`);
244
515
  }
516
+ const ctx2 = Object.assign({}, ctx, {
517
+ parallelNestingLevel: ctx.parallelNestingLevel
518
+ ? ctx.parallelNestingLevel + 1
519
+ : 1,
520
+ });
245
521
  let steps = {};
246
522
  if (node.arguments.length > 0) {
247
523
  switch (node.arguments[0].type) {
248
524
  case AST_NODE_TYPES.ArrayExpression:
249
- steps = parseParallelBranches(node.arguments[0]);
525
+ steps = parseParallelBranches(node.arguments[0], ctx2);
250
526
  break;
251
527
  case AST_NODE_TYPES.ArrowFunctionExpression:
252
- steps = parseParallelIteration(node.arguments[0], ctx);
528
+ steps = parseParallelIteration(node.arguments[0], ctx2);
253
529
  break;
254
530
  default:
255
531
  throw new WorkflowSyntaxError('The first parameter must be an array of functions or an arrow function', node.arguments[0].loc);
@@ -266,25 +542,21 @@ function callExpressionToParallelStep(node, ctx) {
266
542
  }
267
543
  return new ParallelStepAST(steps, shared, concurrencyLimit, exceptionPolicy);
268
544
  }
269
- function parseParallelBranches(node) {
270
- const stepsArray = node.elements.map((arg, idx) => {
271
- const branchName = `branch${idx + 1}`;
272
- if (arg === null) {
273
- throw new WorkflowSyntaxError('Argument should be a function call of type () => void', node.loc);
274
- }
275
- switch (arg.type) {
545
+ function parseParallelBranches(node, ctx) {
546
+ const branches = node.elements.map((arg) => {
547
+ switch (arg?.type) {
276
548
  case AST_NODE_TYPES.Identifier:
277
- return [branchName, new StepsStepAST([new CallStepAST(arg.name)])];
549
+ return new StepsStepAST([new CallStepAST(arg.name)]);
278
550
  case AST_NODE_TYPES.ArrowFunctionExpression:
279
551
  if (arg.body.type !== AST_NODE_TYPES.BlockStatement) {
280
552
  throw new WorkflowSyntaxError('The body must be a block statement', arg.body.loc);
281
553
  }
282
- return [branchName, new StepsStepAST(parseStatement(arg.body, {}))];
554
+ return new StepsStepAST(parseStatement(arg.body, ctx));
283
555
  default:
284
- throw new WorkflowSyntaxError('Argument should be a function call of type () => void', arg.loc);
556
+ throw new WorkflowSyntaxError('Argument should be a function of type () => void', arg ? arg.loc : node.loc);
285
557
  }
286
558
  });
287
- return Object.fromEntries(stepsArray);
559
+ return Object.fromEntries(branches.map((step, i) => [`branch${i + 1}`, step]));
288
560
  }
289
561
  function parseParallelIteration(node, ctx) {
290
562
  if (node.body.type !== AST_NODE_TYPES.BlockStatement ||
@@ -327,8 +599,8 @@ function parseParallelOptions(node) {
327
599
  exceptionPolicy,
328
600
  };
329
601
  }
330
- function generalExpressionToAssignStep(node) {
331
- return new AssignStepAST([['__temp', convertExpression(node)]]);
602
+ function generalExpressionToAssignStep(node, ctx) {
603
+ return new AssignStepAST([[tempName(ctx), convertExpression(node)]]);
332
604
  }
333
605
  function returnStatementToReturnStep(node, ctx) {
334
606
  const value = node.argument ? convertExpression(node.argument) : undefined;
@@ -358,7 +630,7 @@ function flattenIfBranches(ifStatement, ctx) {
358
630
  }
359
631
  else {
360
632
  branches.push({
361
- condition: new PrimitiveExpression(true),
633
+ condition: trueEx,
362
634
  steps: parseStatement(ifStatement.alternate, ctx),
363
635
  });
364
636
  }
@@ -378,10 +650,10 @@ function switchStatementToSteps(node, ctx) {
378
650
  condition = new BinaryExpression(discriminant, '==', test);
379
651
  }
380
652
  else {
381
- condition = new PrimitiveExpression(true);
653
+ condition = trueEx;
382
654
  }
383
655
  const jumpTarget = new JumpTargetAST();
384
- const body = transformAST(caseNode.consequent.flatMap((x) => parseStatement(x, switchCtx)));
656
+ const body = caseNode.consequent.flatMap((x) => parseStatement(x, switchCtx));
385
657
  steps.push(jumpTarget);
386
658
  steps.push(...body);
387
659
  branches.push({
@@ -413,12 +685,12 @@ function forOfStatementToForStep(node, ctx) {
413
685
  throw new WorkflowSyntaxError('Initial value not allowed', declaration.init.loc);
414
686
  }
415
687
  if (declaration.id.type !== AST_NODE_TYPES.Identifier) {
416
- throw new WorkflowSyntaxError(`Expected identifier, got ${declaration.id.type}`, declaration.id.loc);
688
+ throw new WorkflowSyntaxError(`Identifier expected, got ${declaration.id.type}`, declaration.id.loc);
417
689
  }
418
690
  loopVariableName = declaration.id.name;
419
691
  }
420
692
  else {
421
- throw new InternalTranspilingError(`Expected Identifier or VariableDeclaration, got ${node.left.type}`);
693
+ throw new InternalTranspilingError(`Identifier or VariableDeclaration expected, got ${node.left.type}`);
422
694
  }
423
695
  const listExpression = convertExpression(node.right);
424
696
  if (isLiteral(listExpression) &&
@@ -440,7 +712,7 @@ function whileStatementSteps(node, ctx) {
440
712
  breakTarget: endOfLoop.label,
441
713
  });
442
714
  const postSteps = [new NextStepAST(startOfLoop.label)];
443
- const steps = parseStatement(node.body, ctx2, postSteps);
715
+ const steps = parseStatement(node.body, ctx2).concat(postSteps);
444
716
  return [
445
717
  startOfLoop,
446
718
  new SwitchStepAST([
@@ -580,8 +852,8 @@ function extractErrorVariableName(param) {
580
852
  */
581
853
  function finalizerInitializer(conditionVariable, valueVariable) {
582
854
  return new AssignStepAST([
583
- [conditionVariable, new PrimitiveExpression(null)],
584
- [valueVariable, new PrimitiveExpression(null)],
855
+ [conditionVariable, nullEx],
856
+ [valueVariable, nullEx],
585
857
  ]);
586
858
  }
587
859
  /**
@@ -597,16 +869,18 @@ function finalizerInitializer(conditionVariable, valueVariable) {
597
869
  * }
598
870
  */
599
871
  function finalizerFooter(conditionVariable, valueVariable) {
872
+ const variable = new VariableReferenceExpression(conditionVariable);
873
+ const val = new VariableReferenceExpression(valueVariable);
874
+ const returnString = new PrimitiveExpression('return');
875
+ const raiseString = new PrimitiveExpression('raise');
600
876
  return new SwitchStepAST([
601
877
  {
602
- condition: new BinaryExpression(new VariableReferenceExpression(conditionVariable), '==', new PrimitiveExpression('return')),
603
- steps: [
604
- new ReturnStepAST(new VariableReferenceExpression(valueVariable)),
605
- ],
878
+ condition: new BinaryExpression(variable, '==', returnString),
879
+ steps: [new ReturnStepAST(val)],
606
880
  },
607
881
  {
608
- condition: new BinaryExpression(new VariableReferenceExpression(conditionVariable), '==', new PrimitiveExpression('raise')),
609
- steps: [new RaiseStepAST(new VariableReferenceExpression(valueVariable))],
882
+ condition: new BinaryExpression(variable, '==', raiseString),
883
+ steps: [new RaiseStepAST(val)],
610
884
  },
611
885
  ]);
612
886
  }
@@ -628,7 +902,7 @@ function delayedReturnAndJumpToFinalizer(value, ctx) {
628
902
  const [conditionVariable, valueVariable] = finalizerVariables(ctx);
629
903
  return new AssignStepAST([
630
904
  [conditionVariable, new PrimitiveExpression('return')],
631
- [valueVariable, value ?? new PrimitiveExpression(null)],
905
+ [valueVariable, value ?? nullEx],
632
906
  ], finalizerTarget);
633
907
  }
634
908
  function labeledStep(node, ctx) {
@@ -661,43 +935,45 @@ function parseRetryPolicy(node) {
661
935
  }
662
936
  }
663
937
  function retryPolicyFromParams(paramsObject, argsLoc) {
664
- const params = mapRecordValues(paramsObject, asExpression);
665
- if ('backoff' in params) {
666
- let predicate = '';
667
- const predicateEx = params.predicate;
668
- if (predicateEx === undefined) {
669
- predicate = undefined;
670
- }
671
- else if (isFullyQualifiedName(predicateEx)) {
672
- predicate = predicateEx.toString();
673
- }
674
- else {
675
- throw new WorkflowSyntaxError('"predicate" must be a function name', argsLoc);
676
- }
677
- const backoffEx = params.backoff;
678
- if (backoffEx.expressionType === 'primitive' && isRecord(backoffEx.value)) {
679
- const backoffLit = backoffEx.value;
680
- return {
681
- predicate,
682
- maxRetries: params.max_retries,
683
- backoff: {
684
- initialDelay: backoffLit.initial_delay
685
- ? asExpression(backoffLit.initial_delay)
686
- : undefined,
687
- maxDelay: backoffLit.max_delay
688
- ? asExpression(backoffLit.max_delay)
689
- : undefined,
690
- multiplier: backoffLit.multiplier
691
- ? asExpression(backoffLit.multiplier)
692
- : undefined,
693
- },
694
- };
695
- }
696
- else {
697
- throw new WorkflowSyntaxError('Expected an object literal', argsLoc);
698
- }
938
+ const params = R.map(asExpression, paramsObject);
939
+ if (!('backoff' in params)) {
940
+ throw new WorkflowSyntaxError('Required parameter "backoff" missing', argsLoc);
941
+ }
942
+ else if (params.backoff.expressionType !== 'primitive' ||
943
+ !isRecord(params.backoff.value)) {
944
+ throw new WorkflowSyntaxError('Expected "backoff" to be an object literal', argsLoc);
945
+ }
946
+ const backoff = params.backoff.value;
947
+ return {
948
+ predicate: predicateFromRetryParams(params, argsLoc),
949
+ maxRetries: params.max_retries,
950
+ backoff: {
951
+ initialDelay: safeAsExpression(backoff.initial_delay),
952
+ maxDelay: safeAsExpression(backoff.max_delay),
953
+ multiplier: safeAsExpression(backoff.multiplier),
954
+ },
955
+ };
956
+ }
957
+ function predicateFromRetryParams(params, argsLoc) {
958
+ if (!('predicate' in params)) {
959
+ return undefined;
960
+ }
961
+ else if (isFullyQualifiedName(params.predicate)) {
962
+ return params.predicate.toString();
963
+ }
964
+ else {
965
+ throw new WorkflowSyntaxError('"predicate" must be a function name', argsLoc);
966
+ }
967
+ }
968
+ function tempName(ctx) {
969
+ if (ctx.parallelNestingLevel !== undefined) {
970
+ // Temporary variable inside a parallel step can not be the same as temporary
971
+ // variables on the outside. Sharing the variable name would cause deployment
972
+ // error, if the variable is not marked as shared by including it in the
973
+ // "shared" array.
974
+ return `__temp_parallel${ctx.parallelNestingLevel ?? 0}`;
699
975
  }
700
976
  else {
701
- throw new WorkflowSyntaxError('Some required retry policy parameters are missing', argsLoc);
977
+ return '__temp';
702
978
  }
703
979
  }