ts2workflows 0.2.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.
- package/dist/ast/stepnames.d.ts.map +1 -1
- package/dist/ast/stepnames.js +11 -1
- package/dist/ast/steps.d.ts +24 -13
- package/dist/ast/steps.d.ts.map +1 -1
- package/dist/ast/steps.js +42 -27
- package/dist/transpiler/expressions.d.ts +7 -4
- package/dist/transpiler/expressions.d.ts.map +1 -1
- package/dist/transpiler/expressions.js +156 -37
- package/dist/transpiler/index.d.ts.map +1 -1
- package/dist/transpiler/index.js +29 -28
- package/dist/transpiler/statements.d.ts +2 -1
- package/dist/transpiler/statements.d.ts.map +1 -1
- package/dist/transpiler/statements.js +135 -158
- package/dist/transpiler/transformations.d.ts +1 -1
- package/dist/transpiler/transformations.d.ts.map +1 -1
- package/dist/transpiler/transformations.js +27 -6
- package/language_reference.md +57 -35
- package/package.json +22 -3
- package/types/global.d.ts +116 -0
- package/types/workflowslib.d.ts +17 -5
- package/dist/transpiler/asserts.d.ts +0 -7
- package/dist/transpiler/asserts.d.ts.map +0 -1
- package/dist/transpiler/asserts.js +0 -11
|
@@ -1,105 +1,89 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
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 {
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
|
13
|
+
function parseStatementRecursively(node, ctx) {
|
|
18
14
|
switch (node.type) {
|
|
19
|
-
case
|
|
20
|
-
return
|
|
21
|
-
case
|
|
22
|
-
|
|
23
|
-
|
|
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 (
|
|
78
|
-
return
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,46 +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);
|
|
182
|
-
|
|
183
|
-
[
|
|
184
|
-
|
|
185
|
-
|
|
170
|
+
function callExpressionAssignStep(functionName, argumentsNode, resultVariable) {
|
|
171
|
+
const argumentExpressions = throwIfSpread(argumentsNode).map(convertExpression);
|
|
172
|
+
return new AssignStepAST([
|
|
173
|
+
[
|
|
174
|
+
resultVariable ?? '__temp',
|
|
175
|
+
new FunctionInvocationExpression(functionName, argumentExpressions),
|
|
176
|
+
],
|
|
177
|
+
]);
|
|
186
178
|
}
|
|
187
|
-
function callExpressionToCallStep(functionName, argumentsNode) {
|
|
188
|
-
if (argumentsNode.length < 1 ||
|
|
179
|
+
function callExpressionToCallStep(functionName, argumentsNode, resultVariable) {
|
|
180
|
+
if (argumentsNode.length < 1 ||
|
|
181
|
+
argumentsNode[0].type !== AST_NODE_TYPES.ObjectExpression) {
|
|
189
182
|
throw new WorkflowSyntaxError('Expected one object parameter', argumentsNode[0].loc);
|
|
190
183
|
}
|
|
191
184
|
const workflowArguments = convertObjectAsExpressionValues(argumentsNode[0]);
|
|
192
|
-
return new CallStepAST(functionName, workflowArguments);
|
|
185
|
+
return new CallStepAST(functionName, workflowArguments, resultVariable);
|
|
193
186
|
}
|
|
194
187
|
function createCallStep(argumentsNode, resultVariable) {
|
|
195
188
|
if (argumentsNode.length < 1) {
|
|
196
189
|
throw new WorkflowSyntaxError('The first argument must be a Function', argumentsNode[0].loc);
|
|
197
190
|
}
|
|
198
191
|
let functionName;
|
|
199
|
-
if (argumentsNode[0].type === Identifier) {
|
|
192
|
+
if (argumentsNode[0].type === AST_NODE_TYPES.Identifier) {
|
|
200
193
|
functionName = argumentsNode[0].name;
|
|
201
194
|
}
|
|
202
|
-
else if (argumentsNode[0].type === MemberExpression) {
|
|
195
|
+
else if (argumentsNode[0].type === AST_NODE_TYPES.MemberExpression) {
|
|
203
196
|
const memberExp = convertMemberExpression(argumentsNode[0]);
|
|
204
197
|
if (!isFullyQualifiedName(memberExp)) {
|
|
205
198
|
throw new WorkflowSyntaxError('Function name must be a fully-qualified name', argumentsNode[0].loc);
|
|
@@ -211,7 +204,7 @@ function createCallStep(argumentsNode, resultVariable) {
|
|
|
211
204
|
}
|
|
212
205
|
let args = {};
|
|
213
206
|
if (argumentsNode.length >= 2) {
|
|
214
|
-
if (argumentsNode[1].type !== ObjectExpression) {
|
|
207
|
+
if (argumentsNode[1].type !== AST_NODE_TYPES.ObjectExpression) {
|
|
215
208
|
throw new WorkflowSyntaxError('The second argument must be an object', argumentsNode[1].loc);
|
|
216
209
|
}
|
|
217
210
|
args = convertObjectAsExpressionValues(argumentsNode[1]);
|
|
@@ -219,12 +212,12 @@ function createCallStep(argumentsNode, resultVariable) {
|
|
|
219
212
|
return new CallStepAST(functionName, args, resultVariable);
|
|
220
213
|
}
|
|
221
214
|
function blockingFunctionCallStep(functionName, argumentNames, argumentsNode, resultName) {
|
|
222
|
-
const argumentExpressions = argumentsNode.map(convertExpression);
|
|
215
|
+
const argumentExpressions = throwIfSpread(argumentsNode).map(convertExpression);
|
|
223
216
|
const args = Object.fromEntries(argumentNames.flatMap((argName, i) => {
|
|
224
217
|
if (i >= argumentExpressions.length) {
|
|
225
218
|
return [];
|
|
226
219
|
}
|
|
227
|
-
else if (argumentsNode[i].type === Identifier &&
|
|
220
|
+
else if (argumentsNode[i].type === AST_NODE_TYPES.Identifier &&
|
|
228
221
|
argumentsNode[i].name === 'undefined') {
|
|
229
222
|
return [];
|
|
230
223
|
}
|
|
@@ -235,18 +228,17 @@ function blockingFunctionCallStep(functionName, argumentNames, argumentsNode, re
|
|
|
235
228
|
return new CallStepAST(functionName, args, resultName);
|
|
236
229
|
}
|
|
237
230
|
function callExpressionToParallelStep(node, ctx) {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
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"`);
|
|
242
234
|
}
|
|
243
235
|
let steps = {};
|
|
244
236
|
if (node.arguments.length > 0) {
|
|
245
237
|
switch (node.arguments[0].type) {
|
|
246
|
-
case ArrayExpression:
|
|
238
|
+
case AST_NODE_TYPES.ArrayExpression:
|
|
247
239
|
steps = parseParallelBranches(node.arguments[0]);
|
|
248
240
|
break;
|
|
249
|
-
case ArrowFunctionExpression:
|
|
241
|
+
case AST_NODE_TYPES.ArrowFunctionExpression:
|
|
250
242
|
steps = parseParallelIteration(node.arguments[0], ctx);
|
|
251
243
|
break;
|
|
252
244
|
default:
|
|
@@ -265,18 +257,19 @@ function callExpressionToParallelStep(node, ctx) {
|
|
|
265
257
|
return new ParallelStepAST(steps, shared, concurrencyLimit, exceptionPolicy);
|
|
266
258
|
}
|
|
267
259
|
function parseParallelBranches(node) {
|
|
268
|
-
|
|
269
|
-
const nodeElements = node.elements;
|
|
270
|
-
const stepsArray = nodeElements.map((arg, idx) => {
|
|
260
|
+
const stepsArray = node.elements.map((arg, idx) => {
|
|
271
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
|
+
}
|
|
272
265
|
switch (arg.type) {
|
|
273
|
-
case Identifier:
|
|
266
|
+
case AST_NODE_TYPES.Identifier:
|
|
274
267
|
return [branchName, new StepsStepAST([new CallStepAST(arg.name)])];
|
|
275
|
-
case ArrowFunctionExpression:
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
];
|
|
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, {}))];
|
|
280
273
|
default:
|
|
281
274
|
throw new WorkflowSyntaxError('Argument should be a function call of type () => void', arg.loc);
|
|
282
275
|
}
|
|
@@ -284,15 +277,15 @@ function parseParallelBranches(node) {
|
|
|
284
277
|
return Object.fromEntries(stepsArray);
|
|
285
278
|
}
|
|
286
279
|
function parseParallelIteration(node, ctx) {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
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) {
|
|
290
283
|
throw new WorkflowSyntaxError('The parallel function body must be a single for...of statement', node.body.loc);
|
|
291
284
|
}
|
|
292
285
|
return forOfStatementToForStep(node.body.body[0], ctx);
|
|
293
286
|
}
|
|
294
287
|
function parseParallelOptions(node) {
|
|
295
|
-
if (node.type !== ObjectExpression) {
|
|
288
|
+
if (node.type !== AST_NODE_TYPES.ObjectExpression) {
|
|
296
289
|
throw new WorkflowSyntaxError('The second parameter must be an object', node.loc);
|
|
297
290
|
}
|
|
298
291
|
const parallelOptions = convertObjectExpression(node);
|
|
@@ -325,56 +318,45 @@ function parseParallelOptions(node) {
|
|
|
325
318
|
};
|
|
326
319
|
}
|
|
327
320
|
function generalExpressionToAssignStep(node) {
|
|
328
|
-
return new AssignStepAST([['', convertExpression(node)]]);
|
|
321
|
+
return new AssignStepAST([['__temp', convertExpression(node)]]);
|
|
329
322
|
}
|
|
330
323
|
function returnStatementToReturnStep(node) {
|
|
331
|
-
assertType(node, ReturnStatement);
|
|
332
324
|
const value = node.argument ? convertExpression(node.argument) : undefined;
|
|
333
325
|
return new ReturnStepAST(value);
|
|
334
326
|
}
|
|
335
327
|
function throwStatementToRaiseStep(node) {
|
|
336
|
-
assertType(node, ThrowStatement);
|
|
337
328
|
return new RaiseStepAST(convertExpression(node.argument));
|
|
338
329
|
}
|
|
339
330
|
function ifStatementToSwitchStep(node, ctx) {
|
|
340
|
-
assertType(node, IfStatement);
|
|
341
331
|
return new SwitchStepAST(flattenIfBranches(node, ctx));
|
|
342
332
|
}
|
|
343
333
|
function flattenIfBranches(ifStatement, ctx) {
|
|
344
|
-
assertType(ifStatement, IfStatement);
|
|
345
|
-
assertType(ifStatement.consequent, BlockStatement);
|
|
346
334
|
const branches = [
|
|
347
335
|
{
|
|
348
336
|
condition: convertExpression(ifStatement.test),
|
|
349
|
-
steps:
|
|
337
|
+
steps: parseStatement(ifStatement.consequent, ctx),
|
|
350
338
|
},
|
|
351
339
|
];
|
|
352
340
|
if (ifStatement.alternate) {
|
|
353
|
-
if (ifStatement.alternate.type ===
|
|
354
|
-
branches.push({
|
|
355
|
-
condition: new PrimitiveExpression(true),
|
|
356
|
-
steps: parseBlockStatement(ifStatement.alternate, ctx),
|
|
357
|
-
});
|
|
358
|
-
}
|
|
359
|
-
else if (ifStatement.alternate.type === IfStatement) {
|
|
341
|
+
if (ifStatement.alternate.type === AST_NODE_TYPES.IfStatement) {
|
|
360
342
|
branches.push(...flattenIfBranches(ifStatement.alternate, ctx));
|
|
361
343
|
}
|
|
362
344
|
else {
|
|
363
|
-
|
|
345
|
+
branches.push({
|
|
346
|
+
condition: new PrimitiveExpression(true),
|
|
347
|
+
steps: parseStatement(ifStatement.alternate, ctx),
|
|
348
|
+
});
|
|
364
349
|
}
|
|
365
350
|
}
|
|
366
351
|
return branches;
|
|
367
352
|
}
|
|
368
353
|
function switchStatementToSteps(node, ctx) {
|
|
369
|
-
assertType(node, SwitchStatement);
|
|
370
354
|
const endOfSwitch = new JumpTargetAST();
|
|
371
355
|
const switchCtx = Object.assign({}, ctx, { breakTarget: endOfSwitch.label });
|
|
372
356
|
const steps = [];
|
|
373
357
|
const branches = [];
|
|
374
358
|
const discriminant = convertExpression(node.discriminant);
|
|
375
|
-
|
|
376
|
-
cases.forEach((caseNode) => {
|
|
377
|
-
assertType(caseNode, SwitchCase);
|
|
359
|
+
node.cases.forEach((caseNode) => {
|
|
378
360
|
let condition;
|
|
379
361
|
if (caseNode.test) {
|
|
380
362
|
const test = convertExpression(caseNode.test);
|
|
@@ -384,8 +366,7 @@ function switchStatementToSteps(node, ctx) {
|
|
|
384
366
|
condition = new PrimitiveExpression(true);
|
|
385
367
|
}
|
|
386
368
|
const jumpTarget = new JumpTargetAST();
|
|
387
|
-
const
|
|
388
|
-
const body = transformAST(consequent.flatMap((x) => parseStep(x, switchCtx)));
|
|
369
|
+
const body = transformAST(caseNode.consequent.flatMap((x) => parseStatement(x, switchCtx)));
|
|
389
370
|
steps.push(jumpTarget);
|
|
390
371
|
steps.push(...body);
|
|
391
372
|
branches.push({
|
|
@@ -399,18 +380,16 @@ function switchStatementToSteps(node, ctx) {
|
|
|
399
380
|
return steps;
|
|
400
381
|
}
|
|
401
382
|
function forOfStatementToForStep(node, ctx) {
|
|
402
|
-
assertType(node, ForOfStatement);
|
|
403
|
-
assertType(node.body, BlockStatement);
|
|
404
383
|
const bodyCtx = Object.assign({}, ctx, {
|
|
405
384
|
continueTarget: undefined,
|
|
406
385
|
breakTarget: undefined,
|
|
407
386
|
});
|
|
408
|
-
const steps =
|
|
387
|
+
const steps = parseStatement(node.body, bodyCtx);
|
|
409
388
|
let loopVariableName;
|
|
410
|
-
if (node.left.type === Identifier) {
|
|
389
|
+
if (node.left.type === AST_NODE_TYPES.Identifier) {
|
|
411
390
|
loopVariableName = node.left.name;
|
|
412
391
|
}
|
|
413
|
-
else if (node.left.type === VariableDeclaration) {
|
|
392
|
+
else if (node.left.type === AST_NODE_TYPES.VariableDeclaration) {
|
|
414
393
|
if (node.left.declarations.length !== 1) {
|
|
415
394
|
throw new WorkflowSyntaxError('Only one variable can be declared here', node.left.loc);
|
|
416
395
|
}
|
|
@@ -418,7 +397,9 @@ function forOfStatementToForStep(node, ctx) {
|
|
|
418
397
|
if (declaration.init !== null) {
|
|
419
398
|
throw new WorkflowSyntaxError('Initial value not allowed', declaration.init.loc);
|
|
420
399
|
}
|
|
421
|
-
|
|
400
|
+
if (declaration.id.type !== AST_NODE_TYPES.Identifier) {
|
|
401
|
+
throw new WorkflowSyntaxError(`Expected identifier, got ${declaration.id.type}`, declaration.id.loc);
|
|
402
|
+
}
|
|
422
403
|
loopVariableName = declaration.id.name;
|
|
423
404
|
}
|
|
424
405
|
else {
|
|
@@ -437,15 +418,14 @@ function forOfStatementToForStep(node, ctx) {
|
|
|
437
418
|
return new ForStepAST(steps, loopVariableName, listExpression);
|
|
438
419
|
}
|
|
439
420
|
function whileStatementSteps(node, ctx) {
|
|
440
|
-
assertType(node, WhileStatement);
|
|
441
421
|
const startOfLoop = new JumpTargetAST();
|
|
442
422
|
const endOfLoop = new JumpTargetAST();
|
|
443
423
|
const ctx2 = Object.assign({}, ctx, {
|
|
444
424
|
continueTarget: startOfLoop.label,
|
|
445
425
|
breakTarget: endOfLoop.label,
|
|
446
426
|
});
|
|
447
|
-
const
|
|
448
|
-
steps
|
|
427
|
+
const postSteps = [new NextStepAST(startOfLoop.label)];
|
|
428
|
+
const steps = parseStatement(node.body, ctx2, postSteps);
|
|
449
429
|
return [
|
|
450
430
|
startOfLoop,
|
|
451
431
|
new SwitchStepAST([
|
|
@@ -458,7 +438,6 @@ function whileStatementSteps(node, ctx) {
|
|
|
458
438
|
];
|
|
459
439
|
}
|
|
460
440
|
function doWhileStatementSteps(node, ctx) {
|
|
461
|
-
assertType(node, DoWhileStatement);
|
|
462
441
|
const startOfLoop = new JumpTargetAST();
|
|
463
442
|
const endOfLoop = new JumpTargetAST();
|
|
464
443
|
const ctx2 = Object.assign({}, ctx, {
|
|
@@ -466,7 +445,7 @@ function doWhileStatementSteps(node, ctx) {
|
|
|
466
445
|
breakTarget: endOfLoop.label,
|
|
467
446
|
});
|
|
468
447
|
const steps = [startOfLoop];
|
|
469
|
-
steps.push(...
|
|
448
|
+
steps.push(...parseStatement(node.body, ctx2));
|
|
470
449
|
steps.push(new SwitchStepAST([
|
|
471
450
|
{
|
|
472
451
|
condition: convertExpression(node.test),
|
|
@@ -478,10 +457,8 @@ function doWhileStatementSteps(node, ctx) {
|
|
|
478
457
|
return steps;
|
|
479
458
|
}
|
|
480
459
|
function breakStatementToNextStep(node, ctx) {
|
|
481
|
-
assertType(node, BreakStatement);
|
|
482
460
|
let target;
|
|
483
461
|
if (node.label) {
|
|
484
|
-
assertType(node.label, Identifier);
|
|
485
462
|
target = node.label.name;
|
|
486
463
|
}
|
|
487
464
|
else if (ctx.breakTarget) {
|
|
@@ -493,10 +470,8 @@ function breakStatementToNextStep(node, ctx) {
|
|
|
493
470
|
return new NextStepAST(target);
|
|
494
471
|
}
|
|
495
472
|
function continueStatementToNextStep(node, ctx) {
|
|
496
|
-
assertType(node, ContinueStatement);
|
|
497
473
|
let target;
|
|
498
474
|
if (node.label) {
|
|
499
|
-
assertType(node.label, Identifier);
|
|
500
475
|
target = node.label.name;
|
|
501
476
|
}
|
|
502
477
|
else if (ctx.continueTarget) {
|
|
@@ -508,14 +483,18 @@ function continueStatementToNextStep(node, ctx) {
|
|
|
508
483
|
return new NextStepAST(target);
|
|
509
484
|
}
|
|
510
485
|
function tryStatementToTryStep(node, ctx) {
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
const exceptSteps = parseBlockStatement(node.handler.body, ctx);
|
|
486
|
+
const steps = parseStatement(node.block, ctx);
|
|
487
|
+
let exceptSteps = [];
|
|
514
488
|
let errorVariable = undefined;
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
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
|
+
}
|
|
519
498
|
}
|
|
520
499
|
if (node.finalizer !== null) {
|
|
521
500
|
// TODO
|
|
@@ -524,11 +503,9 @@ function tryStatementToTryStep(node, ctx) {
|
|
|
524
503
|
return new TryStepAST(steps, exceptSteps, undefined, errorVariable);
|
|
525
504
|
}
|
|
526
505
|
function labeledStep(node, ctx) {
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
steps[0] = stepWithLabel(steps[0], node.label.name);
|
|
531
|
-
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);
|
|
532
509
|
}
|
|
533
510
|
return steps;
|
|
534
511
|
}
|
|
@@ -7,7 +7,7 @@ import { WorkflowStepAST } from '../ast/steps.js';
|
|
|
7
7
|
*/
|
|
8
8
|
export declare function transformAST(steps: WorkflowStepAST[]): WorkflowStepAST[];
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* Merge a next step to the previous step.
|
|
11
11
|
*
|
|
12
12
|
* For example, transforms this:
|
|
13
13
|
*
|
|
@@ -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;
|
|
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
|
-
|
|
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
|
}
|
|
@@ -124,7 +125,7 @@ function parseRetryPolicyNumber(record, keyName) {
|
|
|
124
125
|
return primitiveValue;
|
|
125
126
|
}
|
|
126
127
|
/**
|
|
127
|
-
*
|
|
128
|
+
* Merge a next step to the previous step.
|
|
128
129
|
*
|
|
129
130
|
* For example, transforms this:
|
|
130
131
|
*
|
|
@@ -142,9 +143,29 @@ function parseRetryPolicyNumber(record, keyName) {
|
|
|
142
143
|
* next: target1
|
|
143
144
|
*/
|
|
144
145
|
export function flattenPlainNextConditions(steps) {
|
|
145
|
-
return steps.
|
|
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));
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
acc.push(step);
|
|
164
|
+
}
|
|
165
|
+
return acc;
|
|
166
|
+
}, []);
|
|
146
167
|
}
|
|
147
|
-
function
|
|
168
|
+
function flattenNextToCondition(step) {
|
|
148
169
|
const transformedBranches = step.branches.map((cond) => {
|
|
149
170
|
if (!cond.next && cond.steps.length === 1 && cond.steps[0].tag === 'next') {
|
|
150
171
|
const nextStep = cond.steps[0];
|
|
@@ -270,7 +291,7 @@ function transformExpressionsAssign(step, transform) {
|
|
|
270
291
|
newSteps.push(...steps2);
|
|
271
292
|
return [name, ex2];
|
|
272
293
|
});
|
|
273
|
-
newSteps.push(new AssignStepAST(newAssignments, step.label));
|
|
294
|
+
newSteps.push(new AssignStepAST(newAssignments, step.next, step.label));
|
|
274
295
|
return newSteps;
|
|
275
296
|
}
|
|
276
297
|
else {
|