ts2workflows 0.8.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]])];
172
+ }
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);
84
194
  }
85
- return callExpressionToStep(decl.init, targetName, ctx);
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
  ]);
@@ -245,14 +513,19 @@ function callExpressionToParallelStep(node, ctx) {
245
513
  node.callee.name !== 'parallel') {
246
514
  throw new InternalTranspilingError(`The parameter must be a call to "parallel"`);
247
515
  }
516
+ const ctx2 = Object.assign({}, ctx, {
517
+ parallelNestingLevel: ctx.parallelNestingLevel
518
+ ? ctx.parallelNestingLevel + 1
519
+ : 1,
520
+ });
248
521
  let steps = {};
249
522
  if (node.arguments.length > 0) {
250
523
  switch (node.arguments[0].type) {
251
524
  case AST_NODE_TYPES.ArrayExpression:
252
- steps = parseParallelBranches(node.arguments[0]);
525
+ steps = parseParallelBranches(node.arguments[0], ctx2);
253
526
  break;
254
527
  case AST_NODE_TYPES.ArrowFunctionExpression:
255
- steps = parseParallelIteration(node.arguments[0], ctx);
528
+ steps = parseParallelIteration(node.arguments[0], ctx2);
256
529
  break;
257
530
  default:
258
531
  throw new WorkflowSyntaxError('The first parameter must be an array of functions or an arrow function', node.arguments[0].loc);
@@ -269,25 +542,21 @@ function callExpressionToParallelStep(node, ctx) {
269
542
  }
270
543
  return new ParallelStepAST(steps, shared, concurrencyLimit, exceptionPolicy);
271
544
  }
272
- function parseParallelBranches(node) {
273
- const stepsArray = node.elements.map((arg, idx) => {
274
- const branchName = `branch${idx + 1}`;
275
- if (arg === null) {
276
- throw new WorkflowSyntaxError('Argument should be a function call of type () => void', node.loc);
277
- }
278
- switch (arg.type) {
545
+ function parseParallelBranches(node, ctx) {
546
+ const branches = node.elements.map((arg) => {
547
+ switch (arg?.type) {
279
548
  case AST_NODE_TYPES.Identifier:
280
- return [branchName, new StepsStepAST([new CallStepAST(arg.name)])];
549
+ return new StepsStepAST([new CallStepAST(arg.name)]);
281
550
  case AST_NODE_TYPES.ArrowFunctionExpression:
282
551
  if (arg.body.type !== AST_NODE_TYPES.BlockStatement) {
283
552
  throw new WorkflowSyntaxError('The body must be a block statement', arg.body.loc);
284
553
  }
285
- return [branchName, new StepsStepAST(parseStatement(arg.body, {}))];
554
+ return new StepsStepAST(parseStatement(arg.body, ctx));
286
555
  default:
287
- 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);
288
557
  }
289
558
  });
290
- return Object.fromEntries(stepsArray);
559
+ return Object.fromEntries(branches.map((step, i) => [`branch${i + 1}`, step]));
291
560
  }
292
561
  function parseParallelIteration(node, ctx) {
293
562
  if (node.body.type !== AST_NODE_TYPES.BlockStatement ||
@@ -330,8 +599,8 @@ function parseParallelOptions(node) {
330
599
  exceptionPolicy,
331
600
  };
332
601
  }
333
- function generalExpressionToAssignStep(node) {
334
- return new AssignStepAST([['__temp', convertExpression(node)]]);
602
+ function generalExpressionToAssignStep(node, ctx) {
603
+ return new AssignStepAST([[tempName(ctx), convertExpression(node)]]);
335
604
  }
336
605
  function returnStatementToReturnStep(node, ctx) {
337
606
  const value = node.argument ? convertExpression(node.argument) : undefined;
@@ -361,7 +630,7 @@ function flattenIfBranches(ifStatement, ctx) {
361
630
  }
362
631
  else {
363
632
  branches.push({
364
- condition: new PrimitiveExpression(true),
633
+ condition: trueEx,
365
634
  steps: parseStatement(ifStatement.alternate, ctx),
366
635
  });
367
636
  }
@@ -381,10 +650,10 @@ function switchStatementToSteps(node, ctx) {
381
650
  condition = new BinaryExpression(discriminant, '==', test);
382
651
  }
383
652
  else {
384
- condition = new PrimitiveExpression(true);
653
+ condition = trueEx;
385
654
  }
386
655
  const jumpTarget = new JumpTargetAST();
387
- const body = transformAST(caseNode.consequent.flatMap((x) => parseStatement(x, switchCtx)));
656
+ const body = caseNode.consequent.flatMap((x) => parseStatement(x, switchCtx));
388
657
  steps.push(jumpTarget);
389
658
  steps.push(...body);
390
659
  branches.push({
@@ -416,12 +685,12 @@ function forOfStatementToForStep(node, ctx) {
416
685
  throw new WorkflowSyntaxError('Initial value not allowed', declaration.init.loc);
417
686
  }
418
687
  if (declaration.id.type !== AST_NODE_TYPES.Identifier) {
419
- 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);
420
689
  }
421
690
  loopVariableName = declaration.id.name;
422
691
  }
423
692
  else {
424
- throw new InternalTranspilingError(`Expected Identifier or VariableDeclaration, got ${node.left.type}`);
693
+ throw new InternalTranspilingError(`Identifier or VariableDeclaration expected, got ${node.left.type}`);
425
694
  }
426
695
  const listExpression = convertExpression(node.right);
427
696
  if (isLiteral(listExpression) &&
@@ -443,7 +712,7 @@ function whileStatementSteps(node, ctx) {
443
712
  breakTarget: endOfLoop.label,
444
713
  });
445
714
  const postSteps = [new NextStepAST(startOfLoop.label)];
446
- const steps = parseStatement(node.body, ctx2, postSteps);
715
+ const steps = parseStatement(node.body, ctx2).concat(postSteps);
447
716
  return [
448
717
  startOfLoop,
449
718
  new SwitchStepAST([
@@ -583,8 +852,8 @@ function extractErrorVariableName(param) {
583
852
  */
584
853
  function finalizerInitializer(conditionVariable, valueVariable) {
585
854
  return new AssignStepAST([
586
- [conditionVariable, new PrimitiveExpression(null)],
587
- [valueVariable, new PrimitiveExpression(null)],
855
+ [conditionVariable, nullEx],
856
+ [valueVariable, nullEx],
588
857
  ]);
589
858
  }
590
859
  /**
@@ -600,16 +869,18 @@ function finalizerInitializer(conditionVariable, valueVariable) {
600
869
  * }
601
870
  */
602
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');
603
876
  return new SwitchStepAST([
604
877
  {
605
- condition: new BinaryExpression(new VariableReferenceExpression(conditionVariable), '==', new PrimitiveExpression('return')),
606
- steps: [
607
- new ReturnStepAST(new VariableReferenceExpression(valueVariable)),
608
- ],
878
+ condition: new BinaryExpression(variable, '==', returnString),
879
+ steps: [new ReturnStepAST(val)],
609
880
  },
610
881
  {
611
- condition: new BinaryExpression(new VariableReferenceExpression(conditionVariable), '==', new PrimitiveExpression('raise')),
612
- steps: [new RaiseStepAST(new VariableReferenceExpression(valueVariable))],
882
+ condition: new BinaryExpression(variable, '==', raiseString),
883
+ steps: [new RaiseStepAST(val)],
613
884
  },
614
885
  ]);
615
886
  }
@@ -631,7 +902,7 @@ function delayedReturnAndJumpToFinalizer(value, ctx) {
631
902
  const [conditionVariable, valueVariable] = finalizerVariables(ctx);
632
903
  return new AssignStepAST([
633
904
  [conditionVariable, new PrimitiveExpression('return')],
634
- [valueVariable, value ?? new PrimitiveExpression(null)],
905
+ [valueVariable, value ?? nullEx],
635
906
  ], finalizerTarget);
636
907
  }
637
908
  function labeledStep(node, ctx) {
@@ -664,43 +935,45 @@ function parseRetryPolicy(node) {
664
935
  }
665
936
  }
666
937
  function retryPolicyFromParams(paramsObject, argsLoc) {
667
- const params = mapRecordValues(paramsObject, asExpression);
668
- if ('backoff' in params) {
669
- let predicate = '';
670
- const predicateEx = params.predicate;
671
- if (predicateEx === undefined) {
672
- predicate = undefined;
673
- }
674
- else if (isFullyQualifiedName(predicateEx)) {
675
- predicate = predicateEx.toString();
676
- }
677
- else {
678
- throw new WorkflowSyntaxError('"predicate" must be a function name', argsLoc);
679
- }
680
- const backoffEx = params.backoff;
681
- if (backoffEx.expressionType === 'primitive' && isRecord(backoffEx.value)) {
682
- const backoffLit = backoffEx.value;
683
- return {
684
- predicate,
685
- maxRetries: params.max_retries,
686
- backoff: {
687
- initialDelay: backoffLit.initial_delay
688
- ? asExpression(backoffLit.initial_delay)
689
- : undefined,
690
- maxDelay: backoffLit.max_delay
691
- ? asExpression(backoffLit.max_delay)
692
- : undefined,
693
- multiplier: backoffLit.multiplier
694
- ? asExpression(backoffLit.multiplier)
695
- : undefined,
696
- },
697
- };
698
- }
699
- else {
700
- throw new WorkflowSyntaxError('Expected an object literal', argsLoc);
701
- }
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}`;
702
975
  }
703
976
  else {
704
- throw new WorkflowSyntaxError('Some required retry policy parameters are missing', argsLoc);
977
+ return '__temp';
705
978
  }
706
979
  }
@@ -1,10 +1,4 @@
1
1
  import { WorkflowStepAST } from '../ast/steps.js';
2
- /**
3
- * Performs various transformations on the AST.
4
- *
5
- * This flat list of steps and does not recurse into nested steps. This gets
6
- * called on each nesting level separately.
7
- */
8
2
  export declare function transformAST(steps: WorkflowStepAST[]): WorkflowStepAST[];
9
3
  /**
10
4
  * Merge a next step to the previous step.
@@ -1 +1 @@
1
- {"version":3,"file":"transformations.d.ts","sourceRoot":"","sources":["../../src/transpiler/transformations.ts"],"names":[],"mappings":"AAAA,OAAO,EASL,eAAe,EAChB,MAAM,iBAAiB,CAAA;AAqBxB;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,eAAe,EAAE,CAQxE;AAiCD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,eAAe,EAAE,GACvB,eAAe,EAAE,CAqBnB"}
1
+ {"version":3,"file":"transformations.d.ts","sourceRoot":"","sources":["../../src/transpiler/transformations.ts"],"names":[],"mappings":"AACA,OAAO,EAQL,eAAe,EAChB,MAAM,iBAAiB,CAAA;AA6BxB,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,eAAe,EAAE,CAExE;AAiCD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,eAAe,EAAE,GACvB,eAAe,EAAE,CAqBnB"}