ts2workflows 0.12.0 → 0.13.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/CHANGELOG.md ADDED
@@ -0,0 +1,117 @@
1
+ # ts2workflows changelog
2
+
3
+ ## Version 0.13.0 - 2025-10-12
4
+
5
+ Fixes:
6
+
7
+ - function identifiers (e.g. in call_step and parallel) are included in the `--link` output
8
+ - Improve type annotations of map.\* functions
9
+
10
+ ## Version 0.12.0 - 2025-08-30
11
+
12
+ New features:
13
+
14
+ - New command line option `--link` generates self-contained YAML files (all needed subworkflows in one file)
15
+ - Accepts Typescript's `satisfies` expression and `debugger` statement. They do not affect the YAML output.
16
+
17
+ Fixes:
18
+
19
+ - Empty body in an `if` statements generated invalid code
20
+ - In certain cases nested map literals generated invalid code
21
+ - Some expressions with many extractable sub-expressions (map literals, blocking calls) generated invalid code because a temporary variable was re-used incorrectly
22
+ - Empty statements are accepted at the top level
23
+ - Ignore extra arguments in blocking function calls in all cases. Previously, extra arguments were ignored in some cases but threw errors in other cases.
24
+ - Call expressions in optional chaining (`data?.getPerson()?.name`) now result in error. Previously, they were incorrectly treated as non-optional in the generated code.
25
+ - Fixed code generation for an object rest element nested in an array pattern: `const [{...rest}] = data`
26
+
27
+ ## Version 0.11.0 - 2025-06-28
28
+
29
+ Breaking changes:
30
+
31
+ - Requires Node 20 or newer and Typescript 5.4.0 or newer
32
+ - retry_policy() must be called inside a try block, not after
33
+ - Variable declarations with `var` are not supported, only `let` and `const`
34
+ - Step name numbering starts from 1 at the start of each subworkflow
35
+
36
+ Fixes:
37
+
38
+ - Type annotation fixes in workflowslib
39
+
40
+ ## Version 0.10.0 - 2025-04-28
41
+
42
+ - Accept binary expressions as properties in assignments: `a[i + 4] = 1` (regression in 0.9.0)
43
+ - Evaluate side-effects only once on the left-hand side in compound assignments: `x[f()] += 1`
44
+ - Fix calling `call_step()` on the right-hand side of a compound assignment: `x += call_step(sum, {a: 10, b: 11})`
45
+ - Output an error if a subworkflow is empty because empty body is not allowed on GCP
46
+
47
+ ## Version 0.9.0 - 2025-04-23
48
+
49
+ Breaking changes:
50
+
51
+ - `True`, `TRUE`, `False` and `FALSE` no longer are synonyms for `true` and `false`
52
+
53
+ New features:
54
+
55
+ - Array and object destructuring: `const [a, b] = getArray()`
56
+
57
+ Fixes:
58
+
59
+ - Fix a deployment error caused by the same temp variable name being used inside and outside of a parallel branch
60
+
61
+ ## Version 0.8.0 - 2025-03-03
62
+
63
+ - Multiple input files can be given on the command line
64
+ - Argument `--outdir` sets the output directory
65
+ - Argument `--project` defines the TSConfig location for the source files
66
+ - `--(no-)generated-file-comment`: optionally include a comment about the output file being generated
67
+ - `--version` prints the correct version number
68
+ - Accept instantiation expressions `func<TYPE>`
69
+
70
+ ## Version 0.7.0 - 2025-02-02
71
+
72
+ - `typeof` operator
73
+ - `null` is allowed as interpolated value in template literal `${null}`
74
+ - Accept `undefined` as a function argument default argument: `func(a: number | undefined = undefined)`
75
+ - Optional function arguments: `func(a?: number)`
76
+
77
+ ## Version 0.6.0 - 2025-01-09
78
+
79
+ Breaking changes:
80
+
81
+ - retry_policy() takes a plain policy function name instead of a {policy: ...} object
82
+
83
+ Fixes:
84
+
85
+ - The try statement supports a finally block
86
+ - Support empty body in a catch block
87
+ - retry_policy() parameter values can now be expressions in addition to number literals
88
+ - 0, "", false and null can now be used as subworkflow parameter default values
89
+ - Type annotation fixes
90
+
91
+ ## Version 0.5.0 - 2024-11-09
92
+
93
+ - Move nested map expressions to assign steps where necessary
94
+ - Array.isArray() is transformed correcly in nested expressions
95
+
96
+ ## Version 0.4.0 - 2024-11-05
97
+
98
+ - Optional chaining a?.b is converted to map.get(a, "b")
99
+ - Non-null assertions person!.name is accepted but ignored to the transpiler
100
+ - Merge a next step to a preceeding assign step
101
+ - Accept a single-statement body (body without braces {}) in if, while, etc
102
+ - Assign the result of call_step() to a member variable: obj.property = call_step()
103
+ - parallel() and retry_policy() special functions can only be used as statements
104
+ - Better error messages on RegExp, BigInt, spread syntax and other non-supported Javascript features
105
+
106
+ ## Version 0.3.0 - 2024-10-19
107
+
108
+ - Function invocations no longer generate invalid empty variable names
109
+ - Include more utility types: ReturnType, Partial, Required, etc.
110
+ - Type annotation fixes
111
+
112
+ ## Version 0.2.0 - 2024-10-09
113
+
114
+ - Reduce cases where maps are needlessly split off into assign statements
115
+ - Accept (but ignore) "declare function"
116
+ - Implemented Array.isArray()
117
+ - Fixes to type annotations
@@ -27,15 +27,19 @@ function findFunctionsRecursively(seen, typeChecker, node) {
27
27
  function findNestedFunctions(typeChecker, node) {
28
28
  const functionDeclarations = [];
29
29
  function visit(node) {
30
- if (ts.isCallExpression(node)) {
31
- const sig = typeChecker.getResolvedSignature(node);
32
- const decl = sig?.getDeclaration();
33
- if (decl && ts.isFunctionDeclaration(decl)) {
34
- functionDeclarations.push(decl);
35
- }
30
+ // isImportOrExportSpecifier() check ignores foo in "import { foo } from ..."
31
+ if (ts.isIdentifier(node) && !ts.isImportOrExportSpecifier(node.parent)) {
32
+ functionDeclarations.push(...functionDeclarationsForIdentifier(typeChecker, node));
36
33
  }
37
34
  ts.forEachChild(node, visit);
38
35
  }
39
36
  visit(node);
40
37
  return functionDeclarations;
41
38
  }
39
+ function functionDeclarationsForIdentifier(typeChecker, node) {
40
+ const symbol = typeChecker.getSymbolAtLocation(node);
41
+ const isAliased = symbol && symbol.flags & ts.SymbolFlags.Alias;
42
+ const symbol2 = isAliased ? typeChecker.getAliasedSymbol(symbol) : symbol;
43
+ const declarations = symbol2?.getDeclarations() ?? [];
44
+ return declarations.filter(ts.isFunctionDeclaration);
45
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts2workflows",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "Transpile Typescript code to GCP Workflows programs",
5
5
  "homepage": "https://github.com/aajanki/ts2workflows",
6
6
  "repository": {
@@ -48,6 +48,7 @@
48
48
  "types",
49
49
  "README.md",
50
50
  "language_reference.md",
51
+ "CHANGELOG.md",
51
52
  "LICENSE"
52
53
  ],
53
54
  "author": "Antti Ajanki",
@@ -77,13 +78,16 @@
77
78
  "rimraf": "^6.0.1",
78
79
  "source-map-support": "^0.5.21",
79
80
  "tsx": "^4.20.5",
81
+ "typescript": "^5.5.4",
80
82
  "typescript-eslint": "^8.0.0"
81
83
  },
84
+ "peerDependencies": {
85
+ "typescript": ">=5.5.4 <6.0.0"
86
+ },
82
87
  "dependencies": {
83
88
  "@typescript-eslint/typescript-estree": "^8.0.0",
84
89
  "commander": "^14.0.0",
85
- "ramda": "^0.31.3",
86
- "typescript": "^5.5.4",
90
+ "ramda": "^0.32.0",
87
91
  "yaml": "^2.4.2"
88
92
  }
89
93
  }
@@ -210,20 +210,33 @@ export declare namespace list {
210
210
  function prepend<T, U>(objs: T[], val: U): (T | U)[]
211
211
  }
212
212
 
213
+ // Typescript `object` is actually too liberal as it includes arrays. Workflows
214
+ // will throw an error if the input is an array.
213
215
  export declare namespace map {
214
- function _delete<T>(map: Record<string, T>, key: string): Record<string, T>
215
- // map.get() with a string key, returns a property value or null
216
- export function get<T>(map: Record<string, T>, keys: string): T | null
217
- // map.get() with string[] key or non-object lookup, the return type is unknown
218
- export function get(map: any, keys: string | string[]): WorkflowsValue
219
- export function merge<T, U>(
220
- first: Record<string, T>,
221
- second: Record<string, U>,
222
- ): Record<string, T | U>
223
- export function merge_nested<T, U>(
224
- first: Record<string, T>,
225
- second: Record<string, U>,
226
- ): Record<string, T | U>
216
+ // If K is a literal key of T, return the exact type.
217
+ // Otherwise the best we can do is to return a Record with
218
+ // any of T property values.
219
+ function _delete<T extends object, K extends string>(
220
+ map: T,
221
+ key: K,
222
+ ): K extends keyof T ? Omit<T, K> : Record<string, T[keyof T]>
223
+ // map.get() with a string key.
224
+ // If K is a literal key of T, this returns the exact type T[K].
225
+ // Otherwise returns less exact union of all T property types or null.
226
+ export function get<T extends object, K extends string>(
227
+ map: T,
228
+ keys: K,
229
+ ): K extends keyof T ? T[K] : T[keyof T] | null
230
+ // map.get() with string[] key, the return type is not inferred
231
+ export function get(map: object, keys: string[]): WorkflowsValue
232
+ export function merge<T extends object, U extends object>(
233
+ first: T,
234
+ second: U,
235
+ ): T & U
236
+ export function merge_nested<T extends object, U extends object>(
237
+ first: T,
238
+ second: U,
239
+ ): T & U
227
240
  export { _delete as delete }
228
241
  }
229
242