ts2workflows 0.8.0 → 0.10.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/README.md +0 -4
- package/dist/ast/expressions.d.ts +9 -0
- package/dist/ast/expressions.d.ts.map +1 -1
- package/dist/ast/expressions.js +43 -19
- package/dist/ast/steps.d.ts +32 -9
- package/dist/ast/steps.d.ts.map +1 -1
- package/dist/ast/steps.js +108 -23
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +4 -0
- package/dist/transpiler/expressions.d.ts +4 -4
- package/dist/transpiler/expressions.d.ts.map +1 -1
- package/dist/transpiler/expressions.js +65 -68
- package/dist/transpiler/index.d.ts.map +1 -1
- package/dist/transpiler/index.js +10 -4
- package/dist/transpiler/statements.d.ts +4 -3
- package/dist/transpiler/statements.d.ts.map +1 -1
- package/dist/transpiler/statements.js +520 -126
- package/dist/transpiler/transformations.d.ts +0 -6
- package/dist/transpiler/transformations.d.ts.map +1 -1
- package/dist/transpiler/transformations.js +102 -154
- package/dist/utils.d.ts +1 -5
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +3 -16
- package/language_reference.md +120 -61
- package/package.json +8 -4
package/dist/errors.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// WorkflowSyntaxError is thrown when the input contains a syntax error.
|
|
2
|
+
// The error is in user's input.
|
|
1
3
|
export class WorkflowSyntaxError extends Error {
|
|
2
4
|
location;
|
|
3
5
|
constructor(message, location) {
|
|
@@ -5,6 +7,8 @@ export class WorkflowSyntaxError extends Error {
|
|
|
5
7
|
this.location = location;
|
|
6
8
|
}
|
|
7
9
|
}
|
|
10
|
+
// InternalTranspilingError is thrown when ts2workflow ends up in an unexpected state.
|
|
11
|
+
// The error is in ts2workflow.
|
|
8
12
|
export class InternalTranspilingError extends Error {
|
|
9
13
|
constructor(message) {
|
|
10
14
|
super(`Internal error: ${message}`);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { TSESTree } from '@typescript-eslint/typescript-estree';
|
|
2
|
-
import { Expression, Primitive } from '../ast/expressions.js';
|
|
2
|
+
import { Expression, MemberExpression, Primitive, VariableReferenceExpression } from '../ast/expressions.js';
|
|
3
3
|
export declare function convertExpression(instance: TSESTree.Expression): Expression;
|
|
4
4
|
export declare function convertObjectExpression(node: TSESTree.ObjectExpression): Record<string, Primitive | Expression>;
|
|
5
5
|
export declare function convertObjectAsExpressionValues(node: TSESTree.ObjectExpression): Record<string, Expression>;
|
|
6
6
|
export declare function convertMemberExpression(node: TSESTree.MemberExpression): Expression;
|
|
7
|
-
export declare function
|
|
8
|
-
export declare function
|
|
7
|
+
export declare function isIntrinsic(calleeName: string): boolean;
|
|
8
|
+
export declare function isIntrinsicStatment(calleeName: string): boolean;
|
|
9
9
|
export declare function throwIfSpread<T extends TSESTree.Expression | TSESTree.Property | TSESTree.SpreadElement | null>(nodes: T[]): Exclude<T, TSESTree.SpreadElement>[];
|
|
10
|
-
export declare function
|
|
10
|
+
export declare function convertVariableNameExpression(instance: TSESTree.Expression): VariableReferenceExpression | MemberExpression;
|
|
11
11
|
//# sourceMappingURL=expressions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expressions.d.ts","sourceRoot":"","sources":["../../src/transpiler/expressions.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"expressions.d.ts","sourceRoot":"","sources":["../../src/transpiler/expressions.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAkB,MAAM,sCAAsC,CAAA;AAC/E,OAAO,EAGL,UAAU,EAEV,gBAAgB,EAChB,SAAS,EAGT,2BAA2B,EAI5B,MAAM,uBAAuB,CAAA;AAG9B,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,GAAG,UAAU,CAiE3E;AAcD,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,QAAQ,CAAC,gBAAgB,GAC9B,MAAM,CAAC,MAAM,EAAE,SAAS,GAAG,UAAU,CAAC,CAgCxC;AAED,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,QAAQ,CAAC,gBAAgB,GAC9B,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAG5B;AAwJD,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,QAAQ,CAAC,gBAAgB,GAC9B,UAAU,CAcZ;AA0JD,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAGvD;AAED,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAG/D;AAoDD,wBAAgB,aAAa,CAC3B,CAAC,SACG,QAAQ,CAAC,UAAU,GACnB,QAAQ,CAAC,QAAQ,GACjB,QAAQ,CAAC,aAAa,GACtB,IAAI,EACR,KAAK,EAAE,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,QAAQ,CAAC,aAAa,CAAC,EAAE,CAgBlD;AAED,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,QAAQ,CAAC,UAAU,GAC5B,2BAA2B,GAAG,gBAAgB,CAchD"}
|
|
@@ -1,69 +1,26 @@
|
|
|
1
|
+
import * as R from 'ramda';
|
|
1
2
|
import { AST_NODE_TYPES } from '@typescript-eslint/typescript-estree';
|
|
2
|
-
import { BinaryExpression, FunctionInvocationExpression, MemberExpression, PrimitiveExpression, UnaryExpression, VariableReferenceExpression,
|
|
3
|
+
import { BinaryExpression, FunctionInvocationExpression, MemberExpression, PrimitiveExpression, UnaryExpression, VariableReferenceExpression, asExpression, isFullyQualifiedName, nullEx, } from '../ast/expressions.js';
|
|
3
4
|
import { InternalTranspilingError, WorkflowSyntaxError } from '../errors.js';
|
|
4
|
-
import { mapRecordValues } from '../utils.js';
|
|
5
5
|
export function convertExpression(instance) {
|
|
6
|
-
const expOrPrimitive = convertExpressionOrPrimitive(instance);
|
|
7
|
-
if (isExpression(expOrPrimitive)) {
|
|
8
|
-
return expOrPrimitive;
|
|
9
|
-
}
|
|
10
|
-
else {
|
|
11
|
-
return new PrimitiveExpression(expOrPrimitive);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
export function convertObjectExpression(node) {
|
|
15
|
-
return Object.fromEntries(throwIfSpread(node.properties).map(({ key, value }) => {
|
|
16
|
-
let keyPrimitive;
|
|
17
|
-
if (key.type === AST_NODE_TYPES.Identifier) {
|
|
18
|
-
keyPrimitive = key.name;
|
|
19
|
-
}
|
|
20
|
-
else if (key.type === AST_NODE_TYPES.Literal) {
|
|
21
|
-
if (typeof key.value === 'string') {
|
|
22
|
-
keyPrimitive = key.value;
|
|
23
|
-
}
|
|
24
|
-
else {
|
|
25
|
-
throw new WorkflowSyntaxError(`Map keys must be identifiers or strings, encountered: ${typeof key.value}`, key.loc);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
else {
|
|
29
|
-
throw new WorkflowSyntaxError(`Not implemented object key type: ${key.type}`, key.loc);
|
|
30
|
-
}
|
|
31
|
-
if (value.type === AST_NODE_TYPES.AssignmentPattern ||
|
|
32
|
-
value.type === AST_NODE_TYPES.TSEmptyBodyFunctionExpression) {
|
|
33
|
-
throw new WorkflowSyntaxError('Value not supported', value.loc);
|
|
34
|
-
}
|
|
35
|
-
return [keyPrimitive, convertExpressionOrPrimitive(value)];
|
|
36
|
-
}));
|
|
37
|
-
}
|
|
38
|
-
export function convertObjectAsExpressionValues(node) {
|
|
39
|
-
// Convert Primitive values to PrimitiveExpressions
|
|
40
|
-
return mapRecordValues(convertObjectExpression(node), asExpression);
|
|
41
|
-
}
|
|
42
|
-
function convertExpressionOrPrimitive(instance) {
|
|
43
6
|
switch (instance.type) {
|
|
44
7
|
case AST_NODE_TYPES.ArrayExpression:
|
|
45
|
-
return convertArrayExpression(instance);
|
|
8
|
+
return asExpression(convertArrayExpression(instance));
|
|
46
9
|
case AST_NODE_TYPES.ObjectExpression:
|
|
47
|
-
return convertObjectExpression(instance);
|
|
10
|
+
return asExpression(convertObjectExpression(instance));
|
|
48
11
|
case AST_NODE_TYPES.Literal:
|
|
49
12
|
if (instance.value instanceof RegExp) {
|
|
50
13
|
throw new WorkflowSyntaxError('RegExp is not supported', instance.loc);
|
|
51
14
|
}
|
|
52
15
|
if (typeof instance.value === 'bigint') {
|
|
53
|
-
throw new WorkflowSyntaxError('BigInt
|
|
16
|
+
throw new WorkflowSyntaxError('BigInt is not supported', instance.loc);
|
|
54
17
|
}
|
|
55
|
-
return instance.value;
|
|
18
|
+
return new PrimitiveExpression(instance.value);
|
|
56
19
|
case AST_NODE_TYPES.TemplateLiteral:
|
|
57
20
|
return convertTemplateLiteralToExpression(instance);
|
|
58
21
|
case AST_NODE_TYPES.Identifier:
|
|
59
22
|
if (instance.name === 'null' || instance.name === 'undefined') {
|
|
60
|
-
return
|
|
61
|
-
}
|
|
62
|
-
else if (instance.name === 'True' || instance.name === 'TRUE') {
|
|
63
|
-
return true;
|
|
64
|
-
}
|
|
65
|
-
else if (instance.name === 'False' || instance.name === 'FALSE') {
|
|
66
|
-
return false;
|
|
23
|
+
return nullEx;
|
|
67
24
|
}
|
|
68
25
|
else {
|
|
69
26
|
return new VariableReferenceExpression(instance.name);
|
|
@@ -82,24 +39,59 @@ function convertExpressionOrPrimitive(instance) {
|
|
|
82
39
|
case AST_NODE_TYPES.ConditionalExpression:
|
|
83
40
|
return convertConditionalExpression(instance);
|
|
84
41
|
case AST_NODE_TYPES.TSAsExpression:
|
|
85
|
-
return
|
|
42
|
+
return convertExpression(instance.expression);
|
|
86
43
|
case AST_NODE_TYPES.TSNonNullExpression:
|
|
87
|
-
return
|
|
44
|
+
return convertExpression(instance.expression);
|
|
88
45
|
case AST_NODE_TYPES.AwaitExpression:
|
|
89
|
-
return
|
|
46
|
+
return convertExpression(instance.argument);
|
|
90
47
|
case AST_NODE_TYPES.TSInstantiationExpression:
|
|
91
|
-
return
|
|
48
|
+
return convertExpression(instance.expression);
|
|
92
49
|
default:
|
|
93
50
|
throw new WorkflowSyntaxError(`Not implemented expression type: ${instance.type}`, instance.loc);
|
|
94
51
|
}
|
|
95
52
|
}
|
|
53
|
+
function convertExpressionOrPrimitive(instance) {
|
|
54
|
+
const ex = convertExpression(instance);
|
|
55
|
+
if (ex.expressionType === 'primitive') {
|
|
56
|
+
return ex.value;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
return ex;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export function convertObjectExpression(node) {
|
|
63
|
+
return Object.fromEntries(throwIfSpread(node.properties).map(({ key, value }) => {
|
|
64
|
+
let keyPrimitive;
|
|
65
|
+
if (key.type === AST_NODE_TYPES.Identifier) {
|
|
66
|
+
keyPrimitive = key.name;
|
|
67
|
+
}
|
|
68
|
+
else if (key.type === AST_NODE_TYPES.Literal) {
|
|
69
|
+
if (typeof key.value === 'string') {
|
|
70
|
+
keyPrimitive = key.value;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
throw new WorkflowSyntaxError(`Map keys must be identifiers or strings, encountered: ${typeof key.value}`, key.loc);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
throw new WorkflowSyntaxError(`Not implemented object key type: ${key.type}`, key.loc);
|
|
78
|
+
}
|
|
79
|
+
if (value.type === AST_NODE_TYPES.AssignmentPattern ||
|
|
80
|
+
value.type === AST_NODE_TYPES.TSEmptyBodyFunctionExpression) {
|
|
81
|
+
throw new WorkflowSyntaxError('Value not supported', value.loc);
|
|
82
|
+
}
|
|
83
|
+
return [keyPrimitive, convertExpressionOrPrimitive(value)];
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
86
|
+
export function convertObjectAsExpressionValues(node) {
|
|
87
|
+
// Convert Primitive values to PrimitiveExpressions
|
|
88
|
+
return R.map(asExpression, convertObjectExpression(node));
|
|
89
|
+
}
|
|
96
90
|
function convertArrayExpression(instance) {
|
|
97
|
-
return throwIfSpread(instance.elements).map((e) => e === null
|
|
98
|
-
? new PrimitiveExpression(null)
|
|
99
|
-
: convertExpressionOrPrimitive(e));
|
|
91
|
+
return throwIfSpread(instance.elements).map((e) => e === null ? nullEx : convertExpressionOrPrimitive(e));
|
|
100
92
|
}
|
|
101
93
|
function convertBinaryExpression(instance) {
|
|
102
|
-
// Special case for nullish coalescing
|
|
94
|
+
// Special case for nullish coalescing because the result is a function call
|
|
103
95
|
// expression, not a binary expression
|
|
104
96
|
if (instance.operator === '??') {
|
|
105
97
|
return nullishCoalescingExpression(instance.left, instance.right);
|
|
@@ -189,7 +181,7 @@ function convertUnaryExpression(instance) {
|
|
|
189
181
|
}
|
|
190
182
|
}
|
|
191
183
|
function convertTypeOfExpression(value) {
|
|
192
|
-
// Note for future
|
|
184
|
+
// Note for future refactoring: evalute value only once (in case it has side effects)
|
|
193
185
|
return new FunctionInvocationExpression('text.replace_all_regex', [
|
|
194
186
|
new FunctionInvocationExpression('text.replace_all_regex', [
|
|
195
187
|
new FunctionInvocationExpression('get_type', [value]),
|
|
@@ -209,7 +201,7 @@ export function convertMemberExpression(node) {
|
|
|
209
201
|
}
|
|
210
202
|
function convertChainExpression(node) {
|
|
211
203
|
const properties = chainExpressionToFlatArray(node.expression);
|
|
212
|
-
const args =
|
|
204
|
+
const args = optionalChainToMapGetArguments(properties);
|
|
213
205
|
return new FunctionInvocationExpression('map.get', args);
|
|
214
206
|
}
|
|
215
207
|
function chainExpressionToFlatArray(node) {
|
|
@@ -234,7 +226,7 @@ function chainExpressionToFlatArray(node) {
|
|
|
234
226
|
];
|
|
235
227
|
}
|
|
236
228
|
}
|
|
237
|
-
function
|
|
229
|
+
function optionalChainToMapGetArguments(properties) {
|
|
238
230
|
if (properties.length <= 0) {
|
|
239
231
|
// this shouldn't happen
|
|
240
232
|
return [];
|
|
@@ -298,7 +290,7 @@ function convertCallExpression(node) {
|
|
|
298
290
|
const calleeExpression = convertExpression(node.callee);
|
|
299
291
|
if (isFullyQualifiedName(calleeExpression)) {
|
|
300
292
|
const calleeName = calleeExpression.toString();
|
|
301
|
-
if (
|
|
293
|
+
if (isIntrinsic(calleeName)) {
|
|
302
294
|
let msg;
|
|
303
295
|
if (calleeName === 'call_step') {
|
|
304
296
|
msg =
|
|
@@ -316,11 +308,11 @@ function convertCallExpression(node) {
|
|
|
316
308
|
throw new WorkflowSyntaxError('Callee should be a qualified name', node.loc);
|
|
317
309
|
}
|
|
318
310
|
}
|
|
319
|
-
export function
|
|
320
|
-
const
|
|
321
|
-
return
|
|
311
|
+
export function isIntrinsic(calleeName) {
|
|
312
|
+
const intrinsics = ['parallel', 'retry_policy', 'call_step'];
|
|
313
|
+
return intrinsics.includes(calleeName);
|
|
322
314
|
}
|
|
323
|
-
export function
|
|
315
|
+
export function isIntrinsicStatment(calleeName) {
|
|
324
316
|
const statementNames = ['parallel', 'retry_policy'];
|
|
325
317
|
return statementNames.includes(calleeName);
|
|
326
318
|
}
|
|
@@ -368,6 +360,11 @@ export function throwIfSpread(nodes) {
|
|
|
368
360
|
const argumentExpressions = nodes.filter((x) => x?.type !== AST_NODE_TYPES.SpreadElement);
|
|
369
361
|
return argumentExpressions;
|
|
370
362
|
}
|
|
371
|
-
export function
|
|
372
|
-
|
|
363
|
+
export function convertVariableNameExpression(instance) {
|
|
364
|
+
const ex = convertExpression(instance);
|
|
365
|
+
if (ex.expressionType !== 'variableReference' &&
|
|
366
|
+
ex.expressionType !== 'member') {
|
|
367
|
+
throw new WorkflowSyntaxError('The left-hand side of an assignment must be a variable or member expression', instance.loc);
|
|
368
|
+
}
|
|
369
|
+
return ex;
|
|
373
370
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transpiler/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transpiler/index.ts"],"names":[],"mappings":"AAcA,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,MAAM,EAClB,YAAY,CAAC,EAAE,MAAM,GACpB,MAAM,CAkBR"}
|
package/dist/transpiler/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { SubworkflowAST } from '../ast/steps.js';
|
|
|
4
4
|
import { WorkflowSyntaxError } from '../errors.js';
|
|
5
5
|
import { generateStepNames } from '../ast/stepnames.js';
|
|
6
6
|
import { parseStatement } from './statements.js';
|
|
7
|
+
import { transformAST } from './transformations.js';
|
|
7
8
|
export function transpile(code, inputFile, tsconfigPath) {
|
|
8
9
|
const parserOptions = {
|
|
9
10
|
jsDocParsingMode: 'none',
|
|
@@ -51,8 +52,15 @@ function parseTopLevelStatement(node) {
|
|
|
51
52
|
}
|
|
52
53
|
}
|
|
53
54
|
function parseSubworkflows(node) {
|
|
54
|
-
const
|
|
55
|
-
const
|
|
55
|
+
const workflowParams = parseWorkflowParams(node.params);
|
|
56
|
+
const steps = transformAST(parseStatement(node.body, {}));
|
|
57
|
+
if (steps.length === 0) {
|
|
58
|
+
throw new WorkflowSyntaxError('Empty subworkflow body is not allowed on GCP Workflows', node.body.loc);
|
|
59
|
+
}
|
|
60
|
+
return new SubworkflowAST(node.id.name, steps, workflowParams);
|
|
61
|
+
}
|
|
62
|
+
function parseWorkflowParams(nodeParams) {
|
|
63
|
+
return nodeParams.map((param) => {
|
|
56
64
|
switch (param.type) {
|
|
57
65
|
case AST_NODE_TYPES.Identifier:
|
|
58
66
|
if (param.optional) {
|
|
@@ -67,8 +75,6 @@ function parseSubworkflows(node) {
|
|
|
67
75
|
throw new WorkflowSyntaxError('Function parameter must be an identifier or an assignment', param.loc);
|
|
68
76
|
}
|
|
69
77
|
});
|
|
70
|
-
const steps = parseStatement(node.body, {});
|
|
71
|
-
return new SubworkflowAST(node.id.name, steps, workflowParams);
|
|
72
78
|
}
|
|
73
79
|
function parseSubworkflowDefaultArgument(param) {
|
|
74
80
|
if (param.left.type !== AST_NODE_TYPES.Identifier) {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { TSESTree } from '@typescript-eslint/typescript-estree';
|
|
2
2
|
import { StepName, WorkflowStepAST } from '../ast/steps.js';
|
|
3
3
|
export interface ParsingContext {
|
|
4
|
-
breakTarget?: StepName;
|
|
5
|
-
continueTarget?: StepName;
|
|
4
|
+
readonly breakTarget?: StepName;
|
|
5
|
+
readonly continueTarget?: StepName;
|
|
6
|
+
readonly parallelNestingLevel?: number;
|
|
6
7
|
finalizerTargets?: StepName[];
|
|
7
8
|
}
|
|
8
|
-
export declare function parseStatement(node: TSESTree.Statement, ctx: ParsingContext
|
|
9
|
+
export declare function parseStatement(node: TSESTree.Statement, ctx: ParsingContext): WorkflowStepAST[];
|
|
9
10
|
//# sourceMappingURL=statements.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"statements.d.ts","sourceRoot":"","sources":["../../src/transpiler/statements.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"statements.d.ts","sourceRoot":"","sources":["../../src/transpiler/statements.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,QAAQ,EAAE,MAAM,sCAAsC,CAAA;AAC/E,OAAO,EAWL,QAAQ,EAOR,eAAe,EAChB,MAAM,iBAAiB,CAAA;AAkCxB,MAAM,WAAW,cAAc;IAE7B,QAAQ,CAAC,WAAW,CAAC,EAAE,QAAQ,CAAA;IAE/B,QAAQ,CAAC,cAAc,CAAC,EAAE,QAAQ,CAAA;IAGlC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAKtC,gBAAgB,CAAC,EAAE,QAAQ,EAAE,CAAA;CAC9B;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,QAAQ,CAAC,SAAS,EACxB,GAAG,EAAE,cAAc,GAClB,eAAe,EAAE,CAEnB"}
|