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