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.
@@ -40,6 +40,12 @@ It is not possible to construct a bytes object expect by calling a function that
40
40
 
41
41
  In addition to the literal `null`, the Typescript `undefined` value is also treated as `null` in Workflows YAML.
42
42
 
43
+ ### Implicit type conversions
44
+
45
+ Expressions that combine variables with operators such as `+`, `>`, `==` perform implict type conversions according to the [rules listed on GCP Workflows documentation](https://cloud.google.com/workflows/docs/reference/syntax/datatypes#implicit-conversions). For example, applying `+` to a string and a number concatenates the values into a string.
46
+
47
+ ⚠️ Checking if a variable is null or not must be done by an explicit comparison: `if (var != null) {...}`. Relying in an implicit conversion, such as `if (var) {...}`, results in a TypeError at runtime.
48
+
43
49
  ## Expressions
44
50
 
45
51
  Most Typescript expressions work as expected.
@@ -56,7 +62,7 @@ name === 'Bean'
56
62
  sys.get_env('GOOGLE_CLOUD_PROJECT_ID')
57
63
  ```
58
64
 
59
- Operators:
65
+ ## Operators
60
66
 
61
67
  | Operator | Description |
62
68
  | ------------ | -------------------------------------------- |
@@ -71,11 +77,59 @@ Operators:
71
77
  | &&, \|\|, ! | logical operators |
72
78
  | in | check if a property is present in an object |
73
79
  | ?? | nullish coalescing |
80
+ | ?. | optional chaining |
81
+ | ? : | conditional operator |
74
82
 
75
83
  The [precendence order of operators](https://cloud.google.com/workflows/docs/reference/syntax/datatypes#order-operations) is the same as in GCP Workflows.
76
84
 
77
85
  See [expression in GCP Workflows](https://cloud.google.com/workflows/docs/reference/syntax/expressions) for more information.
78
86
 
87
+ ### Conditional (ternary) operator
88
+
89
+ The expression
90
+
91
+ ```javascript
92
+ x > 0 ? 'positive' : 'not positive'
93
+ ```
94
+
95
+ is converted to an [if() expression](https://cloud.google.com/workflows/docs/reference/stdlib/expression-helpers#conditional_functions):
96
+
97
+ ```yaml
98
+ ${if(x > 0, "positive", "not positive")}
99
+ ```
100
+
101
+ ⚠️ Note that Workflows always evaluates both expression branches unlike Typescript which evaluates only the branch that gets executed.
102
+
103
+ ### Nullish coalescing operator
104
+
105
+ The expression
106
+
107
+ ```javascript
108
+ x ?? 'default value'
109
+ ```
110
+
111
+ is converted to a [default() expression](https://cloud.google.com/workflows/docs/reference/stdlib/expression-helpers#conditional_functions):
112
+
113
+ ```yaml
114
+ ${default(x, "default value")}
115
+ ```
116
+
117
+ ⚠️ Note that Workflows always evaluates the right-hand side expression unlike Typescript which evaluates the right-hand side only if the left-hand side is `null` or `undefined`.
118
+
119
+ ### Optional chaining
120
+
121
+ The optional chaining expression
122
+
123
+ ```javascript
124
+ data.user?.name
125
+ ```
126
+
127
+ is converted to a [map.get() expression](https://cloud.google.com/workflows/docs/reference/stdlib/map/get):
128
+
129
+ ```yaml
130
+ ${map.get(data, ["user", "name"])}
131
+ ```
132
+
79
133
  ## Template literals
80
134
 
81
135
  Template literals are strings that support string interpolation. For example, `Hello ${name}`.
@@ -145,7 +199,7 @@ is converted to an [assign step](https://cloud.google.com/workflows/docs/referen
145
199
  - projectId: ${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}
146
200
  ```
147
201
 
148
- This syntax can be used to call [standard library functions](https://cloud.google.com/workflows/docs/reference/stdlib/overview), subworkflows or connectors.
202
+ This syntax can be used to call [standard library functions](https://cloud.google.com/workflows/docs/reference/stdlib/overview), subworkflows or connectors. Note that Javascript runtime functions (such as `fetch()`, `console.error()` or `new XMLHttpRequest()`) are not available on Workflows.
149
203
 
150
204
  GCP Workflows language has two ways of calling functions and subworkflows: as expression in an [assign step](https://cloud.google.com/workflows/docs/reference/syntax/variables#assign-step) or as [call step](https://cloud.google.com/workflows/docs/reference/syntax/calls). They can mostly be used interchangeably. However, [blocking calls](https://cloud.google.com/workflows/docs/reference/syntax/expressions#blocking-calls) must be made as call steps. The transpiler tries to automatically output a call step when necessary.
151
205
 
@@ -175,7 +229,7 @@ main:
175
229
  severity: INFO
176
230
  ```
177
231
 
178
- Some Workflows standard library functions have names that are reserved keywords in Typescript. Those functions must be called with alternative names in ts2workflows source code:
232
+ Some Workflows standard library functions have names that are reserved keywords in Typescript. Those functions must be called with alternative syntax in ts2workflows source code:
179
233
 
180
234
  - To generate a call to `default()` in Workflows code, use the nullish coalescing operator `??`.
181
235
  - To generete a call to `if()` in Workflows code, use the ternary operator `a ? b : c`.
@@ -307,38 +361,6 @@ steps:
307
361
  return: ${b}
308
362
  ```
309
363
 
310
- ## Conditional (ternary) operator
311
-
312
- The expression
313
-
314
- ```javascript
315
- x > 0 ? 'positive' : 'not positive'
316
- ```
317
-
318
- is converted to an [if() expression](https://cloud.google.com/workflows/docs/reference/stdlib/expression-helpers#conditional_functions):
319
-
320
- ```yaml
321
- ${if(x > 0, "positive", "not positive")}
322
- ```
323
-
324
- ⚠️ Note that Workflows always evaluates both expression branches unlike Typescript which evaluates only the branch that gets executed.
325
-
326
- ## Nullish coalescing operator
327
-
328
- The expression
329
-
330
- ```javascript
331
- x ?? 'default value'
332
- ```
333
-
334
- is converted to an [default() expression](https://cloud.google.com/workflows/docs/reference/stdlib/expression-helpers#conditional_functions):
335
-
336
- ```yaml
337
- ${default(x, "default value")}
338
- ```
339
-
340
- ⚠️ Note that Workflows always evaluates the right-hand side expression unlike Typescript which evaluates the right-hand side only if the left-hand side is `null` or `undefined`.
341
-
342
364
  ## Loops
343
365
 
344
366
  The fragment
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts2workflows",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Transpile Typescript code to GCP Workflows programs",
5
5
  "homepage": "https://github.com/aajanki/ts2workflows",
6
6
  "repository": {
@@ -19,7 +19,25 @@
19
19
  "build:functionmetadata": "tsx scripts/generateBlockingFunctionMetadata.ts",
20
20
  "lint": "eslint src test scripts",
21
21
  "format": "prettier . --write",
22
- "test": "mocha"
22
+ "test": "mocha",
23
+ "prepare": "husky"
24
+ },
25
+ "lint-staged": {
26
+ "src/**/*.ts": [
27
+ "prettier --write",
28
+ "eslint"
29
+ ],
30
+ "test/**/*.ts": [
31
+ "prettier --write",
32
+ "eslint"
33
+ ],
34
+ "scripts/**/*.ts": [
35
+ "prettier --write",
36
+ "eslint"
37
+ ],
38
+ "*.md": [
39
+ "prettier --write"
40
+ ]
23
41
  },
24
42
  "bin": "./dist/cli.js",
25
43
  "files": [
@@ -46,6 +64,8 @@
46
64
  "@typescript-eslint/parser": "^8.0.0",
47
65
  "chai": "^5.1.1",
48
66
  "eslint": "^9.10.0",
67
+ "husky": "^9.1.6",
68
+ "lint-staged": "^15.2.10",
49
69
  "mocha": "^10.4.0",
50
70
  "prettier": "^3.2.5",
51
71
  "rimraf": "^5.0.10",
@@ -54,7 +74,6 @@
54
74
  },
55
75
  "dependencies": {
56
76
  "@typescript-eslint/typescript-estree": "^8.0.0",
57
- "@typescript-eslint/utils": "^8.0.0",
58
77
  "commander": "^12.1.0",
59
78
  "typescript": "^5.0.0",
60
79
  "yaml": "^2.4.2"
@@ -0,0 +1,116 @@
1
+ export {}
2
+
3
+ /// <reference no-default-lib="true"/>
4
+
5
+ declare global {
6
+ // Minimal definition of Symbol.iterator required by the for-of statement
7
+ interface SymbolConstructor {
8
+ readonly iterator: unique symbol
9
+ }
10
+
11
+ var Symbol: SymbolConstructor
12
+
13
+ interface Iterator<T> {}
14
+
15
+ interface Iterable<T> {
16
+ [Symbol.iterator](): Iterator<T>
17
+ }
18
+
19
+ interface IterableIterator<T> extends Iterator<T> {
20
+ [Symbol.iterator](): IterableIterator<T>
21
+ }
22
+
23
+ interface Array<T> {
24
+ // Array member access
25
+ [n: number]: T
26
+
27
+ // Arrays can be iterated by the for-of statement
28
+ [Symbol.iterator](): IterableIterator<T>
29
+ }
30
+
31
+ interface ArrayConstructor {
32
+ isArray(arg: any): arg is any[]
33
+ }
34
+
35
+ var Array: ArrayConstructor
36
+
37
+ interface Boolean {}
38
+ interface CallableFunction {}
39
+ interface Function {}
40
+ interface IArguments {}
41
+ interface NewableFunction {}
42
+ interface Number {}
43
+ interface Object {}
44
+ interface RegExp {}
45
+ interface String {}
46
+
47
+ /**
48
+ * Utility types
49
+ * Copied from lib.es5.d.ts
50
+ */
51
+
52
+ /**
53
+ * Make all properties in T optional
54
+ */
55
+ type Partial<T> = {
56
+ [P in keyof T]?: T[P]
57
+ }
58
+
59
+ /**
60
+ * Make all properties in T required
61
+ */
62
+ type Required<T> = {
63
+ [P in keyof T]-?: T[P]
64
+ }
65
+
66
+ /**
67
+ * Make all properties in T readonly
68
+ */
69
+ type Readonly<T> = {
70
+ readonly [P in keyof T]: T[P]
71
+ }
72
+
73
+ /**
74
+ * From T, pick a set of properties whose keys are in the union K
75
+ */
76
+ type Pick<T, K extends keyof T> = {
77
+ [P in K]: T[P]
78
+ }
79
+
80
+ /**
81
+ * Construct a type with a set of properties K of type T
82
+ */
83
+
84
+ type Record<K extends keyof any, T> = {
85
+ [P in K]: T
86
+ }
87
+
88
+ /**
89
+ * Obtain the return type of a function type
90
+ */
91
+ type ReturnType<T extends (...args: any) => any> = T extends (
92
+ ...args: any
93
+ ) => infer R
94
+ ? R
95
+ : any
96
+
97
+ /**
98
+ * Exclude from T those types that are assignable to U
99
+ */
100
+ type Exclude<T, U> = T extends U ? never : T
101
+
102
+ /**
103
+ * Extract from T those types that are assignable to U
104
+ */
105
+ type Extract<T, U> = T extends U ? T : never
106
+
107
+ /**
108
+ * Construct a type with the properties of T except for those in type K.
109
+ */
110
+ type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>
111
+
112
+ /**
113
+ * Exclude null and undefined from T
114
+ */
115
+ type NonNullable<T> = T & {}
116
+ }
@@ -161,9 +161,15 @@ export declare namespace http {
161
161
  }
162
162
 
163
163
  export declare namespace json {
164
- function decode(data: bytes | string): object
164
+ function decode(data: bytes | string): unknown
165
165
  function encode(
166
- data: string | number | boolean | unknown[] | Record<string, unknown>,
166
+ data:
167
+ | string
168
+ | number
169
+ | boolean
170
+ | unknown[]
171
+ | Record<string, unknown>
172
+ | null,
167
173
  indent?:
168
174
  | boolean
169
175
  | {
@@ -172,7 +178,13 @@ export declare namespace json {
172
178
  },
173
179
  ): bytes
174
180
  function encode_to_string(
175
- data: string | number | boolean | unknown[] | Record<string, unknown>,
181
+ data:
182
+ | string
183
+ | number
184
+ | boolean
185
+ | unknown[]
186
+ | Record<string, unknown>
187
+ | null,
176
188
  indent?:
177
189
  | boolean
178
190
  | {
@@ -192,7 +204,7 @@ export declare namespace map {
192
204
  export function get<T, K extends string | string[]>(
193
205
  map: Record<string, T>,
194
206
  keys: K,
195
- ): K extends string ? T : unknown
207
+ ): K extends string ? T | null : unknown
196
208
  export function merge<T, U>(
197
209
  first: Record<string, T>,
198
210
  second: Record<string, U>,
@@ -245,7 +257,7 @@ export declare namespace text {
245
257
  index: number
246
258
  match: string
247
259
  }[]
248
- function match_regexp(source: string, regexp: string): boolean
260
+ function match_regex(source: string, regexp: string): boolean
249
261
  function replace_all(source: string, substr: string, repl: string): string
250
262
  function replace_all_regex(
251
263
  source: string,
@@ -1,7 +0,0 @@
1
- export declare function assertType(node: {
2
- type: string;
3
- }, expectedType: string): void;
4
- export declare function assertOneOfManyTypes(node: {
5
- type: string;
6
- }, expectAnyOfTheseTypes: string[]): void;
7
- //# sourceMappingURL=asserts.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"asserts.d.ts","sourceRoot":"","sources":["../../src/transpiler/asserts.ts"],"names":[],"mappings":"AAEA,wBAAgB,UAAU,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAM7E;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EACtB,qBAAqB,EAAE,MAAM,EAAE,GAC9B,IAAI,CAMN"}
@@ -1,11 +0,0 @@
1
- import { InternalTranspilingError } from '../errors.js';
2
- export function assertType(node, expectedType) {
3
- if (node?.type !== expectedType) {
4
- throw new InternalTranspilingError(`Expected ${expectedType}, got ${node?.type}`);
5
- }
6
- }
7
- export function assertOneOfManyTypes(node, expectAnyOfTheseTypes) {
8
- if (!expectAnyOfTheseTypes.includes(node?.type)) {
9
- throw new InternalTranspilingError(`Expected ${expectAnyOfTheseTypes.join(' or ')}, got ${node?.type}`);
10
- }
11
- }