ts2workflows 0.3.0 → 0.4.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,105 +1,89 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument */
2
- import { AST_NODE_TYPES } from '@typescript-eslint/utils';
3
- import { AssignStepAST, CallStepAST, ForStepAST, JumpTargetAST, NextStepAST, ParallelStepAST, RaiseStepAST, ReturnStepAST, StepsStepAST, SwitchStepAST, TryStepAST, stepWithLabel, } from '../ast/steps.js';
1
+ 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';
4
3
  import { BinaryExpression, FunctionInvocationExpression, PrimitiveExpression, VariableReferenceExpression, isExpression, isFullyQualifiedName, isLiteral, } from '../ast/expressions.js';
5
4
  import { InternalTranspilingError, WorkflowSyntaxError } from '../errors.js';
6
5
  import { isRecord } from '../utils.js';
7
6
  import { transformAST } from './transformations.js';
8
- import { assertType } from './asserts.js';
9
- import { convertExpression, convertMemberExpression, convertObjectExpression, convertObjectAsExpressionValues, } from './expressions.js';
7
+ import { convertExpression, convertMemberExpression, convertObjectExpression, convertObjectAsExpressionValues, isMagicFunction, throwIfSpread, } from './expressions.js';
10
8
  import { blockingFunctions } from './generated/functionMetadata.js';
11
- const { ArrayExpression, ArrowFunctionExpression, AssignmentExpression, BlockStatement, BreakStatement, CallExpression, ContinueStatement, DoWhileStatement, EmptyStatement, ExpressionStatement, ForInStatement, ForOfStatement, FunctionDeclaration, Identifier, IfStatement, LabeledStatement, MemberExpression, ObjectExpression, ReturnStatement, SwitchCase, SwitchStatement, ThrowStatement, TryStatement, TSDeclareFunction, TSTypeAliasDeclaration, TSInterfaceDeclaration, VariableDeclaration, VariableDeclarator, WhileStatement, } = AST_NODE_TYPES;
12
- export function parseBlockStatement(node, ctx) {
13
- assertType(node, BlockStatement);
14
- const body = node.body;
15
- return transformAST(body.flatMap((x) => parseStep(x, ctx)));
9
+ export function parseStatement(node, ctx, postSteps) {
10
+ const steps = parseStatementRecursively(node, ctx);
11
+ return transformAST(steps.concat(postSteps ?? []));
16
12
  }
17
- function parseStep(node, ctx) {
13
+ function parseStatementRecursively(node, ctx) {
18
14
  switch (node.type) {
19
- case VariableDeclaration:
20
- return convertVariableDeclarations(node.declarations);
21
- case ExpressionStatement:
22
- if (node.expression.type === AssignmentExpression) {
23
- return assignmentExpressionToSteps(node.expression);
15
+ case AST_NODE_TYPES.BlockStatement:
16
+ return node.body.flatMap((statement) => parseStatementRecursively(statement, ctx));
17
+ case AST_NODE_TYPES.VariableDeclaration:
18
+ return convertVariableDeclarations(node.declarations, ctx);
19
+ case AST_NODE_TYPES.ExpressionStatement:
20
+ if (node.expression.type === AST_NODE_TYPES.AssignmentExpression) {
21
+ return assignmentExpressionToSteps(node.expression, ctx);
24
22
  }
25
- else if (node.expression.type === CallExpression) {
26
- return [callExpressionToStep(node.expression, ctx)];
23
+ else if (node.expression.type === AST_NODE_TYPES.CallExpression) {
24
+ return [callExpressionToStep(node.expression, undefined, ctx)];
27
25
  }
28
26
  else {
29
27
  return [generalExpressionToAssignStep(node.expression)];
30
28
  }
31
- case ReturnStatement:
29
+ case AST_NODE_TYPES.ReturnStatement:
32
30
  return [returnStatementToReturnStep(node)];
33
- case ThrowStatement:
31
+ case AST_NODE_TYPES.ThrowStatement:
34
32
  return [throwStatementToRaiseStep(node)];
35
- case IfStatement:
33
+ case AST_NODE_TYPES.IfStatement:
36
34
  return [ifStatementToSwitchStep(node, ctx)];
37
- case SwitchStatement:
35
+ case AST_NODE_TYPES.SwitchStatement:
38
36
  return switchStatementToSteps(node, ctx);
39
- case ForInStatement:
37
+ case AST_NODE_TYPES.ForInStatement:
40
38
  throw new WorkflowSyntaxError('for...in is not a supported construct. Use for...of.', node.loc);
41
- case ForOfStatement:
39
+ case AST_NODE_TYPES.ForOfStatement:
42
40
  return [forOfStatementToForStep(node, ctx)];
43
- case DoWhileStatement:
41
+ case AST_NODE_TYPES.DoWhileStatement:
44
42
  return doWhileStatementSteps(node, ctx);
45
- case WhileStatement:
43
+ case AST_NODE_TYPES.WhileStatement:
46
44
  return whileStatementSteps(node, ctx);
47
- case BreakStatement:
45
+ case AST_NODE_TYPES.BreakStatement:
48
46
  return [breakStatementToNextStep(node, ctx)];
49
- case ContinueStatement:
47
+ case AST_NODE_TYPES.ContinueStatement:
50
48
  return [continueStatementToNextStep(node, ctx)];
51
- case TryStatement:
49
+ case AST_NODE_TYPES.TryStatement:
52
50
  return [tryStatementToTryStep(node, ctx)];
53
- case LabeledStatement:
51
+ case AST_NODE_TYPES.LabeledStatement:
54
52
  return labeledStep(node, ctx);
55
- case EmptyStatement:
53
+ case AST_NODE_TYPES.EmptyStatement:
56
54
  return [];
57
- case FunctionDeclaration:
55
+ case AST_NODE_TYPES.FunctionDeclaration:
58
56
  throw new WorkflowSyntaxError('Functions must be defined at the top level of a source file', node.loc);
59
- case TSInterfaceDeclaration:
60
- case TSTypeAliasDeclaration:
61
- case TSDeclareFunction:
57
+ case AST_NODE_TYPES.TSInterfaceDeclaration:
58
+ case AST_NODE_TYPES.TSTypeAliasDeclaration:
59
+ case AST_NODE_TYPES.TSDeclareFunction:
62
60
  // Ignore "type", "interface" and "declare function"
63
61
  return [];
64
62
  default:
65
63
  throw new WorkflowSyntaxError(`TODO: encountered unsupported type: ${node.type}`, node.loc);
66
64
  }
67
65
  }
68
- function convertVariableDeclarations(declarations) {
66
+ function convertVariableDeclarations(declarations, ctx) {
69
67
  return declarations.map((decl) => {
70
- if (decl.type !== VariableDeclarator) {
68
+ if (decl.type !== AST_NODE_TYPES.VariableDeclarator) {
71
69
  throw new WorkflowSyntaxError('Not a VariableDeclarator', decl.loc);
72
70
  }
73
- if (decl.id.type !== Identifier) {
71
+ if (decl.id.type !== AST_NODE_TYPES.Identifier) {
74
72
  throw new WorkflowSyntaxError('Expected Identifier', decl.loc);
75
73
  }
76
74
  const targetName = decl.id.name;
77
- if (!decl.init) {
78
- return new AssignStepAST([[targetName, new PrimitiveExpression(null)]]);
79
- }
80
- else if (decl.init.type === CallExpression) {
81
- const maybeBlockingcall = getBlockingCallParameters(decl.init);
82
- if (maybeBlockingcall.isBlockingCall) {
83
- // This branch could be removed. The transform step for extracting
84
- // blocking function would take care of this, but it creates an
85
- // unnecessary temporary variable assignment step.
86
- return blockingFunctionCallStep(maybeBlockingcall.functionName, maybeBlockingcall.argumentNames, decl.init.arguments, targetName);
87
- }
88
- else if (decl.init.callee.type === Identifier &&
89
- decl.init.callee.name === 'call_step') {
90
- return createCallStep(decl.init.arguments, targetName);
91
- }
92
- else {
93
- return new AssignStepAST([[targetName, convertExpression(decl.init)]]);
94
- }
75
+ if (decl.init?.type === AST_NODE_TYPES.CallExpression) {
76
+ return callExpressionToStep(decl.init, targetName, ctx);
95
77
  }
96
78
  else {
97
- return new AssignStepAST([[targetName, convertExpression(decl.init)]]);
79
+ const value = decl.init == null
80
+ ? new PrimitiveExpression(null)
81
+ : convertExpression(decl.init);
82
+ return new AssignStepAST([[targetName, value]]);
98
83
  }
99
84
  });
100
85
  }
101
- function assignmentExpressionToSteps(node) {
102
- assertType(node, AssignmentExpression);
86
+ function assignmentExpressionToSteps(node, ctx) {
103
87
  let compoundOperator = undefined;
104
88
  switch (node.operator) {
105
89
  case '=':
@@ -133,25 +117,31 @@ function assignmentExpressionToSteps(node) {
133
117
  if (!isFullyQualifiedName(targetExpression)) {
134
118
  throw new WorkflowSyntaxError('The left-hand side of an assignment must be an identifier or a property access', node.loc);
135
119
  }
120
+ let valueExpression;
121
+ const steps = [];
136
122
  const targetName = targetExpression.toString();
137
- let valueExpression = convertExpression(node.right);
123
+ if (node.right.type === AST_NODE_TYPES.CallExpression &&
124
+ node.right.callee.type === AST_NODE_TYPES.Identifier &&
125
+ isMagicFunction(node.right.callee.name)) {
126
+ const needsTempVariable = compoundOperator === undefined ||
127
+ node.left.type !== AST_NODE_TYPES.Identifier;
128
+ const resultVariable = needsTempVariable ? '__temp' : targetName;
129
+ steps.push(callExpressionToStep(node.right, resultVariable, ctx));
130
+ if (!needsTempVariable) {
131
+ return steps;
132
+ }
133
+ valueExpression = new VariableReferenceExpression('__temp');
134
+ }
135
+ else {
136
+ valueExpression = convertExpression(node.right);
137
+ }
138
138
  if (compoundOperator) {
139
139
  valueExpression = new BinaryExpression(new VariableReferenceExpression(targetName), compoundOperator, valueExpression);
140
140
  }
141
- return [new AssignStepAST([[targetName, valueExpression]])];
142
- }
143
- function getBlockingCallParameters(node) {
144
- if (node?.type === CallExpression) {
145
- const functionName = convertExpression(node.callee).toString();
146
- const argumentNames = blockingFunctions.get(functionName);
147
- if (argumentNames) {
148
- return { isBlockingCall: true, functionName, argumentNames };
149
- }
150
- }
151
- return { isBlockingCall: false };
141
+ steps.push(new AssignStepAST([[targetName, valueExpression]]));
142
+ return steps;
152
143
  }
153
- function callExpressionToStep(node, ctx) {
154
- assertType(node, CallExpression);
144
+ function callExpressionToStep(node, resultVariable, ctx) {
155
145
  const calleeExpression = convertExpression(node.callee);
156
146
  if (isFullyQualifiedName(calleeExpression)) {
157
147
  const calleeName = calleeExpression.toString();
@@ -160,48 +150,49 @@ function callExpressionToStep(node, ctx) {
160
150
  return callExpressionToParallelStep(node, ctx);
161
151
  }
162
152
  else if (calleeName === 'retry_policy') {
163
- return callExpressionToCallStep(calleeName, node.arguments);
153
+ return callExpressionToCallStep(calleeName, node.arguments, resultVariable);
164
154
  }
165
155
  else if (calleeName === 'call_step') {
166
- return createCallStep(node.arguments);
156
+ return createCallStep(node.arguments, resultVariable);
167
157
  }
168
158
  else if (blockingFunctions.has(calleeName)) {
169
159
  const argumentNames = blockingFunctions.get(calleeName) ?? [];
170
- return blockingFunctionCallStep(calleeName, argumentNames, node.arguments);
160
+ return blockingFunctionCallStep(calleeName, argumentNames, node.arguments, resultVariable);
171
161
  }
172
162
  else {
173
- return callExpressionAssignStep(calleeName, node.arguments);
163
+ return callExpressionAssignStep(calleeName, node.arguments, resultVariable);
174
164
  }
175
165
  }
176
166
  else {
177
167
  throw new WorkflowSyntaxError('Expeced a subworkflow or a standard library function name', node.callee.loc);
178
168
  }
179
169
  }
180
- function callExpressionAssignStep(functionName, argumentsNode) {
181
- const argumentExpressions = argumentsNode.map(convertExpression);
170
+ function callExpressionAssignStep(functionName, argumentsNode, resultVariable) {
171
+ const argumentExpressions = throwIfSpread(argumentsNode).map(convertExpression);
182
172
  return new AssignStepAST([
183
173
  [
184
- '__temp',
174
+ resultVariable ?? '__temp',
185
175
  new FunctionInvocationExpression(functionName, argumentExpressions),
186
176
  ],
187
177
  ]);
188
178
  }
189
- function callExpressionToCallStep(functionName, argumentsNode) {
190
- if (argumentsNode.length < 1 || argumentsNode[0].type !== ObjectExpression) {
179
+ function callExpressionToCallStep(functionName, argumentsNode, resultVariable) {
180
+ if (argumentsNode.length < 1 ||
181
+ argumentsNode[0].type !== AST_NODE_TYPES.ObjectExpression) {
191
182
  throw new WorkflowSyntaxError('Expected one object parameter', argumentsNode[0].loc);
192
183
  }
193
184
  const workflowArguments = convertObjectAsExpressionValues(argumentsNode[0]);
194
- return new CallStepAST(functionName, workflowArguments);
185
+ return new CallStepAST(functionName, workflowArguments, resultVariable);
195
186
  }
196
187
  function createCallStep(argumentsNode, resultVariable) {
197
188
  if (argumentsNode.length < 1) {
198
189
  throw new WorkflowSyntaxError('The first argument must be a Function', argumentsNode[0].loc);
199
190
  }
200
191
  let functionName;
201
- if (argumentsNode[0].type === Identifier) {
192
+ if (argumentsNode[0].type === AST_NODE_TYPES.Identifier) {
202
193
  functionName = argumentsNode[0].name;
203
194
  }
204
- else if (argumentsNode[0].type === MemberExpression) {
195
+ else if (argumentsNode[0].type === AST_NODE_TYPES.MemberExpression) {
205
196
  const memberExp = convertMemberExpression(argumentsNode[0]);
206
197
  if (!isFullyQualifiedName(memberExp)) {
207
198
  throw new WorkflowSyntaxError('Function name must be a fully-qualified name', argumentsNode[0].loc);
@@ -213,7 +204,7 @@ function createCallStep(argumentsNode, resultVariable) {
213
204
  }
214
205
  let args = {};
215
206
  if (argumentsNode.length >= 2) {
216
- if (argumentsNode[1].type !== ObjectExpression) {
207
+ if (argumentsNode[1].type !== AST_NODE_TYPES.ObjectExpression) {
217
208
  throw new WorkflowSyntaxError('The second argument must be an object', argumentsNode[1].loc);
218
209
  }
219
210
  args = convertObjectAsExpressionValues(argumentsNode[1]);
@@ -221,12 +212,12 @@ function createCallStep(argumentsNode, resultVariable) {
221
212
  return new CallStepAST(functionName, args, resultVariable);
222
213
  }
223
214
  function blockingFunctionCallStep(functionName, argumentNames, argumentsNode, resultName) {
224
- const argumentExpressions = argumentsNode.map(convertExpression);
215
+ const argumentExpressions = throwIfSpread(argumentsNode).map(convertExpression);
225
216
  const args = Object.fromEntries(argumentNames.flatMap((argName, i) => {
226
217
  if (i >= argumentExpressions.length) {
227
218
  return [];
228
219
  }
229
- else if (argumentsNode[i].type === Identifier &&
220
+ else if (argumentsNode[i].type === AST_NODE_TYPES.Identifier &&
230
221
  argumentsNode[i].name === 'undefined') {
231
222
  return [];
232
223
  }
@@ -237,18 +228,17 @@ function blockingFunctionCallStep(functionName, argumentNames, argumentsNode, re
237
228
  return new CallStepAST(functionName, args, resultName);
238
229
  }
239
230
  function callExpressionToParallelStep(node, ctx) {
240
- assertType(node, CallExpression);
241
- assertType(node.callee, Identifier);
242
- if (node.callee.name !== 'parallel') {
243
- throw new TypeError(`The parameter must be a call to "parallel"`);
231
+ if (node.callee.type !== AST_NODE_TYPES.Identifier ||
232
+ node.callee.name !== 'parallel') {
233
+ throw new InternalTranspilingError(`The parameter must be a call to "parallel"`);
244
234
  }
245
235
  let steps = {};
246
236
  if (node.arguments.length > 0) {
247
237
  switch (node.arguments[0].type) {
248
- case ArrayExpression:
238
+ case AST_NODE_TYPES.ArrayExpression:
249
239
  steps = parseParallelBranches(node.arguments[0]);
250
240
  break;
251
- case ArrowFunctionExpression:
241
+ case AST_NODE_TYPES.ArrowFunctionExpression:
252
242
  steps = parseParallelIteration(node.arguments[0], ctx);
253
243
  break;
254
244
  default:
@@ -267,18 +257,19 @@ function callExpressionToParallelStep(node, ctx) {
267
257
  return new ParallelStepAST(steps, shared, concurrencyLimit, exceptionPolicy);
268
258
  }
269
259
  function parseParallelBranches(node) {
270
- assertType(node, ArrayExpression);
271
- const nodeElements = node.elements;
272
- const stepsArray = nodeElements.map((arg, idx) => {
260
+ const stepsArray = node.elements.map((arg, idx) => {
273
261
  const branchName = `branch${idx + 1}`;
262
+ if (arg === null) {
263
+ throw new WorkflowSyntaxError('Argument should be a function call of type () => void', node.loc);
264
+ }
274
265
  switch (arg.type) {
275
- case Identifier:
266
+ case AST_NODE_TYPES.Identifier:
276
267
  return [branchName, new StepsStepAST([new CallStepAST(arg.name)])];
277
- case ArrowFunctionExpression:
278
- return [
279
- branchName,
280
- new StepsStepAST(parseBlockStatement(arg.body, {})),
281
- ];
268
+ case AST_NODE_TYPES.ArrowFunctionExpression:
269
+ if (arg.body.type !== AST_NODE_TYPES.BlockStatement) {
270
+ throw new WorkflowSyntaxError('The body must be a block statement', arg.body.loc);
271
+ }
272
+ return [branchName, new StepsStepAST(parseStatement(arg.body, {}))];
282
273
  default:
283
274
  throw new WorkflowSyntaxError('Argument should be a function call of type () => void', arg.loc);
284
275
  }
@@ -286,15 +277,15 @@ function parseParallelBranches(node) {
286
277
  return Object.fromEntries(stepsArray);
287
278
  }
288
279
  function parseParallelIteration(node, ctx) {
289
- assertType(node, ArrowFunctionExpression);
290
- if (node.body.body.length !== 1 ||
291
- node.body.body[0].type !== ForOfStatement) {
280
+ if (node.body.type !== AST_NODE_TYPES.BlockStatement ||
281
+ node.body.body.length !== 1 ||
282
+ node.body.body[0].type !== AST_NODE_TYPES.ForOfStatement) {
292
283
  throw new WorkflowSyntaxError('The parallel function body must be a single for...of statement', node.body.loc);
293
284
  }
294
285
  return forOfStatementToForStep(node.body.body[0], ctx);
295
286
  }
296
287
  function parseParallelOptions(node) {
297
- if (node.type !== ObjectExpression) {
288
+ if (node.type !== AST_NODE_TYPES.ObjectExpression) {
298
289
  throw new WorkflowSyntaxError('The second parameter must be an object', node.loc);
299
290
  }
300
291
  const parallelOptions = convertObjectExpression(node);
@@ -330,53 +321,42 @@ function generalExpressionToAssignStep(node) {
330
321
  return new AssignStepAST([['__temp', convertExpression(node)]]);
331
322
  }
332
323
  function returnStatementToReturnStep(node) {
333
- assertType(node, ReturnStatement);
334
324
  const value = node.argument ? convertExpression(node.argument) : undefined;
335
325
  return new ReturnStepAST(value);
336
326
  }
337
327
  function throwStatementToRaiseStep(node) {
338
- assertType(node, ThrowStatement);
339
328
  return new RaiseStepAST(convertExpression(node.argument));
340
329
  }
341
330
  function ifStatementToSwitchStep(node, ctx) {
342
- assertType(node, IfStatement);
343
331
  return new SwitchStepAST(flattenIfBranches(node, ctx));
344
332
  }
345
333
  function flattenIfBranches(ifStatement, ctx) {
346
- assertType(ifStatement, IfStatement);
347
- assertType(ifStatement.consequent, BlockStatement);
348
334
  const branches = [
349
335
  {
350
336
  condition: convertExpression(ifStatement.test),
351
- steps: parseBlockStatement(ifStatement.consequent, ctx),
337
+ steps: parseStatement(ifStatement.consequent, ctx),
352
338
  },
353
339
  ];
354
340
  if (ifStatement.alternate) {
355
- if (ifStatement.alternate.type === BlockStatement) {
356
- branches.push({
357
- condition: new PrimitiveExpression(true),
358
- steps: parseBlockStatement(ifStatement.alternate, ctx),
359
- });
360
- }
361
- else if (ifStatement.alternate.type === IfStatement) {
341
+ if (ifStatement.alternate.type === AST_NODE_TYPES.IfStatement) {
362
342
  branches.push(...flattenIfBranches(ifStatement.alternate, ctx));
363
343
  }
364
344
  else {
365
- throw new InternalTranspilingError(`Expected BlockStatement or IfStatement, got ${ifStatement.alternate.type}`);
345
+ branches.push({
346
+ condition: new PrimitiveExpression(true),
347
+ steps: parseStatement(ifStatement.alternate, ctx),
348
+ });
366
349
  }
367
350
  }
368
351
  return branches;
369
352
  }
370
353
  function switchStatementToSteps(node, ctx) {
371
- assertType(node, SwitchStatement);
372
354
  const endOfSwitch = new JumpTargetAST();
373
355
  const switchCtx = Object.assign({}, ctx, { breakTarget: endOfSwitch.label });
374
356
  const steps = [];
375
357
  const branches = [];
376
358
  const discriminant = convertExpression(node.discriminant);
377
- const cases = node.cases;
378
- cases.forEach((caseNode) => {
379
- assertType(caseNode, SwitchCase);
359
+ node.cases.forEach((caseNode) => {
380
360
  let condition;
381
361
  if (caseNode.test) {
382
362
  const test = convertExpression(caseNode.test);
@@ -386,8 +366,7 @@ function switchStatementToSteps(node, ctx) {
386
366
  condition = new PrimitiveExpression(true);
387
367
  }
388
368
  const jumpTarget = new JumpTargetAST();
389
- const consequent = caseNode.consequent;
390
- const body = transformAST(consequent.flatMap((x) => parseStep(x, switchCtx)));
369
+ const body = transformAST(caseNode.consequent.flatMap((x) => parseStatement(x, switchCtx)));
391
370
  steps.push(jumpTarget);
392
371
  steps.push(...body);
393
372
  branches.push({
@@ -401,18 +380,16 @@ function switchStatementToSteps(node, ctx) {
401
380
  return steps;
402
381
  }
403
382
  function forOfStatementToForStep(node, ctx) {
404
- assertType(node, ForOfStatement);
405
- assertType(node.body, BlockStatement);
406
383
  const bodyCtx = Object.assign({}, ctx, {
407
384
  continueTarget: undefined,
408
385
  breakTarget: undefined,
409
386
  });
410
- const steps = parseBlockStatement(node.body, bodyCtx);
387
+ const steps = parseStatement(node.body, bodyCtx);
411
388
  let loopVariableName;
412
- if (node.left.type === Identifier) {
389
+ if (node.left.type === AST_NODE_TYPES.Identifier) {
413
390
  loopVariableName = node.left.name;
414
391
  }
415
- else if (node.left.type === VariableDeclaration) {
392
+ else if (node.left.type === AST_NODE_TYPES.VariableDeclaration) {
416
393
  if (node.left.declarations.length !== 1) {
417
394
  throw new WorkflowSyntaxError('Only one variable can be declared here', node.left.loc);
418
395
  }
@@ -420,7 +397,9 @@ function forOfStatementToForStep(node, ctx) {
420
397
  if (declaration.init !== null) {
421
398
  throw new WorkflowSyntaxError('Initial value not allowed', declaration.init.loc);
422
399
  }
423
- assertType(declaration.id, Identifier);
400
+ if (declaration.id.type !== AST_NODE_TYPES.Identifier) {
401
+ throw new WorkflowSyntaxError(`Expected identifier, got ${declaration.id.type}`, declaration.id.loc);
402
+ }
424
403
  loopVariableName = declaration.id.name;
425
404
  }
426
405
  else {
@@ -439,15 +418,14 @@ function forOfStatementToForStep(node, ctx) {
439
418
  return new ForStepAST(steps, loopVariableName, listExpression);
440
419
  }
441
420
  function whileStatementSteps(node, ctx) {
442
- assertType(node, WhileStatement);
443
421
  const startOfLoop = new JumpTargetAST();
444
422
  const endOfLoop = new JumpTargetAST();
445
423
  const ctx2 = Object.assign({}, ctx, {
446
424
  continueTarget: startOfLoop.label,
447
425
  breakTarget: endOfLoop.label,
448
426
  });
449
- const steps = parseBlockStatement(node.body, ctx2);
450
- steps.push(new NextStepAST(startOfLoop.label));
427
+ const postSteps = [new NextStepAST(startOfLoop.label)];
428
+ const steps = parseStatement(node.body, ctx2, postSteps);
451
429
  return [
452
430
  startOfLoop,
453
431
  new SwitchStepAST([
@@ -460,7 +438,6 @@ function whileStatementSteps(node, ctx) {
460
438
  ];
461
439
  }
462
440
  function doWhileStatementSteps(node, ctx) {
463
- assertType(node, DoWhileStatement);
464
441
  const startOfLoop = new JumpTargetAST();
465
442
  const endOfLoop = new JumpTargetAST();
466
443
  const ctx2 = Object.assign({}, ctx, {
@@ -468,7 +445,7 @@ function doWhileStatementSteps(node, ctx) {
468
445
  breakTarget: endOfLoop.label,
469
446
  });
470
447
  const steps = [startOfLoop];
471
- steps.push(...parseBlockStatement(node.body, ctx2));
448
+ steps.push(...parseStatement(node.body, ctx2));
472
449
  steps.push(new SwitchStepAST([
473
450
  {
474
451
  condition: convertExpression(node.test),
@@ -480,10 +457,8 @@ function doWhileStatementSteps(node, ctx) {
480
457
  return steps;
481
458
  }
482
459
  function breakStatementToNextStep(node, ctx) {
483
- assertType(node, BreakStatement);
484
460
  let target;
485
461
  if (node.label) {
486
- assertType(node.label, Identifier);
487
462
  target = node.label.name;
488
463
  }
489
464
  else if (ctx.breakTarget) {
@@ -495,10 +470,8 @@ function breakStatementToNextStep(node, ctx) {
495
470
  return new NextStepAST(target);
496
471
  }
497
472
  function continueStatementToNextStep(node, ctx) {
498
- assertType(node, ContinueStatement);
499
473
  let target;
500
474
  if (node.label) {
501
- assertType(node.label, Identifier);
502
475
  target = node.label.name;
503
476
  }
504
477
  else if (ctx.continueTarget) {
@@ -510,14 +483,18 @@ function continueStatementToNextStep(node, ctx) {
510
483
  return new NextStepAST(target);
511
484
  }
512
485
  function tryStatementToTryStep(node, ctx) {
513
- assertType(node, TryStatement);
514
- const steps = parseBlockStatement(node.block, ctx);
515
- const exceptSteps = parseBlockStatement(node.handler.body, ctx);
486
+ const steps = parseStatement(node.block, ctx);
487
+ let exceptSteps = [];
516
488
  let errorVariable = undefined;
517
- const handlerParam = node.handler.param;
518
- if (handlerParam) {
519
- assertType(handlerParam, Identifier);
520
- errorVariable = handlerParam.name;
489
+ if (node.handler) {
490
+ exceptSteps = parseStatement(node.handler.body, ctx);
491
+ const handlerParam = node.handler.param;
492
+ if (handlerParam) {
493
+ if (handlerParam.type !== AST_NODE_TYPES.Identifier) {
494
+ throw new WorkflowSyntaxError('The error variable must be an identifier', handlerParam.loc);
495
+ }
496
+ errorVariable = handlerParam.name;
497
+ }
521
498
  }
522
499
  if (node.finalizer !== null) {
523
500
  // TODO
@@ -526,11 +503,9 @@ function tryStatementToTryStep(node, ctx) {
526
503
  return new TryStepAST(steps, exceptSteps, undefined, errorVariable);
527
504
  }
528
505
  function labeledStep(node, ctx) {
529
- assertType(node, LabeledStatement);
530
- const steps = parseStep(node.body, ctx);
531
- if (steps.length > 0) {
532
- steps[0] = stepWithLabel(steps[0], node.label.name);
533
- return steps;
506
+ const steps = parseStatement(node.body, ctx);
507
+ if (steps.length > 0 && steps[0].tag !== 'jumptarget') {
508
+ steps[0] = steps[0].withLabel(node.label.name);
534
509
  }
535
510
  return steps;
536
511
  }
@@ -1 +1 @@
1
- {"version":3,"file":"transformations.d.ts","sourceRoot":"","sources":["../../src/transpiler/transformations.ts"],"names":[],"mappings":"AAAA,OAAO,EAUL,eAAe,EAChB,MAAM,iBAAiB,CAAA;AAuBxB;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,eAAe,EAAE,CAUxE;AA0JD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,eAAe,EAAE,GACvB,eAAe,EAAE,CAoBnB"}
1
+ {"version":3,"file":"transformations.d.ts","sourceRoot":"","sources":["../../src/transpiler/transformations.ts"],"names":[],"mappings":"AAAA,OAAO,EAUL,eAAe,EAChB,MAAM,iBAAiB,CAAA;AAuBxB;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,eAAe,EAAE,CAUxE;AA4JD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,eAAe,EAAE,GACvB,eAAe,EAAE,CAqBnB"}
@@ -23,8 +23,9 @@ function mergeAssignSteps(steps) {
23
23
  const prev = acc.length > 0 ? acc[acc.length - 1] : null;
24
24
  if (current.tag === 'assign' &&
25
25
  prev?.tag === 'assign' &&
26
- prev.assignments.length < 50) {
27
- const merged = new AssignStepAST(prev.assignments.concat(current.assignments));
26
+ prev.assignments.length < 50 &&
27
+ !prev.next) {
28
+ const merged = new AssignStepAST(prev.assignments.concat(current.assignments), current.next);
28
29
  acc.pop();
29
30
  acc.push(merged);
30
31
  }
@@ -142,26 +143,29 @@ function parseRetryPolicyNumber(record, keyName) {
142
143
  * next: target1
143
144
  */
144
145
  export function flattenPlainNextConditions(steps) {
145
- /*
146
- const res = steps.reduce((acc: WorkflowStepAST[], step: WorkflowStepAST) => {
147
- if (acc.length > 0) {
148
- if (step.tag === 'next') {
149
- const prev = acc[-1]
150
-
151
- if (prev.tag === 'assign') {
152
-
153
- }
154
-
146
+ return steps.reduce((acc, step) => {
147
+ if (acc.length > 0 && step.tag === 'next') {
148
+ // Merge a "next" to the previous "assign" step
149
+ const prev = acc[acc.length - 1];
150
+ if (prev.tag === 'assign' && !prev.next) {
151
+ acc.pop();
152
+ acc.push(prev.withNext(step.target));
153
+ }
154
+ else {
155
+ acc.push(step);
156
+ }
157
+ }
158
+ else if (step.tag === 'switch') {
159
+ // If the condition steps consists of a single "next", merge it with the condition
160
+ acc.push(flattenNextToCondition(step));
155
161
  }
156
- }
157
-
158
- return acc
159
- }, [])
160
-
161
- */
162
- return steps.map((step) => (step.tag === 'switch' ? flattenNext(step) : step));
162
+ else {
163
+ acc.push(step);
164
+ }
165
+ return acc;
166
+ }, []);
163
167
  }
164
- function flattenNext(step) {
168
+ function flattenNextToCondition(step) {
165
169
  const transformedBranches = step.branches.map((cond) => {
166
170
  if (!cond.next && cond.steps.length === 1 && cond.steps[0].tag === 'next') {
167
171
  const nextStep = cond.steps[0];
@@ -287,7 +291,7 @@ function transformExpressionsAssign(step, transform) {
287
291
  newSteps.push(...steps2);
288
292
  return [name, ex2];
289
293
  });
290
- newSteps.push(new AssignStepAST(newAssignments, step.label));
294
+ newSteps.push(new AssignStepAST(newAssignments, step.next, step.label));
291
295
  return newSteps;
292
296
  }
293
297
  else {