ts2workflows 0.1.0 → 0.2.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/transpiler/index.d.ts.map +1 -1
- package/dist/transpiler/index.js +4 -3
- package/dist/transpiler/statements.d.ts.map +1 -1
- package/dist/transpiler/statements.js +3 -2
- package/dist/transpiler/transformations.d.ts.map +1 -1
- package/dist/transpiler/transformations.js +48 -11
- package/language_reference.md +24 -9
- package/package.json +1 -1
- package/types/workflowslib.d.ts +16 -13
|
@@ -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":"AA0BA,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAa9C"}
|
package/dist/transpiler/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { WorkflowSyntaxError } from '../errors.js';
|
|
|
7
7
|
import { generateStepNames } from '../ast/stepnames.js';
|
|
8
8
|
import { assertType } from './asserts.js';
|
|
9
9
|
import { parseBlockStatement } from './statements.js';
|
|
10
|
-
const { AssignmentPattern, ExportNamedDeclaration, FunctionDeclaration, Identifier, ImportDeclaration, ImportDefaultSpecifier, ImportNamespaceSpecifier, Literal, Program, TSTypeAliasDeclaration, TSInterfaceDeclaration, } = AST_NODE_TYPES;
|
|
10
|
+
const { AssignmentPattern, ExportNamedDeclaration, FunctionDeclaration, Identifier, ImportDeclaration, ImportDefaultSpecifier, ImportNamespaceSpecifier, Literal, Program, TSDeclareFunction, TSTypeAliasDeclaration, TSInterfaceDeclaration, } = AST_NODE_TYPES;
|
|
11
11
|
export function transpile(code) {
|
|
12
12
|
const parserOptions = {
|
|
13
13
|
jsDocParsingMode: 'none',
|
|
@@ -40,10 +40,11 @@ function parseTopLevelStatement(node) {
|
|
|
40
40
|
}
|
|
41
41
|
case TSInterfaceDeclaration:
|
|
42
42
|
case TSTypeAliasDeclaration:
|
|
43
|
-
|
|
43
|
+
case TSDeclareFunction:
|
|
44
|
+
// Ignore "type", "interface" and "declare function" at the top-level
|
|
44
45
|
return [];
|
|
45
46
|
default:
|
|
46
|
-
throw new WorkflowSyntaxError(`Only function
|
|
47
|
+
throw new WorkflowSyntaxError(`Only function definitions, imports and type aliases allowed at the top level, encountered ${node?.type}`, node?.loc);
|
|
47
48
|
}
|
|
48
49
|
}
|
|
49
50
|
function parseSubworkflows(node) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"statements.d.ts","sourceRoot":"","sources":["../../src/transpiler/statements.ts"],"names":[],"mappings":"AAEA,OAAO,EASL,QAAQ,EAOR,eAAe,EAEhB,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"statements.d.ts","sourceRoot":"","sources":["../../src/transpiler/statements.ts"],"names":[],"mappings":"AAEA,OAAO,EASL,QAAQ,EAOR,eAAe,EAEhB,MAAM,iBAAiB,CAAA;AAyDxB,MAAM,WAAW,cAAc;IAE7B,WAAW,CAAC,EAAE,QAAQ,CAAA;IAEtB,cAAc,CAAC,EAAE,QAAQ,CAAA;CAC1B;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,GAAG,EACT,GAAG,EAAE,cAAc,GAClB,eAAe,EAAE,CAKnB"}
|
|
@@ -8,7 +8,7 @@ import { transformAST } from './transformations.js';
|
|
|
8
8
|
import { assertType } from './asserts.js';
|
|
9
9
|
import { convertExpression, convertMemberExpression, convertObjectExpression, convertObjectAsExpressionValues, } from './expressions.js';
|
|
10
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;
|
|
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
12
|
export function parseBlockStatement(node, ctx) {
|
|
13
13
|
assertType(node, BlockStatement);
|
|
14
14
|
const body = node.body;
|
|
@@ -58,7 +58,8 @@ function parseStep(node, ctx) {
|
|
|
58
58
|
throw new WorkflowSyntaxError('Functions must be defined at the top level of a source file', node.loc);
|
|
59
59
|
case TSInterfaceDeclaration:
|
|
60
60
|
case TSTypeAliasDeclaration:
|
|
61
|
-
|
|
61
|
+
case TSDeclareFunction:
|
|
62
|
+
// Ignore "type", "interface" and "declare function"
|
|
62
63
|
return [];
|
|
63
64
|
default:
|
|
64
65
|
throw new WorkflowSyntaxError(`TODO: encountered unsupported type: ${node.type}`, node.loc);
|
|
@@ -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;
|
|
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,CAEnB"}
|
|
@@ -3,6 +3,7 @@ import { InternalTranspilingError } from '../errors.js';
|
|
|
3
3
|
import { isRecord } from '../utils.js';
|
|
4
4
|
import { BinaryExpression, FunctionInvocationExpression, MemberExpression, PrimitiveExpression, UnaryExpression, VariableReferenceExpression, expressionToLiteralValueOrLiteralExpression, isExpression, isFullyQualifiedName, isLiteral, } from '../ast/expressions.js';
|
|
5
5
|
import { blockingFunctions } from './generated/functionMetadata.js';
|
|
6
|
+
const Unmodified = Symbol();
|
|
6
7
|
/**
|
|
7
8
|
* Performs various transformations on the AST.
|
|
8
9
|
*
|
|
@@ -10,7 +11,7 @@ import { blockingFunctions } from './generated/functionMetadata.js';
|
|
|
10
11
|
* called on each nesting level separately.
|
|
11
12
|
*/
|
|
12
13
|
export function transformAST(steps) {
|
|
13
|
-
return blockingCallsAsCallSteps(flattenPlainNextConditions(combineRetryBlocksToTry(mergeAssignSteps(mapLiteralsAsAssignSteps(steps)))));
|
|
14
|
+
return blockingCallsAsCallSteps(runtimeFunctionImplementation(flattenPlainNextConditions(combineRetryBlocksToTry(mergeAssignSteps(mapLiteralsAsAssignSteps(steps))))));
|
|
14
15
|
}
|
|
15
16
|
/**
|
|
16
17
|
* Merge consecutive assign steps into one assign step
|
|
@@ -196,7 +197,6 @@ function createTempVariableGenerator() {
|
|
|
196
197
|
const generator = () => `__temp${i++}`;
|
|
197
198
|
return generator;
|
|
198
199
|
}
|
|
199
|
-
const Unmodified = Symbol();
|
|
200
200
|
function replaceBlockingCalls(expression, generateName) {
|
|
201
201
|
function replaceBlockingFunctionInvocations(ex) {
|
|
202
202
|
if (ex.expressionType === 'functionInvocation') {
|
|
@@ -406,13 +406,14 @@ function mapLiteralsAsAssignSteps(steps) {
|
|
|
406
406
|
return value.expressionType === 'primitive';
|
|
407
407
|
});
|
|
408
408
|
}
|
|
409
|
-
else if (current.tag === 'raise') {
|
|
409
|
+
else if (current.tag === 'raise' || current.tag === 'return') {
|
|
410
410
|
needsTransformation =
|
|
411
|
-
|
|
411
|
+
current.value !== undefined &&
|
|
412
|
+
includesExtractableMapLiteral(current.value, true);
|
|
412
413
|
}
|
|
413
414
|
else if (current.tag === 'call') {
|
|
414
415
|
if (current.args) {
|
|
415
|
-
needsTransformation = Object.values(current.args).some((ex) =>
|
|
416
|
+
needsTransformation = Object.values(current.args).some((ex) => includesExtractableMapLiteral(ex, true));
|
|
416
417
|
}
|
|
417
418
|
}
|
|
418
419
|
if (needsTransformation) {
|
|
@@ -425,20 +426,34 @@ function mapLiteralsAsAssignSteps(steps) {
|
|
|
425
426
|
return acc;
|
|
426
427
|
}, []);
|
|
427
428
|
}
|
|
428
|
-
|
|
429
|
+
// Return true if the string representation of ex would include {}
|
|
430
|
+
function includesExtractableMapLiteral(ex, parentAllowsMaps) {
|
|
429
431
|
switch (ex.expressionType) {
|
|
430
432
|
case 'primitive':
|
|
431
|
-
|
|
433
|
+
if (isRecord(ex.value)) {
|
|
434
|
+
return (!parentAllowsMaps ||
|
|
435
|
+
Object.values(ex.value).some((x) => isExpression(x) &&
|
|
436
|
+
includesExtractableMapLiteral(x, parentAllowsMaps)));
|
|
437
|
+
}
|
|
438
|
+
else if (Array.isArray(ex.value)) {
|
|
439
|
+
return ex.value.some((x) => isExpression(x) &&
|
|
440
|
+
includesExtractableMapLiteral(x, parentAllowsMaps));
|
|
441
|
+
}
|
|
442
|
+
else {
|
|
443
|
+
return false;
|
|
444
|
+
}
|
|
432
445
|
case 'binary':
|
|
433
|
-
return
|
|
446
|
+
return (includesExtractableMapLiteral(ex.left, parentAllowsMaps) ||
|
|
447
|
+
includesExtractableMapLiteral(ex.right, parentAllowsMaps));
|
|
434
448
|
case 'variableReference':
|
|
435
449
|
return false;
|
|
436
450
|
case 'unary':
|
|
437
|
-
return
|
|
451
|
+
return includesExtractableMapLiteral(ex.value, parentAllowsMaps);
|
|
438
452
|
case 'functionInvocation':
|
|
439
|
-
return ex.arguments.some(
|
|
453
|
+
return ex.arguments.some((x) => includesExtractableMapLiteral(x, false));
|
|
440
454
|
case 'member':
|
|
441
|
-
return
|
|
455
|
+
return (includesExtractableMapLiteral(ex.object, false) ||
|
|
456
|
+
includesExtractableMapLiteral(ex.property, false));
|
|
442
457
|
}
|
|
443
458
|
}
|
|
444
459
|
function replaceMapLiterals(expression, generateName) {
|
|
@@ -459,3 +474,25 @@ function replaceMapLiterals(expression, generateName) {
|
|
|
459
474
|
assignSteps,
|
|
460
475
|
};
|
|
461
476
|
}
|
|
477
|
+
/**
|
|
478
|
+
* Replace `Array.isArray(x)` with `get_type(x) == "list"`
|
|
479
|
+
*/
|
|
480
|
+
function runtimeFunctionImplementation(steps) {
|
|
481
|
+
return steps.reduce((acc, current) => {
|
|
482
|
+
const transformedSteps = transformStepExpressions(current, (ex) => [
|
|
483
|
+
[],
|
|
484
|
+
transformExpression(ex, replaceIsArray),
|
|
485
|
+
]);
|
|
486
|
+
acc.push(...transformedSteps);
|
|
487
|
+
return acc;
|
|
488
|
+
}, []);
|
|
489
|
+
}
|
|
490
|
+
function replaceIsArray(ex) {
|
|
491
|
+
if (ex.expressionType === 'functionInvocation' &&
|
|
492
|
+
ex.functionName === 'Array.isArray') {
|
|
493
|
+
return new BinaryExpression(new FunctionInvocationExpression('get_type', ex.arguments), '==', new PrimitiveExpression('list'));
|
|
494
|
+
}
|
|
495
|
+
else {
|
|
496
|
+
return Unmodified;
|
|
497
|
+
}
|
|
498
|
+
}
|
package/language_reference.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
ts2workflow converts Typescript source code to GCP Workflows YAML syntax. Only a subset of Typescript language features are supported. This page documents supported Typescript features and shows examples of the generted Workflows YAML output.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Most functions provided by a Javascript runtime (`console.log()`, `setInterval()`, etc) are not available.
|
|
6
6
|
|
|
7
7
|
Type annotations are allowed. Type checking is done by the compiler but the types dont't affect the generated Workflows code.
|
|
8
8
|
|
|
@@ -22,7 +22,7 @@ Semicolon can be used as optional statement delimitter.
|
|
|
22
22
|
|
|
23
23
|
### Array type
|
|
24
24
|
|
|
25
|
-
⚠️ Arrays are not objects. In particular, methods like `
|
|
25
|
+
⚠️ Arrays are not objects. In particular, methods like `[].map()` and `[].concat()` are not available.
|
|
26
26
|
|
|
27
27
|
⚠️ Accessing out-of-bounds index will cause an IndexError at runtime unlike in Typescript where out-of-bounds access would return `undefined`.
|
|
28
28
|
|
|
@@ -689,7 +689,19 @@ function read_from_env() {
|
|
|
689
689
|
|
|
690
690
|
At the moment, type annotations are provided for some [connectors](https://cloud.google.com/workflows/docs/reference/googleapis) but not for all of them.
|
|
691
691
|
|
|
692
|
-
|
|
692
|
+
### Runtime functions
|
|
693
|
+
|
|
694
|
+
This section describes the few standard Javascript runtime functions that are available. Most are not.
|
|
695
|
+
|
|
696
|
+
### Array.isArray()
|
|
697
|
+
|
|
698
|
+
```typescript
|
|
699
|
+
Array.isArray(arg: any): arg is any[]
|
|
700
|
+
```
|
|
701
|
+
|
|
702
|
+
Gets converted to the comparison `get_type(arg) == "list"`. Unlike a direct call to `get_type()`, `Array.isArray()` allows the type inference to learn if `arg` is array or not.
|
|
703
|
+
|
|
704
|
+
## Language extension functions
|
|
693
705
|
|
|
694
706
|
ts2workflows provides some special functions for implementing features that are not directly supported by Typescript language features. The type annotations for these functions can be imported from ts2workflows/types/workflowslib:
|
|
695
707
|
|
|
@@ -701,15 +713,18 @@ import {
|
|
|
701
713
|
} from 'ts2workflows/types/workflowslib'
|
|
702
714
|
```
|
|
703
715
|
|
|
704
|
-
### call_step
|
|
716
|
+
### call_step()
|
|
705
717
|
|
|
706
718
|
```typescript
|
|
707
|
-
function call_step
|
|
719
|
+
function call_step<T, A extends any[]>(
|
|
720
|
+
func: (...args: A) => T,
|
|
721
|
+
arguments: Record<string, unknown>,
|
|
722
|
+
): T
|
|
708
723
|
```
|
|
709
724
|
|
|
710
725
|
The `call_step` function outputs a [call step](https://cloud.google.com/workflows/docs/reference/syntax/calls).
|
|
711
726
|
|
|
712
|
-
### parallel
|
|
727
|
+
### parallel()
|
|
713
728
|
|
|
714
729
|
```typescript
|
|
715
730
|
function parallel(
|
|
@@ -724,7 +739,7 @@ function parallel(
|
|
|
724
739
|
|
|
725
740
|
The `parallel` function executes code blocks in parallel (using [parallel step](https://cloud.google.com/workflows/docs/reference/syntax/parallel-steps)). See the previous sections covering parallel branches and iteration.
|
|
726
741
|
|
|
727
|
-
### retry_policy
|
|
742
|
+
### retry_policy()
|
|
728
743
|
|
|
729
744
|
```typescript
|
|
730
745
|
function retry_policy(
|
|
@@ -760,9 +775,9 @@ const var1 = 1 // This is a comment
|
|
|
760
775
|
|
|
761
776
|
ts2workflows supports only a subset of all Typescript language features. Some examples that are not (yet) supported by ts2workflows:
|
|
762
777
|
|
|
763
|
-
-
|
|
778
|
+
- Most functions provided by a Javascript runtime (`console.log()`, `setInterval()`, etc) are not available. Only the [GCP Workflows standard library functions](https://cloud.google.com/workflows/docs/reference/stdlib/overview) and [connectors](https://cloud.google.com/workflows/docs/reference/googleapis) are available.
|
|
764
779
|
- Classes (`class`) are not supported
|
|
765
|
-
- Arrays and maps are not objects. In particular, arrays don't have methods such as `
|
|
780
|
+
- Arrays and maps are not objects. In particular, arrays don't have methods such as `[].push()`, `[].map()`, etc.
|
|
766
781
|
- Functions (subworkflows) are not first-class objects. Functions can not be assigned to a variable or passed to other functions
|
|
767
782
|
- Update expressions (`x++` and similar) are not supported
|
|
768
783
|
- Destructuring (`[a, b] = func()`) is not supported
|
package/package.json
CHANGED
package/types/workflowslib.d.ts
CHANGED
|
@@ -188,16 +188,19 @@ export declare namespace list {
|
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
export declare namespace map {
|
|
191
|
-
function _delete<
|
|
192
|
-
export function get<
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
191
|
+
function _delete<T>(map: Record<string, T>, key: string): Record<string, T>
|
|
192
|
+
export function get<T, K extends string | string[]>(
|
|
193
|
+
map: Record<string, T>,
|
|
194
|
+
keys: K,
|
|
195
|
+
): K extends string ? T : unknown
|
|
196
|
+
export function merge<T, U>(
|
|
197
|
+
first: Record<string, T>,
|
|
198
|
+
second: Record<string, U>,
|
|
199
|
+
): Record<string, T | U>
|
|
200
|
+
export function merge_nested<T, U>(
|
|
201
|
+
first: Record<string, T>,
|
|
202
|
+
second: Record<string, U>,
|
|
203
|
+
): Record<string, T | U>
|
|
201
204
|
export { _delete as delete }
|
|
202
205
|
}
|
|
203
206
|
|
|
@@ -708,7 +711,7 @@ export declare function retry_policy(
|
|
|
708
711
|
},
|
|
709
712
|
): void
|
|
710
713
|
|
|
711
|
-
export declare function call_step(
|
|
712
|
-
func:
|
|
714
|
+
export declare function call_step<T, A extends any[]>(
|
|
715
|
+
func: (...args: A) => T,
|
|
713
716
|
arguments: Record<string, unknown>,
|
|
714
|
-
):
|
|
717
|
+
): T
|