typenative 0.0.16 → 0.0.17
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 +15 -0
- package/README.md +135 -92
- package/bin/transpiler.js +692 -20
- package/package.json +8 -2
- package/types/typenative.d.ts +16 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,21 @@ All notable changes to TypeNative will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.0.17] - 2026-02-16
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Support for ternary expressions (`condition ? a : b`)
|
|
13
|
+
- Support for optional chaining (`obj?.prop`, `arr?.[i]`)
|
|
14
|
+
- Support for nullish coalescing (`??` operator)
|
|
15
|
+
- Support for type aliases (`type X = ...`)
|
|
16
|
+
- Support for type assertions (`expr as Type`)
|
|
17
|
+
- Support for optional properties (`prop?: Type` in interfaces/types)
|
|
18
|
+
- Support for default parameter values (e.g. `function(x = defaultValue)`)
|
|
19
|
+
- Support for enum declarations and member access (`enum X { ... }`, `X.Member`)
|
|
20
|
+
- Support for array methods: `map`, `filter`, `some`, `find`
|
|
21
|
+
- Support for chaining array methods (e.g. `arr.map(...).filter(...).join(...)`)
|
|
22
|
+
|
|
8
23
|
## [0.0.16] - 2025-02-15
|
|
9
24
|
|
|
10
25
|
### Added
|
package/README.md
CHANGED
|
@@ -11,99 +11,142 @@ Build native applications using Typescript.
|
|
|
11
11
|
|
|
12
12
|
- Write a file `test.ts` with content `console.log('Hello World!');` or any other message
|
|
13
13
|
- Run `npx typenative --source test.ts --script`
|
|
14
|
-
- See your message in the terminal
|
|
15
14
|
|
|
16
|
-
##
|
|
15
|
+
## Typescript Syntax Support
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
- Give your project a name
|
|
20
|
-
- Start writing code
|
|
17
|
+
TypeNative currently supports a focused subset of TypeScript syntax elements that are transpiled to Go code. The support is grouped by topic for easier scanning.
|
|
21
18
|
|
|
22
|
-
|
|
19
|
+
**Basic Types**
|
|
20
|
+
|
|
21
|
+
| Feature | Supported | Notes |
|
|
22
|
+
| -------------- | :-------: | ------------------------------------------------------------- |
|
|
23
|
+
| number | ✅ | Transpiled to `float64` |
|
|
24
|
+
| boolean | ✅ | Transpiled to `bool` |
|
|
25
|
+
| string | ✅ | |
|
|
26
|
+
| null | ✅ | |
|
|
27
|
+
| any | ✅ | Used for type inference |
|
|
28
|
+
| Nullable types | ✅ | `T \| null` / `T \| undefined` transpiled to Go pointer types |
|
|
29
|
+
|
|
30
|
+
**Variables & Objects**
|
|
31
|
+
|
|
32
|
+
| Feature | Supported | Notes |
|
|
33
|
+
| --------------------- | :-------: | -------------------------------- |
|
|
34
|
+
| Variable declarations | ✅ | `let` and `const` |
|
|
35
|
+
| Object literals | ✅ | Transpiled to Go struct literals |
|
|
36
|
+
|
|
37
|
+
**Operators**
|
|
38
|
+
|
|
39
|
+
| Feature | Supported | Notes |
|
|
40
|
+
| ------------------------ | :-------: | ------------------------------ |
|
|
41
|
+
| Arithmetic operators | ✅ | `+`, `-`, etc. |
|
|
42
|
+
| Comparison operators | ✅ | `==`, `!=`, `===`, `!==`, etc. |
|
|
43
|
+
| Logical operators | ✅ | `&&`, `\|\|` |
|
|
44
|
+
| Increment/Decrement | ✅ | `++`, `--` |
|
|
45
|
+
| Non-null assertion (`!`) | ✅ | Stripped during transpilation |
|
|
46
|
+
| Ternary expressions | ✅ | `condition ? a : b` |
|
|
47
|
+
| Nullish coalescing | ✅ | `??` operator |
|
|
48
|
+
| Optional chaining | ✅ | `obj?.prop`, `arr?.[i]` |
|
|
49
|
+
|
|
50
|
+
**Control Flow**
|
|
51
|
+
|
|
52
|
+
| Feature | Supported | Notes |
|
|
53
|
+
| ------------------ | :-------: | ---------------------------------- |
|
|
54
|
+
| If/Else statements | ✅ | Fully supported |
|
|
55
|
+
| Switch statements | ✅ | Case and default statements |
|
|
56
|
+
| For loops | ✅ | Standard `for` loops |
|
|
57
|
+
| For...of loops | ✅ | Iteration over arrays |
|
|
58
|
+
| While loops | ✅ | Transpiled to Go's `for` loops |
|
|
59
|
+
| Do...while loops | ✅ | Implemented with conditional break |
|
|
60
|
+
|
|
61
|
+
**Data Structures & Array Methods**
|
|
62
|
+
|
|
63
|
+
| Feature | Supported | Notes |
|
|
64
|
+
| -------------------------- | :-------: | ---------------------------------------------------------------- |
|
|
65
|
+
| Arrays | ✅ | Basic array operations |
|
|
66
|
+
| Array methods | ✅ | `push`, `join`, `slice` |
|
|
67
|
+
| Higher-order array methods | ✅ | `.map()`, `.filter()`, `.some()`, `.find()` |
|
|
68
|
+
| Method chaining | ✅ | Chaining array methods such as `.map(...).filter(...).join(...)` |
|
|
69
|
+
|
|
70
|
+
**Functions**
|
|
71
|
+
|
|
72
|
+
| Feature | Supported | Notes |
|
|
73
|
+
| ---------------------------- | :-------: | --------------------------------- |
|
|
74
|
+
| Function declarations | ✅ | Transpiled to Go functions |
|
|
75
|
+
| Arrow functions | ✅ | Transpiled to anonymous functions |
|
|
76
|
+
| Generics (functions/classes) | ✅ | Type parameters via Go generics |
|
|
77
|
+
| Default parameter values | ✅ | `function(x = defaultValue)` |
|
|
78
|
+
|
|
79
|
+
**Classes & Interfaces**
|
|
80
|
+
|
|
81
|
+
| Feature | Supported | Notes |
|
|
82
|
+
| ------------------- | :-------: | -------------------------------------------------------------- |
|
|
83
|
+
| Classes | ✅ | Transpiled to Go structs with constructor and receiver methods |
|
|
84
|
+
| Class inheritance | ✅ | `extends` via embedded structs, `super()` supported |
|
|
85
|
+
| Interfaces | ✅ | Transpiled to Go interfaces, supports `extends` |
|
|
86
|
+
| Optional properties | ✅ | `prop?: Type` in interfaces/types |
|
|
87
|
+
| Enums | ✅ | `enum` declarations and member access |
|
|
88
|
+
|
|
89
|
+
**Async & Timing**
|
|
90
|
+
|
|
91
|
+
| Feature | Supported | Notes |
|
|
92
|
+
| ----------- | :-------: | ----------------------------------------------------------------- |
|
|
93
|
+
| Async/Await | ✅ | `async` functions return Go channels, `await` reads from channels |
|
|
94
|
+
| Promises | ✅ | `new Promise` transpiled to channel + goroutine pattern |
|
|
95
|
+
| setTimeout | ✅ | Mapped to Go's `time.AfterFunc` |
|
|
96
|
+
|
|
97
|
+
**Built-in Functions & Utilities**
|
|
98
|
+
|
|
99
|
+
| Feature | Supported | Notes |
|
|
100
|
+
| --------------------- | :-------: | ----------------------------------------------------- |
|
|
101
|
+
| console.log | ✅ | Mapped to `fmt.Println` |
|
|
102
|
+
| console.time/timeEnd | ✅ | Performance measurement via `time.Now` / `time.Since` |
|
|
103
|
+
| assert | ✅ | Transpiled to `panic` on failure |
|
|
104
|
+
| parseInt / parseFloat | ✅ | Mapped to Go's `strconv` package |
|
|
105
|
+
|
|
106
|
+
**Math Methods**
|
|
107
|
+
|
|
108
|
+
| Feature | Supported | Notes |
|
|
109
|
+
| ------------------------- | :-------: | ------------------------------------------------- |
|
|
110
|
+
| Math.random | ✅ | Mapped to `rand.Float64()` |
|
|
111
|
+
| Math.floor / ceil / round | ✅ | Mapped to `math.Floor`, `math.Ceil`, `math.Round` |
|
|
112
|
+
| Math.abs / sqrt / pow | ✅ | Mapped to corresponding `math` functions |
|
|
113
|
+
| Math.min / max | ✅ | Mapped to `math.Min`, `math.Max` |
|
|
114
|
+
|
|
115
|
+
**String Methods**
|
|
116
|
+
|
|
117
|
+
| Feature | Supported | Notes |
|
|
118
|
+
| -------------------------- | :-------: | --------------------------------------------- |
|
|
119
|
+
| Template literals | ✅ | Backtick strings with `${expr}` interpolation |
|
|
120
|
+
| toUpperCase / toLowerCase | ✅ | Via `strings` package |
|
|
121
|
+
| trim / trimStart / trimEnd | ✅ | Via `strings` package |
|
|
122
|
+
| split / includes / indexOf | ✅ | Via `strings` package |
|
|
123
|
+
| startsWith / endsWith | ✅ | Via `strings` package |
|
|
124
|
+
| replace / replaceAll | ✅ | Via `strings` package |
|
|
125
|
+
| charAt / substring / slice | ✅ | Direct Go string indexing/slicing |
|
|
126
|
+
| concat / repeat | ✅ | String concatenation and `strings.Repeat` |
|
|
127
|
+
|
|
128
|
+
**Number / Object Methods**
|
|
129
|
+
|
|
130
|
+
| Feature | Supported | Notes |
|
|
131
|
+
| -------- | :-------: | ----------------------------------------------------- |
|
|
132
|
+
| toString | ✅ | Universal `toString()` via `fmt.Sprintf` for any type |
|
|
133
|
+
|
|
134
|
+
**RegExp**
|
|
135
|
+
|
|
136
|
+
| Feature | Supported | Notes |
|
|
137
|
+
| -------------- | :-------: | --------------------------------------------------- |
|
|
138
|
+
| Regex literals | ✅ | `/pattern/flags` transpiled to `regexp.MustCompile` |
|
|
139
|
+
| new RegExp() | ✅ | Constructor with optional flags |
|
|
140
|
+
| test() | ✅ | Mapped to `regexp.MatchString` |
|
|
141
|
+
| exec() | ✅ | Mapped to `regexp.FindStringSubmatch` |
|
|
142
|
+
|
|
143
|
+
**Unsupported / Roadmap**
|
|
144
|
+
|
|
145
|
+
| Feature | Supported | Notes |
|
|
146
|
+
| --------------------------- | :-------: | ------------------------------------------------ |
|
|
147
|
+
| Modules/Imports | ❌ | `import` / `export` declarations |
|
|
148
|
+
| Try/Catch | ❌ | Error handling |
|
|
149
|
+
| Map / Set | ❌ | Built-in collection types and their methods |
|
|
150
|
+
| Closures over mutable state | ❌ | Functions capturing and mutating outer variables |
|
|
23
151
|
|
|
24
|
-
TypeNative currently
|
|
25
|
-
|
|
26
|
-
| Feature | Supported | Notes |
|
|
27
|
-
| --------------------------- | :-------: | ----------------------------------------------------------------- |
|
|
28
|
-
| **Basic Types** | | |
|
|
29
|
-
| number | ✅ | Transpiled to `float64` |
|
|
30
|
-
| boolean | ✅ | Transpiled to `bool` |
|
|
31
|
-
| string | ✅ | |
|
|
32
|
-
| null | ✅ | |
|
|
33
|
-
| any | ✅ | Used for type inference |
|
|
34
|
-
| Nullable types | ✅ | `T \| null` / `T \| undefined` transpiled to Go pointer types |
|
|
35
|
-
| **Variables** | | |
|
|
36
|
-
| Variable declarations | ✅ | `let` and `const` |
|
|
37
|
-
| Object literals | ✅ | Transpiled to Go struct literals |
|
|
38
|
-
| **Operators** | | |
|
|
39
|
-
| Arithmetic operators | ✅ | `+`, `-`, etc. |
|
|
40
|
-
| Comparison operators | ✅ | `==`, `!=`, `===`, `!==`, etc. |
|
|
41
|
-
| Logical operators | ✅ | `&&`, `\|\|` |
|
|
42
|
-
| Increment/Decrement | ✅ | `++`, `--` |
|
|
43
|
-
| Non-null assertion (`!`) | ✅ | Stripped during transpilation |
|
|
44
|
-
| **Control Flow** | | |
|
|
45
|
-
| For loops | ✅ | Standard `for` loops |
|
|
46
|
-
| For...of loops | ✅ | Iteration over arrays |
|
|
47
|
-
| While loops | ✅ | Transpiled to Go's `for` loops |
|
|
48
|
-
| Do...while loops | ✅ | Implemented with conditional break |
|
|
49
|
-
| If/Else statements | ✅ | Fully supported |
|
|
50
|
-
| Switch statements | ✅ | Case and default statements |
|
|
51
|
-
| **Data Structures** | | |
|
|
52
|
-
| Arrays | ✅ | Basic array operations |
|
|
53
|
-
| Array methods | ✅ | `push`, `join`, `slice`, `toString` |
|
|
54
|
-
| **Functions** | | |
|
|
55
|
-
| Function declarations | ✅ | Transpiled to Go functions |
|
|
56
|
-
| Arrow functions | ✅ | Transpiled to anonymous functions |
|
|
57
|
-
| **Classes & Interfaces** | | |
|
|
58
|
-
| Classes | ✅ | Transpiled to Go structs with constructor and receiver methods |
|
|
59
|
-
| Class inheritance | ✅ | `extends` via embedded structs, `super()` supported |
|
|
60
|
-
| Interfaces | ✅ | Transpiled to Go interfaces, supports `extends` |
|
|
61
|
-
| Generics | ✅ | Type parameters on functions and classes via Go generics |
|
|
62
|
-
| **Async** | | |
|
|
63
|
-
| Async/Await | ✅ | `async` functions return Go channels, `await` reads from channels |
|
|
64
|
-
| Promises | ✅ | `new Promise` transpiled to channel + goroutine pattern |
|
|
65
|
-
| setTimeout | ✅ | Mapped to Go's `time.AfterFunc` |
|
|
66
|
-
| **Built-in Functions** | | |
|
|
67
|
-
| console.log | ✅ | Mapped to `fmt.Println` |
|
|
68
|
-
| console.time/timeEnd | ✅ | Performance measurement via `time.Now` / `time.Since` |
|
|
69
|
-
| assert | ✅ | Transpiled to `panic` on failure |
|
|
70
|
-
| parseInt / parseFloat | ✅ | Mapped to Go's `strconv` package |
|
|
71
|
-
| **Math Methods** | | |
|
|
72
|
-
| Math.random | ✅ | Mapped to `rand.Float64()` |
|
|
73
|
-
| Math.floor / ceil / round | ✅ | Mapped to `math.Floor`, `math.Ceil`, `math.Round` |
|
|
74
|
-
| Math.abs / sqrt / pow | ✅ | Mapped to corresponding `math` functions |
|
|
75
|
-
| Math.min / max | ✅ | Mapped to `math.Min`, `math.Max` |
|
|
76
|
-
| **String Methods** | | |
|
|
77
|
-
| toUpperCase / toLowerCase | ✅ | Via `strings` package |
|
|
78
|
-
| trim / trimStart / trimEnd | ✅ | Via `strings` package |
|
|
79
|
-
| split / includes / indexOf | ✅ | Via `strings` package |
|
|
80
|
-
| startsWith / endsWith | ✅ | Via `strings` package |
|
|
81
|
-
| replace / replaceAll | ✅ | Via `strings` package |
|
|
82
|
-
| charAt / substring / slice | ✅ | Direct Go string indexing/slicing |
|
|
83
|
-
| concat / repeat / toString | ✅ | String concatenation and `strings.Repeat` |
|
|
84
|
-
| **Number / Object Methods** | | |
|
|
85
|
-
| toString | ✅ | Universal `toString()` via `fmt.Sprintf` for any type |
|
|
86
|
-
| **RegExp** | | |
|
|
87
|
-
| Regex literals | ✅ | `/pattern/flags` transpiled to `regexp.MustCompile` |
|
|
88
|
-
| new RegExp() | ✅ | Constructor with optional flags |
|
|
89
|
-
| test() | ✅ | Mapped to `regexp.MatchString` |
|
|
90
|
-
| exec() | ✅ | Mapped to `regexp.FindStringSubmatch` |
|
|
91
|
-
| **Unsupported Features** | | |
|
|
92
|
-
| Modules/Imports | ❌ | `import` / `export` declarations |
|
|
93
|
-
| Try/Catch | ❌ | Error handling |
|
|
94
|
-
| Template literals | ❌ | Backtick strings with `${expr}` interpolation |
|
|
95
|
-
| Ternary expressions | ❌ | `condition ? a : b` |
|
|
96
|
-
| Optional chaining | ❌ | `obj?.prop`, `arr?.[i]` |
|
|
97
|
-
| Nullish coalescing | ❌ | `??` operator |
|
|
98
|
-
| Spread operator | ❌ | `[...iterable]`, `{...obj}` |
|
|
99
|
-
| Type aliases | ❌ | `type X = ...` |
|
|
100
|
-
| Type assertions | ❌ | `expr as Type` |
|
|
101
|
-
| Optional properties | ❌ | `prop?: Type` in interfaces/types |
|
|
102
|
-
| Default parameter values | ❌ | `function(x = defaultValue)` |
|
|
103
|
-
| Map / Set | ❌ | Built-in collection types and their methods |
|
|
104
|
-
| Higher-order array methods | ❌ | `.map()`, `.filter()`, `.some()`, `.find()` with callbacks |
|
|
105
|
-
| Method chaining | ❌ | `arr.map(...).filter(...).join(...)` |
|
|
106
|
-
| Enums | ❌ | `enum` declarations and member access |
|
|
107
|
-
| Closures over mutable state | ❌ | Functions capturing and mutating outer variables |
|
|
108
|
-
|
|
109
|
-
TypeNative is currently in early development and new features are being added regularly.
|
|
152
|
+
TypeNative is currently in early development and new features are being added regularly. The goal for `1.0` release is for TypeNative to transpile itself.
|
package/bin/transpiler.js
CHANGED
|
@@ -9,6 +9,14 @@ let promiseResolveName = '';
|
|
|
9
9
|
const dangerousNames = new Set(['main']);
|
|
10
10
|
const renamedFunctions = new Map();
|
|
11
11
|
const variableTypes = new Map();
|
|
12
|
+
const variableGoTypes = new Map();
|
|
13
|
+
const variableClassNames = new Map();
|
|
14
|
+
const classPropertyTypes = new Map();
|
|
15
|
+
const classMethodReturnTypes = new Map();
|
|
16
|
+
const interfacePropertyTypes = new Map();
|
|
17
|
+
const typeAliases = new Map();
|
|
18
|
+
const enumNames = new Set();
|
|
19
|
+
const enumBaseTypes = new Map();
|
|
12
20
|
export function transpileToNative(code) {
|
|
13
21
|
const sourceFile = ts.createSourceFile('main.ts', code, ts.ScriptTarget.ES2020, true, ts.ScriptKind.TS);
|
|
14
22
|
TypeCheker = ts.createProgram(['main.ts'], {}).getTypeChecker();
|
|
@@ -18,6 +26,14 @@ export function transpileToNative(code) {
|
|
|
18
26
|
promiseResolveName = '';
|
|
19
27
|
renamedFunctions.clear();
|
|
20
28
|
variableTypes.clear();
|
|
29
|
+
variableGoTypes.clear();
|
|
30
|
+
variableClassNames.clear();
|
|
31
|
+
classPropertyTypes.clear();
|
|
32
|
+
classMethodReturnTypes.clear();
|
|
33
|
+
interfacePropertyTypes.clear();
|
|
34
|
+
typeAliases.clear();
|
|
35
|
+
enumNames.clear();
|
|
36
|
+
enumBaseTypes.clear();
|
|
21
37
|
const transpiledCode = visit(sourceFile, { addFunctionOutside: true });
|
|
22
38
|
const transpiledCodeOutside = outsideNodes.map((n) => visit(n, { isOutside: true })).join('\n');
|
|
23
39
|
return `package main
|
|
@@ -43,8 +59,17 @@ export function visit(node, options = {}) {
|
|
|
43
59
|
return 'nil';
|
|
44
60
|
return getSafeName(node.text);
|
|
45
61
|
}
|
|
46
|
-
else if (ts.isStringLiteral(node)) {
|
|
47
|
-
return
|
|
62
|
+
else if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {
|
|
63
|
+
return toGoStringLiteral(node.text);
|
|
64
|
+
}
|
|
65
|
+
else if (ts.isAsExpression(node)) {
|
|
66
|
+
return visit(node.expression);
|
|
67
|
+
}
|
|
68
|
+
else if (ts.isTypeAssertionExpression(node)) {
|
|
69
|
+
return visit(node.expression);
|
|
70
|
+
}
|
|
71
|
+
else if (ts.isTemplateExpression(node)) {
|
|
72
|
+
return visitTemplateExpression(node);
|
|
48
73
|
}
|
|
49
74
|
else if (ts.isNumericLiteral(node)) {
|
|
50
75
|
return `float64(${node.text})`;
|
|
@@ -73,12 +98,23 @@ export function visit(node, options = {}) {
|
|
|
73
98
|
return `[]${type} {${node.elements.map((e) => visit(e)).join(', ')}}`;
|
|
74
99
|
}
|
|
75
100
|
else if (ts.isBlock(node)) {
|
|
76
|
-
return `{\n\t\t${
|
|
101
|
+
return `{\n\t\t${options.prefixBlockContent ?? ''}${node.statements
|
|
102
|
+
.map((n) => visit(n))
|
|
103
|
+
.join('\t')}${options.extraBlockContent ?? ''}}${options.inline ? '' : '\n\t'}`;
|
|
77
104
|
}
|
|
78
105
|
else if (ts.isElementAccessExpression(node)) {
|
|
106
|
+
if (hasQuestionDot(node)) {
|
|
107
|
+
return visitOptionalElementAccess(node);
|
|
108
|
+
}
|
|
79
109
|
return `${visit(node.expression)}[int(${visit(node.argumentExpression)})]`;
|
|
80
110
|
}
|
|
81
111
|
else if (ts.isPropertyAccessExpression(node)) {
|
|
112
|
+
if (hasQuestionDot(node)) {
|
|
113
|
+
return visitOptionalPropertyAccess(node);
|
|
114
|
+
}
|
|
115
|
+
if (ts.isIdentifier(node.expression) && enumNames.has(node.expression.text)) {
|
|
116
|
+
return `${getSafeName(node.expression.text)}_${getEnumMemberName(node.name)}`;
|
|
117
|
+
}
|
|
82
118
|
const leftSide = visit(node.expression);
|
|
83
119
|
const rightSide = visit(node.name);
|
|
84
120
|
const objectType = resolveExpressionType(node.expression);
|
|
@@ -88,9 +124,18 @@ export function visit(node, options = {}) {
|
|
|
88
124
|
const type = getType(node.type);
|
|
89
125
|
// Track variable type for type-aware method dispatch
|
|
90
126
|
if (ts.isIdentifier(node.name)) {
|
|
127
|
+
if (node.type) {
|
|
128
|
+
variableGoTypes.set(node.name.text, getType(node.type));
|
|
129
|
+
}
|
|
91
130
|
const cat = node.type ? getTypeCategory(node.type) : undefined;
|
|
92
131
|
if (cat) {
|
|
93
132
|
variableTypes.set(node.name.text, cat);
|
|
133
|
+
if (cat === 'class' && node.type) {
|
|
134
|
+
const className = getClassNameFromTypeNode(node.type);
|
|
135
|
+
if (className) {
|
|
136
|
+
variableClassNames.set(node.name.text, className);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
94
139
|
}
|
|
95
140
|
else if (node.initializer &&
|
|
96
141
|
ts.isNewExpression(node.initializer) &&
|
|
@@ -100,11 +145,18 @@ export function visit(node, options = {}) {
|
|
|
100
145
|
}
|
|
101
146
|
else if (classNames.has(node.initializer.expression.text)) {
|
|
102
147
|
variableTypes.set(node.name.text, 'class');
|
|
148
|
+
variableClassNames.set(node.name.text, node.initializer.expression.text);
|
|
103
149
|
}
|
|
104
150
|
}
|
|
105
151
|
else if (node.initializer && ts.isRegularExpressionLiteral(node.initializer)) {
|
|
106
152
|
variableTypes.set(node.name.text, 'RegExp');
|
|
107
153
|
}
|
|
154
|
+
if (!variableGoTypes.has(node.name.text) && node.initializer) {
|
|
155
|
+
const inferredType = inferExpressionType(node.initializer);
|
|
156
|
+
if (inferredType) {
|
|
157
|
+
variableGoTypes.set(node.name.text, inferredType);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
108
160
|
}
|
|
109
161
|
let initializer = node.initializer ? `= ${visit(node.initializer)}` : '';
|
|
110
162
|
// Wrap non-nil values assigned to nullable primitive pointer types
|
|
@@ -119,6 +171,10 @@ export function visit(node, options = {}) {
|
|
|
119
171
|
return `${type === ':' ? '' : 'var '}${visit(node.name)} ${type}${type === ':' ? '' : ' '}${initializer}`;
|
|
120
172
|
}
|
|
121
173
|
else if (ts.isCallExpression(node)) {
|
|
174
|
+
if (hasQuestionDot(node) ||
|
|
175
|
+
(ts.isPropertyAccessExpression(node.expression) && hasQuestionDot(node.expression))) {
|
|
176
|
+
return visitOptionalCall(node);
|
|
177
|
+
}
|
|
122
178
|
// Handle setTimeout specially to get raw delay value
|
|
123
179
|
if (ts.isIdentifier(node.expression) && node.expression.text === 'setTimeout') {
|
|
124
180
|
importedPackages.add('time');
|
|
@@ -127,6 +183,10 @@ export function visit(node, options = {}) {
|
|
|
127
183
|
const delay = ts.isNumericLiteral(delayNode) ? delayNode.text : visit(delayNode);
|
|
128
184
|
return `time.AfterFunc(${delay} * time.Millisecond, ${callback.trimEnd()})`;
|
|
129
185
|
}
|
|
186
|
+
const arrayHigherOrderCall = visitArrayHigherOrderCall(node);
|
|
187
|
+
if (arrayHigherOrderCall) {
|
|
188
|
+
return arrayHigherOrderCall;
|
|
189
|
+
}
|
|
130
190
|
const caller = visit(node.expression);
|
|
131
191
|
const safeCaller = getSafeName(caller);
|
|
132
192
|
const typeArgs = getTypeArguments(node.typeArguments);
|
|
@@ -144,7 +204,13 @@ export function visit(node, options = {}) {
|
|
|
144
204
|
else if (ts.isPostfixUnaryExpression(node)) {
|
|
145
205
|
return `${visit(node.operand, { inline: true })}${getOperatorText(node.operator)}`;
|
|
146
206
|
}
|
|
207
|
+
else if (ts.isConditionalExpression(node)) {
|
|
208
|
+
return visitConditionalExpression(node);
|
|
209
|
+
}
|
|
147
210
|
else if (ts.isBinaryExpression(node)) {
|
|
211
|
+
if (node.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken) {
|
|
212
|
+
return visitNullishCoalescingExpression(node);
|
|
213
|
+
}
|
|
148
214
|
let op = node.operatorToken.getText();
|
|
149
215
|
if (op === '===')
|
|
150
216
|
op = '==';
|
|
@@ -233,28 +299,56 @@ export function visit(node, options = {}) {
|
|
|
233
299
|
const name = visit(node.name, { inline: true });
|
|
234
300
|
const safeName = getSafeName(name);
|
|
235
301
|
const typeParams = getTypeParameters(node.typeParameters);
|
|
236
|
-
const
|
|
237
|
-
.map((p) => `${visit(p.name)} ${getType(p.type)}`)
|
|
238
|
-
.join(', ');
|
|
302
|
+
const parameterInfo = getFunctionParametersInfo(node.parameters);
|
|
239
303
|
const returnType = node.type ? ` ${getType(node.type)}` : '';
|
|
240
304
|
if (options.isOutside) {
|
|
241
|
-
return `func ${safeName}${typeParams}(${
|
|
305
|
+
return `func ${safeName}${typeParams}(${parameterInfo.signature})${returnType} ${visit(node.body, {
|
|
306
|
+
prefixBlockContent: parameterInfo.prefixBlockContent
|
|
307
|
+
})}`;
|
|
242
308
|
}
|
|
243
|
-
return `${safeName} := func${typeParams}(${
|
|
309
|
+
return `${safeName} := func${typeParams}(${parameterInfo.signature})${returnType} ${visit(node.body, {
|
|
310
|
+
prefixBlockContent: parameterInfo.prefixBlockContent
|
|
311
|
+
})}`;
|
|
244
312
|
}
|
|
245
313
|
else if (ts.isArrowFunction(node)) {
|
|
246
|
-
const
|
|
247
|
-
.map((p) => `${visit(p.name)} ${getType(p.type)}`)
|
|
248
|
-
.join(', ');
|
|
314
|
+
const parameterInfo = getFunctionParametersInfo(node.parameters);
|
|
249
315
|
const returnType = node.type ? ` ${getType(node.type)}` : '';
|
|
250
|
-
|
|
316
|
+
if (parameterInfo.prefixBlockContent && !ts.isBlock(node.body)) {
|
|
317
|
+
return `func(${parameterInfo.signature})${returnType} {\n\t\t${parameterInfo.prefixBlockContent}return ${visit(node.body)};\n\t}`;
|
|
318
|
+
}
|
|
319
|
+
return `func(${parameterInfo.signature})${returnType} ${visit(node.body, {
|
|
320
|
+
prefixBlockContent: parameterInfo.prefixBlockContent
|
|
321
|
+
})}`;
|
|
251
322
|
}
|
|
252
323
|
else if (node.kind === ts.SyntaxKind.ThisKeyword) {
|
|
253
324
|
return 'self';
|
|
254
325
|
}
|
|
326
|
+
else if (ts.isEnumDeclaration(node)) {
|
|
327
|
+
const enumName = node.name.text;
|
|
328
|
+
enumNames.add(enumName);
|
|
329
|
+
enumBaseTypes.set(enumName, getEnumBaseType(node));
|
|
330
|
+
if (options.addFunctionOutside) {
|
|
331
|
+
outsideNodes.push(node);
|
|
332
|
+
return '';
|
|
333
|
+
}
|
|
334
|
+
return visitEnumDeclaration(node);
|
|
335
|
+
}
|
|
336
|
+
else if (ts.isTypeAliasDeclaration(node)) {
|
|
337
|
+
typeAliases.set(node.name.text, node.type);
|
|
338
|
+
return '';
|
|
339
|
+
}
|
|
255
340
|
else if (ts.isInterfaceDeclaration(node)) {
|
|
256
341
|
if (options.addFunctionOutside) {
|
|
257
342
|
outsideNodes.push(node);
|
|
343
|
+
const properties = new Map();
|
|
344
|
+
for (const member of node.members) {
|
|
345
|
+
if (ts.isPropertySignature(member) && ts.isIdentifier(member.name)) {
|
|
346
|
+
properties.set(member.name.text, getOptionalNodeType(member.type, !!member.questionToken));
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
if (properties.size > 0) {
|
|
350
|
+
interfacePropertyTypes.set(visit(node.name), properties);
|
|
351
|
+
}
|
|
258
352
|
return '';
|
|
259
353
|
}
|
|
260
354
|
const name = visit(node.name);
|
|
@@ -270,6 +364,7 @@ export function visit(node, options = {}) {
|
|
|
270
364
|
}
|
|
271
365
|
}
|
|
272
366
|
const methods = [];
|
|
367
|
+
const properties = [];
|
|
273
368
|
for (const member of node.members) {
|
|
274
369
|
if (ts.isMethodSignature(member)) {
|
|
275
370
|
const methodName = visit(member.name);
|
|
@@ -279,6 +374,13 @@ export function visit(node, options = {}) {
|
|
|
279
374
|
const returnType = member.type ? ` ${getType(member.type)}` : '';
|
|
280
375
|
methods.push(`\t${methodName}(${params})${returnType}`);
|
|
281
376
|
}
|
|
377
|
+
else if (ts.isPropertySignature(member) && ts.isIdentifier(member.name)) {
|
|
378
|
+
properties.push(`\t${member.name.text} ${getOptionalNodeType(member.type, !!member.questionToken)}`);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
if (properties.length > 0 && methods.length === 0) {
|
|
382
|
+
const fields = [...extendedInterfaces.map((e) => `\t${e}`), ...properties];
|
|
383
|
+
return `type ${name}${typeParams} struct {\n${fields.join('\n')}\n}`;
|
|
282
384
|
}
|
|
283
385
|
const members = [...extendedInterfaces.map((e) => `\t${e}`), ...methods];
|
|
284
386
|
return `type ${name}${typeParams} interface {\n${members.join('\n')}\n}`;
|
|
@@ -286,7 +388,20 @@ export function visit(node, options = {}) {
|
|
|
286
388
|
else if (ts.isClassDeclaration(node)) {
|
|
287
389
|
if (options.addFunctionOutside) {
|
|
288
390
|
outsideNodes.push(node);
|
|
289
|
-
|
|
391
|
+
const className = visit(node.name);
|
|
392
|
+
classNames.add(className);
|
|
393
|
+
const properties = new Map();
|
|
394
|
+
const methods = new Map();
|
|
395
|
+
for (const member of node.members) {
|
|
396
|
+
if (ts.isPropertyDeclaration(member) && ts.isIdentifier(member.name)) {
|
|
397
|
+
properties.set(member.name.text, getOptionalNodeType(member.type, !!member.questionToken));
|
|
398
|
+
}
|
|
399
|
+
if (ts.isMethodDeclaration(member) && ts.isIdentifier(member.name)) {
|
|
400
|
+
methods.set(member.name.text, member.type ? getType(member.type) : 'interface{}');
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
classPropertyTypes.set(className, properties);
|
|
404
|
+
classMethodReturnTypes.set(className, methods);
|
|
290
405
|
return '';
|
|
291
406
|
}
|
|
292
407
|
const name = visit(node.name);
|
|
@@ -312,7 +427,7 @@ export function visit(node, options = {}) {
|
|
|
312
427
|
fieldType = `[]${getType(member.type, true)}`;
|
|
313
428
|
}
|
|
314
429
|
else {
|
|
315
|
-
fieldType = member.type
|
|
430
|
+
fieldType = getOptionalNodeType(member.type, !!member.questionToken);
|
|
316
431
|
}
|
|
317
432
|
fields.push(`\t${fieldName} ${fieldType}`);
|
|
318
433
|
}
|
|
@@ -320,7 +435,7 @@ export function visit(node, options = {}) {
|
|
|
320
435
|
let result = `type ${name}${typeParams} struct {\n${fields.join('\n')}\n}\n\n`;
|
|
321
436
|
const ctor = node.members.find((m) => ts.isConstructorDeclaration(m));
|
|
322
437
|
if (ctor) {
|
|
323
|
-
const
|
|
438
|
+
const ctorParameterInfo = getFunctionParametersInfo(ctor.parameters);
|
|
324
439
|
const bodyStatements = ctor.body?.statements
|
|
325
440
|
.filter((s) => {
|
|
326
441
|
if (ts.isExpressionStatement(s) && ts.isCallExpression(s.expression)) {
|
|
@@ -330,7 +445,7 @@ export function visit(node, options = {}) {
|
|
|
330
445
|
})
|
|
331
446
|
.map((s) => visit(s))
|
|
332
447
|
.join('\t') ?? '';
|
|
333
|
-
result += `func New${name}${typeParams}(${
|
|
448
|
+
result += `func New${name}${typeParams}(${ctorParameterInfo.signature}) *${name}${typeParamNames} {\n\t\tself := &${name}${typeParamNames}{}\n\t\t${ctorParameterInfo.prefixBlockContent}${bodyStatements}return self;\n\t}\n\n`;
|
|
334
449
|
}
|
|
335
450
|
else {
|
|
336
451
|
result += `func New${name}${typeParams}() *${name}${typeParamNames} {\n\t\treturn &${name}${typeParamNames}{}\n\t}\n\n`;
|
|
@@ -338,11 +453,11 @@ export function visit(node, options = {}) {
|
|
|
338
453
|
for (const member of node.members) {
|
|
339
454
|
if (ts.isMethodDeclaration(member)) {
|
|
340
455
|
const methodName = visit(member.name);
|
|
341
|
-
const
|
|
342
|
-
.map((p) => `${visit(p.name)} ${getType(p.type)}`)
|
|
343
|
-
.join(', ');
|
|
456
|
+
const methodParameterInfo = getFunctionParametersInfo(member.parameters);
|
|
344
457
|
const returnType = member.type ? ` ${getType(member.type)}` : '';
|
|
345
|
-
result += `func (self *${name}${typeParamNames}) ${methodName}(${
|
|
458
|
+
result += `func (self *${name}${typeParamNames}) ${methodName}(${methodParameterInfo.signature})${returnType} ${visit(member.body, {
|
|
459
|
+
prefixBlockContent: methodParameterInfo.prefixBlockContent
|
|
460
|
+
})}\n\n`;
|
|
346
461
|
}
|
|
347
462
|
}
|
|
348
463
|
return result.trim();
|
|
@@ -408,9 +523,492 @@ function getTypeText(typeNode) {
|
|
|
408
523
|
}
|
|
409
524
|
return getType(typeNode);
|
|
410
525
|
}
|
|
526
|
+
function toGoStringLiteral(value) {
|
|
527
|
+
return JSON.stringify(value);
|
|
528
|
+
}
|
|
529
|
+
function visitTemplateExpression(node) {
|
|
530
|
+
const parts = [];
|
|
531
|
+
if (node.head.text.length > 0) {
|
|
532
|
+
parts.push(toGoStringLiteral(node.head.text));
|
|
533
|
+
}
|
|
534
|
+
for (const span of node.templateSpans) {
|
|
535
|
+
importedPackages.add('fmt');
|
|
536
|
+
parts.push(`fmt.Sprintf("%v", ${visit(span.expression)})`);
|
|
537
|
+
if (span.literal.text.length > 0) {
|
|
538
|
+
parts.push(toGoStringLiteral(span.literal.text));
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
if (parts.length === 0) {
|
|
542
|
+
return '""';
|
|
543
|
+
}
|
|
544
|
+
return parts.join(' + ');
|
|
545
|
+
}
|
|
546
|
+
function hasQuestionDot(node) {
|
|
547
|
+
return ('questionDotToken' in node &&
|
|
548
|
+
!!node.questionDotToken);
|
|
549
|
+
}
|
|
550
|
+
function getTempName(prefix) {
|
|
551
|
+
return `__${prefix}_${goSafeId()}__`;
|
|
552
|
+
}
|
|
553
|
+
function inferExpectedTypeFromContext(node) {
|
|
554
|
+
const parent = node.parent;
|
|
555
|
+
if (ts.isVariableDeclaration(parent) && parent.initializer === node && parent.type) {
|
|
556
|
+
return getType(parent.type);
|
|
557
|
+
}
|
|
558
|
+
if (ts.isReturnStatement(parent)) {
|
|
559
|
+
let scope = parent.parent;
|
|
560
|
+
while (scope) {
|
|
561
|
+
if (ts.isFunctionDeclaration(scope) ||
|
|
562
|
+
ts.isMethodDeclaration(scope) ||
|
|
563
|
+
ts.isFunctionExpression(scope) ||
|
|
564
|
+
ts.isArrowFunction(scope)) {
|
|
565
|
+
if (scope.type)
|
|
566
|
+
return getType(scope.type);
|
|
567
|
+
break;
|
|
568
|
+
}
|
|
569
|
+
scope = scope.parent;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return undefined;
|
|
573
|
+
}
|
|
574
|
+
function inferExpressionType(expr) {
|
|
575
|
+
if (ts.isParenthesizedExpression(expr))
|
|
576
|
+
return inferExpressionType(expr.expression);
|
|
577
|
+
if (ts.isNonNullExpression(expr))
|
|
578
|
+
return inferExpressionType(expr.expression);
|
|
579
|
+
if (ts.isAsExpression(expr))
|
|
580
|
+
return getType(expr.type);
|
|
581
|
+
if (ts.isTypeAssertionExpression(expr))
|
|
582
|
+
return getType(expr.type);
|
|
583
|
+
if (ts.isStringLiteral(expr) ||
|
|
584
|
+
ts.isNoSubstitutionTemplateLiteral(expr) ||
|
|
585
|
+
ts.isTemplateExpression(expr)) {
|
|
586
|
+
return 'string';
|
|
587
|
+
}
|
|
588
|
+
if (ts.isNumericLiteral(expr))
|
|
589
|
+
return 'float64';
|
|
590
|
+
if (expr.kind === ts.SyntaxKind.TrueKeyword || expr.kind === ts.SyntaxKind.FalseKeyword)
|
|
591
|
+
return 'bool';
|
|
592
|
+
if (expr.kind === ts.SyntaxKind.NullKeyword)
|
|
593
|
+
return 'nil';
|
|
594
|
+
if (ts.isIdentifier(expr))
|
|
595
|
+
return variableGoTypes.get(expr.text);
|
|
596
|
+
if (ts.isArrayLiteralExpression(expr)) {
|
|
597
|
+
if (expr.elements.length === 0)
|
|
598
|
+
return '[]interface{}';
|
|
599
|
+
const firstElementType = inferExpressionType(expr.elements[0]) ?? 'interface{}';
|
|
600
|
+
return `[]${firstElementType}`;
|
|
601
|
+
}
|
|
602
|
+
if (ts.isPropertyAccessExpression(expr)) {
|
|
603
|
+
if (ts.isIdentifier(expr.expression) && enumNames.has(expr.expression.text)) {
|
|
604
|
+
const enumType = getSafeName(expr.expression.text);
|
|
605
|
+
return enumType;
|
|
606
|
+
}
|
|
607
|
+
const leftType = inferExpressionType(expr.expression);
|
|
608
|
+
if (expr.name.text === 'length')
|
|
609
|
+
return 'float64';
|
|
610
|
+
const resolvedLeftType = leftType?.replace(/^\*/, '').replace(/\[.*\]$/, '');
|
|
611
|
+
const resolvedPropertyType = resolvedLeftType
|
|
612
|
+
? (classPropertyTypes.get(resolvedLeftType)?.get(expr.name.text) ??
|
|
613
|
+
interfacePropertyTypes.get(resolvedLeftType)?.get(expr.name.text))
|
|
614
|
+
: undefined;
|
|
615
|
+
if (hasQuestionDot(expr)) {
|
|
616
|
+
if (leftType && leftType.startsWith('*')) {
|
|
617
|
+
const memberType = resolvedPropertyType ?? 'interface{}';
|
|
618
|
+
return makeNullableType(memberType);
|
|
619
|
+
}
|
|
620
|
+
return 'interface{}';
|
|
621
|
+
}
|
|
622
|
+
if (resolvedPropertyType) {
|
|
623
|
+
return resolvedPropertyType;
|
|
624
|
+
}
|
|
625
|
+
if (ts.isIdentifier(expr.expression)) {
|
|
626
|
+
const className = variableClassNames.get(expr.expression.text);
|
|
627
|
+
const memberType = className
|
|
628
|
+
? classPropertyTypes.get(className)?.get(expr.name.text)
|
|
629
|
+
: undefined;
|
|
630
|
+
if (memberType)
|
|
631
|
+
return memberType;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
if (ts.isCallExpression(expr) && ts.isPropertyAccessExpression(expr.expression)) {
|
|
635
|
+
const methodName = expr.expression.name.text;
|
|
636
|
+
const ownerType = inferExpressionType(expr.expression.expression);
|
|
637
|
+
if (isArrayLikeGoType(ownerType)) {
|
|
638
|
+
const elementType = getArrayElementTypeFromGoType(ownerType);
|
|
639
|
+
if (methodName === 'map') {
|
|
640
|
+
const callback = expr.arguments[0];
|
|
641
|
+
const mappedType = callback
|
|
642
|
+
? inferArrayCallbackReturnType(callback, elementType, elementType)
|
|
643
|
+
: elementType;
|
|
644
|
+
return `[]${mappedType}`;
|
|
645
|
+
}
|
|
646
|
+
if (methodName === 'filter')
|
|
647
|
+
return `[]${elementType}`;
|
|
648
|
+
if (methodName === 'some')
|
|
649
|
+
return 'bool';
|
|
650
|
+
if (methodName === 'find')
|
|
651
|
+
return elementType;
|
|
652
|
+
if (methodName === 'join')
|
|
653
|
+
return 'string';
|
|
654
|
+
}
|
|
655
|
+
if (ownerType && ownerType.startsWith('*')) {
|
|
656
|
+
const className = ownerType.replace(/^\*/, '').replace(/\[.*\]$/, '');
|
|
657
|
+
const returnType = classMethodReturnTypes.get(className)?.get(methodName);
|
|
658
|
+
if (returnType) {
|
|
659
|
+
if (hasQuestionDot(expr) || hasQuestionDot(expr.expression)) {
|
|
660
|
+
return makeNullableType(returnType);
|
|
661
|
+
}
|
|
662
|
+
return returnType;
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
if (ts.isIdentifier(expr.expression.expression)) {
|
|
666
|
+
const className = variableClassNames.get(expr.expression.expression.text);
|
|
667
|
+
const returnType = className
|
|
668
|
+
? classMethodReturnTypes.get(className)?.get(methodName)
|
|
669
|
+
: undefined;
|
|
670
|
+
if (returnType) {
|
|
671
|
+
if (hasQuestionDot(expr) || hasQuestionDot(expr.expression)) {
|
|
672
|
+
return makeNullableType(returnType);
|
|
673
|
+
}
|
|
674
|
+
return returnType;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
if (ts.isConditionalExpression(expr)) {
|
|
679
|
+
const whenTrueType = inferExpressionType(expr.whenTrue);
|
|
680
|
+
const whenFalseType = inferExpressionType(expr.whenFalse);
|
|
681
|
+
if (whenTrueType && whenTrueType === whenFalseType)
|
|
682
|
+
return whenTrueType;
|
|
683
|
+
return whenTrueType ?? whenFalseType;
|
|
684
|
+
}
|
|
685
|
+
if (ts.isBinaryExpression(expr) &&
|
|
686
|
+
expr.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken) {
|
|
687
|
+
const leftType = inferExpressionType(expr.left);
|
|
688
|
+
const rightType = inferExpressionType(expr.right);
|
|
689
|
+
if (leftType && leftType.startsWith('*') && rightType === leftType.slice(1)) {
|
|
690
|
+
return rightType;
|
|
691
|
+
}
|
|
692
|
+
return rightType ?? leftType;
|
|
693
|
+
}
|
|
694
|
+
return undefined;
|
|
695
|
+
}
|
|
696
|
+
function makeNullableType(typeName) {
|
|
697
|
+
if (!typeName || typeName === 'interface{}' || typeName.startsWith('*'))
|
|
698
|
+
return typeName || 'interface{}';
|
|
699
|
+
if (['string', 'float64', 'bool'].includes(typeName))
|
|
700
|
+
return `*${typeName}`;
|
|
701
|
+
return typeName;
|
|
702
|
+
}
|
|
703
|
+
function visitConditionalExpression(node) {
|
|
704
|
+
const whenTrue = visit(node.whenTrue);
|
|
705
|
+
const whenFalse = visit(node.whenFalse);
|
|
706
|
+
const resultType = inferExpectedTypeFromContext(node) ||
|
|
707
|
+
(() => {
|
|
708
|
+
const whenTrueType = inferExpressionType(node.whenTrue);
|
|
709
|
+
const whenFalseType = inferExpressionType(node.whenFalse);
|
|
710
|
+
if (whenTrueType && whenTrueType === whenFalseType)
|
|
711
|
+
return whenTrueType;
|
|
712
|
+
return whenTrueType ?? whenFalseType ?? 'interface{}';
|
|
713
|
+
})();
|
|
714
|
+
return `func() ${resultType} { if ${visit(node.condition)} { return ${whenTrue} }; return ${whenFalse} }()`;
|
|
715
|
+
}
|
|
716
|
+
function visitNullishCoalescingExpression(node) {
|
|
717
|
+
const leftType = inferExpressionType(node.left);
|
|
718
|
+
const rightType = inferExpressionType(node.right);
|
|
719
|
+
if (leftType && leftType.startsWith('*')) {
|
|
720
|
+
const leftValueType = leftType.slice(1);
|
|
721
|
+
const expectedType = inferExpectedTypeFromContext(node);
|
|
722
|
+
const resultType = expectedType || (rightType === leftValueType ? leftValueType : (rightType ?? leftType));
|
|
723
|
+
const tmp = getTempName('nullish');
|
|
724
|
+
const leftExpr = visit(node.left);
|
|
725
|
+
const rightExpr = visit(node.right);
|
|
726
|
+
const returnLeft = resultType === leftValueType ? `*${tmp}` : tmp;
|
|
727
|
+
return `func() ${resultType} { ${tmp} := ${leftExpr}; if ${tmp} == nil { return ${rightExpr} }; return ${returnLeft} }()`;
|
|
728
|
+
}
|
|
729
|
+
return visit(node.left);
|
|
730
|
+
}
|
|
731
|
+
function visitOptionalPropertyAccess(node) {
|
|
732
|
+
const baseExpr = visit(node.expression);
|
|
733
|
+
const baseType = inferExpressionType(node.expression);
|
|
734
|
+
if (!baseType || !baseType.startsWith('*')) {
|
|
735
|
+
const objectType = resolveExpressionType(node.expression);
|
|
736
|
+
return getAcessString(baseExpr, visit(node.name), objectType);
|
|
737
|
+
}
|
|
738
|
+
const className = baseType.replace(/^\*/, '').replace(/\[.*\]$/, '');
|
|
739
|
+
const propertyType = classPropertyTypes.get(className)?.get(node.name.text) ?? 'interface{}';
|
|
740
|
+
const nullableType = makeNullableType(propertyType);
|
|
741
|
+
const tmp = getTempName('opt');
|
|
742
|
+
const propertyAccess = `${tmp}.${visit(node.name)}`;
|
|
743
|
+
if (nullableType.startsWith('*') && nullableType.slice(1) === propertyType) {
|
|
744
|
+
const valueTemp = getTempName('optv');
|
|
745
|
+
return `func() ${nullableType} { ${tmp} := ${baseExpr}; if ${tmp} == nil { var __zero ${nullableType}; return __zero }; ${valueTemp} := ${propertyAccess}; return &${valueTemp} }()`;
|
|
746
|
+
}
|
|
747
|
+
return `func() ${nullableType} { ${tmp} := ${baseExpr}; if ${tmp} == nil { var __zero ${nullableType}; return __zero }; return ${propertyAccess} }()`;
|
|
748
|
+
}
|
|
749
|
+
function visitOptionalElementAccess(node) {
|
|
750
|
+
const baseExpr = visit(node.expression);
|
|
751
|
+
const baseType = inferExpressionType(node.expression);
|
|
752
|
+
if (!baseType || !baseType.startsWith('*')) {
|
|
753
|
+
return `${baseExpr}[int(${visit(node.argumentExpression)})]`;
|
|
754
|
+
}
|
|
755
|
+
const valueType = inferExpectedTypeFromContext(node) ?? 'interface{}';
|
|
756
|
+
const nullableType = makeNullableType(valueType);
|
|
757
|
+
const tmp = getTempName('opte');
|
|
758
|
+
const elementExpr = `${tmp}[int(${visit(node.argumentExpression)})]`;
|
|
759
|
+
if (nullableType.startsWith('*') && nullableType.slice(1) === valueType) {
|
|
760
|
+
const valueTemp = getTempName('optev');
|
|
761
|
+
return `func() ${nullableType} { ${tmp} := ${baseExpr}; if ${tmp} == nil { var __zero ${nullableType}; return __zero }; ${valueTemp} := ${elementExpr}; return &${valueTemp} }()`;
|
|
762
|
+
}
|
|
763
|
+
return `func() ${nullableType} { ${tmp} := ${baseExpr}; if ${tmp} == nil { var __zero ${nullableType}; return __zero }; return ${elementExpr} }()`;
|
|
764
|
+
}
|
|
765
|
+
function visitOptionalCall(node) {
|
|
766
|
+
if (!ts.isPropertyAccessExpression(node.expression)) {
|
|
767
|
+
return `${visit(node.expression)}(${node.arguments.map((a) => visit(a)).join(', ')})`;
|
|
768
|
+
}
|
|
769
|
+
const baseNode = node.expression.expression;
|
|
770
|
+
const methodName = node.expression.name.text;
|
|
771
|
+
const baseExpr = visit(baseNode);
|
|
772
|
+
const baseType = inferExpressionType(baseNode);
|
|
773
|
+
const args = node.arguments.map((a) => visit(a)).join(', ');
|
|
774
|
+
if (!baseType || !baseType.startsWith('*')) {
|
|
775
|
+
return `${baseExpr}.${methodName}(${args})`;
|
|
776
|
+
}
|
|
777
|
+
const className = baseType.replace(/^\*/, '').replace(/\[.*\]$/, '');
|
|
778
|
+
const returnType = classMethodReturnTypes.get(className)?.get(methodName) ?? 'interface{}';
|
|
779
|
+
const nullableType = makeNullableType(returnType);
|
|
780
|
+
const tmp = getTempName('optc');
|
|
781
|
+
const callExpr = `${tmp}.${methodName}(${args})`;
|
|
782
|
+
if (nullableType.startsWith('*') && nullableType.slice(1) === returnType) {
|
|
783
|
+
const valueTemp = getTempName('optcv');
|
|
784
|
+
return `func() ${nullableType} { ${tmp} := ${baseExpr}; if ${tmp} == nil { var __zero ${nullableType}; return __zero }; ${valueTemp} := ${callExpr}; return &${valueTemp} }()`;
|
|
785
|
+
}
|
|
786
|
+
return `func() ${nullableType} { ${tmp} := ${baseExpr}; if ${tmp} == nil { var __zero ${nullableType}; return __zero }; return ${callExpr} }()`;
|
|
787
|
+
}
|
|
788
|
+
function isArrayLikeGoType(goType) {
|
|
789
|
+
return !!goType && goType.startsWith('[]');
|
|
790
|
+
}
|
|
791
|
+
function getArrayElementTypeFromGoType(goType) {
|
|
792
|
+
if (!goType.startsWith('[]'))
|
|
793
|
+
return 'interface{}';
|
|
794
|
+
const elementType = goType.slice(2);
|
|
795
|
+
return elementType || 'interface{}';
|
|
796
|
+
}
|
|
797
|
+
function inferArrayCallbackReturnType(callback, elementType, fallbackType) {
|
|
798
|
+
if (ts.isArrowFunction(callback) || ts.isFunctionExpression(callback)) {
|
|
799
|
+
if (callback.type) {
|
|
800
|
+
const explicitType = getType(callback.type);
|
|
801
|
+
return explicitType || fallbackType;
|
|
802
|
+
}
|
|
803
|
+
if (ts.isBlock(callback.body)) {
|
|
804
|
+
return fallbackType;
|
|
805
|
+
}
|
|
806
|
+
const inferred = inferExpressionType(callback.body);
|
|
807
|
+
return inferred ?? fallbackType;
|
|
808
|
+
}
|
|
809
|
+
if (ts.isIdentifier(callback)) {
|
|
810
|
+
const knownType = variableGoTypes.get(callback.text);
|
|
811
|
+
if (knownType)
|
|
812
|
+
return knownType;
|
|
813
|
+
}
|
|
814
|
+
return fallbackType;
|
|
815
|
+
}
|
|
816
|
+
function buildArrayCallbackInfo(callback, elementType, forcedReturnType) {
|
|
817
|
+
if (ts.isArrowFunction(callback) || ts.isFunctionExpression(callback)) {
|
|
818
|
+
const paramCount = callback.parameters.length;
|
|
819
|
+
const callbackReturnType = forcedReturnType ?? inferArrayCallbackReturnType(callback, elementType, 'interface{}');
|
|
820
|
+
const params = [];
|
|
821
|
+
if (paramCount > 0) {
|
|
822
|
+
params.push(`${visit(callback.parameters[0].name)} ${elementType}`);
|
|
823
|
+
}
|
|
824
|
+
if (paramCount > 1) {
|
|
825
|
+
params.push(`${visit(callback.parameters[1].name)} float64`);
|
|
826
|
+
}
|
|
827
|
+
if (paramCount > 2) {
|
|
828
|
+
params.push(`${visit(callback.parameters[2].name)} []${elementType}`);
|
|
829
|
+
}
|
|
830
|
+
const body = ts.isBlock(callback.body)
|
|
831
|
+
? visit(callback.body)
|
|
832
|
+
: `{\n\t\treturn ${visit(callback.body)};\n\t}`;
|
|
833
|
+
return {
|
|
834
|
+
fnExpr: `func(${params.join(', ')}) ${callbackReturnType} ${body}`,
|
|
835
|
+
paramCount,
|
|
836
|
+
returnType: callbackReturnType
|
|
837
|
+
};
|
|
838
|
+
}
|
|
839
|
+
return {
|
|
840
|
+
fnExpr: visit(callback),
|
|
841
|
+
paramCount: 1,
|
|
842
|
+
returnType: forcedReturnType ?? 'interface{}'
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
function buildArrayCallbackInvocation(callbackInfo, itemVar, indexVar, arrayVar) {
|
|
846
|
+
const args = [];
|
|
847
|
+
if (callbackInfo.paramCount > 0)
|
|
848
|
+
args.push(itemVar);
|
|
849
|
+
if (callbackInfo.paramCount > 1)
|
|
850
|
+
args.push(`float64(${indexVar})`);
|
|
851
|
+
if (callbackInfo.paramCount > 2)
|
|
852
|
+
args.push(arrayVar);
|
|
853
|
+
return `(${callbackInfo.fnExpr})(${args.join(', ')})`;
|
|
854
|
+
}
|
|
855
|
+
function visitArrayHigherOrderCall(node) {
|
|
856
|
+
if (!ts.isPropertyAccessExpression(node.expression))
|
|
857
|
+
return undefined;
|
|
858
|
+
const methodName = node.expression.name.text;
|
|
859
|
+
if (!['map', 'filter', 'some', 'find', 'join'].includes(methodName)) {
|
|
860
|
+
return undefined;
|
|
861
|
+
}
|
|
862
|
+
const arrayExprNode = node.expression.expression;
|
|
863
|
+
const arrayExpr = visit(arrayExprNode);
|
|
864
|
+
const ownerType = inferExpressionType(arrayExprNode);
|
|
865
|
+
const elementType = isArrayLikeGoType(ownerType)
|
|
866
|
+
? getArrayElementTypeFromGoType(ownerType)
|
|
867
|
+
: 'interface{}';
|
|
868
|
+
if (methodName === 'join') {
|
|
869
|
+
importedPackages.add('strings');
|
|
870
|
+
importedPackages.add('fmt');
|
|
871
|
+
const separator = node.arguments[0] ? visit(node.arguments[0]) : '""';
|
|
872
|
+
const arrVar = getTempName('arrjoin');
|
|
873
|
+
const partsVar = getTempName('parts');
|
|
874
|
+
return `func() string { ${arrVar} := ${arrayExpr}; ${partsVar} := make([]string, len(${arrVar})); for i, v := range ${arrVar} { ${partsVar}[i] = fmt.Sprintf("%v", v) }; return strings.Join(${partsVar}, ${separator}) }()`;
|
|
875
|
+
}
|
|
876
|
+
const callback = node.arguments[0];
|
|
877
|
+
if (!callback) {
|
|
878
|
+
return undefined;
|
|
879
|
+
}
|
|
880
|
+
const arrVar = getTempName('arrhof');
|
|
881
|
+
const idxVar = getTempName('i');
|
|
882
|
+
const itemVar = getTempName('item');
|
|
883
|
+
if (methodName === 'map') {
|
|
884
|
+
const callbackInfo = buildArrayCallbackInfo(callback, elementType, elementType);
|
|
885
|
+
const mappedType = callbackInfo.returnType || 'interface{}';
|
|
886
|
+
const resultVar = getTempName('mapres');
|
|
887
|
+
const rangeIndexVar = callbackInfo.paramCount > 1 ? idxVar : '_';
|
|
888
|
+
const callbackCall = buildArrayCallbackInvocation(callbackInfo, itemVar, idxVar, arrVar);
|
|
889
|
+
return `func() []${mappedType} { ${arrVar} := ${arrayExpr}; ${resultVar} := make([]${mappedType}, 0, len(${arrVar})); for ${rangeIndexVar}, ${itemVar} := range ${arrVar} { ${resultVar} = append(${resultVar}, ${callbackCall}) }; return ${resultVar} }()`;
|
|
890
|
+
}
|
|
891
|
+
if (methodName === 'filter') {
|
|
892
|
+
const callbackInfo = buildArrayCallbackInfo(callback, elementType, 'bool');
|
|
893
|
+
const resultVar = getTempName('filterres');
|
|
894
|
+
const rangeIndexVar = callbackInfo.paramCount > 1 ? idxVar : '_';
|
|
895
|
+
const callbackCall = buildArrayCallbackInvocation(callbackInfo, itemVar, idxVar, arrVar);
|
|
896
|
+
return `func() []${elementType} { ${arrVar} := ${arrayExpr}; ${resultVar} := make([]${elementType}, 0, len(${arrVar})); for ${rangeIndexVar}, ${itemVar} := range ${arrVar} { if ${callbackCall} { ${resultVar} = append(${resultVar}, ${itemVar}) } }; return ${resultVar} }()`;
|
|
897
|
+
}
|
|
898
|
+
if (methodName === 'some') {
|
|
899
|
+
const callbackInfo = buildArrayCallbackInfo(callback, elementType, 'bool');
|
|
900
|
+
const rangeIndexVar = callbackInfo.paramCount > 1 ? idxVar : '_';
|
|
901
|
+
const callbackCall = buildArrayCallbackInvocation(callbackInfo, itemVar, idxVar, arrVar);
|
|
902
|
+
return `func() bool { ${arrVar} := ${arrayExpr}; for ${rangeIndexVar}, ${itemVar} := range ${arrVar} { if ${callbackCall} { return true } }; return false }()`;
|
|
903
|
+
}
|
|
904
|
+
const callbackInfo = buildArrayCallbackInfo(callback, elementType, 'bool');
|
|
905
|
+
const rangeIndexVar = callbackInfo.paramCount > 1 ? idxVar : '_';
|
|
906
|
+
const callbackCall = buildArrayCallbackInvocation(callbackInfo, itemVar, idxVar, arrVar);
|
|
907
|
+
return `func() ${elementType} { ${arrVar} := ${arrayExpr}; for ${rangeIndexVar}, ${itemVar} := range ${arrVar} { if ${callbackCall} { return ${itemVar} } }; var __zero ${elementType}; return __zero }()`;
|
|
908
|
+
}
|
|
909
|
+
function getAliasType(name, seen = new Set()) {
|
|
910
|
+
const aliasType = typeAliases.get(name);
|
|
911
|
+
if (!aliasType)
|
|
912
|
+
return undefined;
|
|
913
|
+
if (seen.has(name))
|
|
914
|
+
return undefined;
|
|
915
|
+
if (ts.isTypeReferenceNode(aliasType) && ts.isIdentifier(aliasType.typeName)) {
|
|
916
|
+
const nestedName = aliasType.typeName.text;
|
|
917
|
+
if (typeAliases.has(nestedName)) {
|
|
918
|
+
seen.add(name);
|
|
919
|
+
return getAliasType(nestedName, seen) ?? aliasType;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
return aliasType;
|
|
923
|
+
}
|
|
924
|
+
function getOptionalNodeType(typeNode, isOptional) {
|
|
925
|
+
const baseType = typeNode ? getType(typeNode) : 'interface{}';
|
|
926
|
+
if (!isOptional)
|
|
927
|
+
return baseType;
|
|
928
|
+
if (baseType === 'interface{}' || baseType.startsWith('*'))
|
|
929
|
+
return baseType;
|
|
930
|
+
if (['string', 'float64', 'bool'].includes(baseType))
|
|
931
|
+
return `*${baseType}`;
|
|
932
|
+
return baseType;
|
|
933
|
+
}
|
|
934
|
+
function getEnumMemberName(name) {
|
|
935
|
+
if (ts.isIdentifier(name)) {
|
|
936
|
+
return getSafeName(name.text);
|
|
937
|
+
}
|
|
938
|
+
if (ts.isStringLiteral(name) || ts.isNumericLiteral(name)) {
|
|
939
|
+
const sanitized = name.text.replace(/[^a-zA-Z0-9_]/g, '_');
|
|
940
|
+
return sanitized.length > 0 ? sanitized : 'Member';
|
|
941
|
+
}
|
|
942
|
+
return 'Member';
|
|
943
|
+
}
|
|
944
|
+
function getEnumBaseType(node) {
|
|
945
|
+
for (const member of node.members) {
|
|
946
|
+
const initializer = member.initializer;
|
|
947
|
+
if (!initializer)
|
|
948
|
+
continue;
|
|
949
|
+
if (ts.isStringLiteral(initializer) || ts.isNoSubstitutionTemplateLiteral(initializer)) {
|
|
950
|
+
return 'string';
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
return 'float64';
|
|
954
|
+
}
|
|
955
|
+
function readNumericEnumInitializer(initializer) {
|
|
956
|
+
if (ts.isNumericLiteral(initializer)) {
|
|
957
|
+
return Number(initializer.text);
|
|
958
|
+
}
|
|
959
|
+
if (ts.isPrefixUnaryExpression(initializer) &&
|
|
960
|
+
initializer.operator === ts.SyntaxKind.MinusToken &&
|
|
961
|
+
ts.isNumericLiteral(initializer.operand)) {
|
|
962
|
+
return -Number(initializer.operand.text);
|
|
963
|
+
}
|
|
964
|
+
return undefined;
|
|
965
|
+
}
|
|
966
|
+
function visitEnumDeclaration(node) {
|
|
967
|
+
const enumName = getSafeName(node.name.text);
|
|
968
|
+
const baseType = enumBaseTypes.get(node.name.text) ?? getEnumBaseType(node);
|
|
969
|
+
let nextNumericValue = 0;
|
|
970
|
+
let canAutoIncrement = true;
|
|
971
|
+
const members = [];
|
|
972
|
+
for (const member of node.members) {
|
|
973
|
+
const memberName = getEnumMemberName(member.name);
|
|
974
|
+
const symbolName = `${enumName}_${memberName}`;
|
|
975
|
+
let valueExpr;
|
|
976
|
+
if (member.initializer) {
|
|
977
|
+
if (baseType === 'float64') {
|
|
978
|
+
const numericValue = readNumericEnumInitializer(member.initializer);
|
|
979
|
+
if (numericValue !== undefined) {
|
|
980
|
+
valueExpr = `${numericValue}`;
|
|
981
|
+
nextNumericValue = numericValue + 1;
|
|
982
|
+
canAutoIncrement = true;
|
|
983
|
+
}
|
|
984
|
+
else {
|
|
985
|
+
valueExpr = `float64(${visit(member.initializer)})`;
|
|
986
|
+
canAutoIncrement = false;
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
else {
|
|
990
|
+
valueExpr = visit(member.initializer);
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
else if (baseType === 'float64') {
|
|
994
|
+
const currentValue = canAutoIncrement ? nextNumericValue : 0;
|
|
995
|
+
valueExpr = `${currentValue}`;
|
|
996
|
+
nextNumericValue = currentValue + 1;
|
|
997
|
+
}
|
|
998
|
+
else {
|
|
999
|
+
valueExpr = toGoStringLiteral(memberName);
|
|
1000
|
+
}
|
|
1001
|
+
members.push(`\t${symbolName} ${enumName} = ${enumName}(${valueExpr})`);
|
|
1002
|
+
}
|
|
1003
|
+
return `type ${enumName} ${baseType}\n\nvar (\n${members.join('\n')}\n)`;
|
|
1004
|
+
}
|
|
411
1005
|
function getType(typeNode, getArrayType = false) {
|
|
412
1006
|
if (!typeNode)
|
|
413
1007
|
return ':';
|
|
1008
|
+
if (ts.isArrayTypeNode(typeNode)) {
|
|
1009
|
+
const elementType = getType(typeNode.elementType);
|
|
1010
|
+
return getArrayType ? elementType : `[]${elementType}`;
|
|
1011
|
+
}
|
|
414
1012
|
// Handle union types (e.g. string | null, number | undefined)
|
|
415
1013
|
if (ts.isUnionTypeNode(typeNode)) {
|
|
416
1014
|
const nonNullTypes = typeNode.types.filter((t) => t.kind !== ts.SyntaxKind.NullKeyword &&
|
|
@@ -430,6 +1028,13 @@ function getType(typeNode, getArrayType = false) {
|
|
|
430
1028
|
}
|
|
431
1029
|
if (ts.isTypeReferenceNode(typeNode) && ts.isIdentifier(typeNode.typeName)) {
|
|
432
1030
|
const name = typeNode.typeName.text;
|
|
1031
|
+
if (enumNames.has(name)) {
|
|
1032
|
+
return getSafeName(name);
|
|
1033
|
+
}
|
|
1034
|
+
const aliasType = getAliasType(name);
|
|
1035
|
+
if (aliasType) {
|
|
1036
|
+
return getType(aliasType, getArrayType);
|
|
1037
|
+
}
|
|
433
1038
|
if (name === 'Promise' && typeNode.typeArguments && typeNode.typeArguments.length > 0) {
|
|
434
1039
|
return `chan ${getType(typeNode.typeArguments[0])}`;
|
|
435
1040
|
}
|
|
@@ -492,6 +1097,20 @@ function getTypeCategory(typeNode) {
|
|
|
492
1097
|
}
|
|
493
1098
|
return undefined;
|
|
494
1099
|
}
|
|
1100
|
+
function getClassNameFromTypeNode(typeNode) {
|
|
1101
|
+
if (ts.isTypeReferenceNode(typeNode) && ts.isIdentifier(typeNode.typeName)) {
|
|
1102
|
+
return classNames.has(typeNode.typeName.text) ? typeNode.typeName.text : undefined;
|
|
1103
|
+
}
|
|
1104
|
+
if (ts.isUnionTypeNode(typeNode)) {
|
|
1105
|
+
const nonNullTypes = typeNode.types.filter((t) => t.kind !== ts.SyntaxKind.NullKeyword &&
|
|
1106
|
+
t.kind !== ts.SyntaxKind.UndefinedKeyword &&
|
|
1107
|
+
!(ts.isLiteralTypeNode(t) && t.literal.kind === ts.SyntaxKind.NullKeyword));
|
|
1108
|
+
if (nonNullTypes.length === 1) {
|
|
1109
|
+
return getClassNameFromTypeNode(nonNullTypes[0]);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
return undefined;
|
|
1113
|
+
}
|
|
495
1114
|
function resolveExpressionType(expr) {
|
|
496
1115
|
if (ts.isIdentifier(expr)) {
|
|
497
1116
|
return variableTypes.get(expr.text);
|
|
@@ -772,6 +1391,59 @@ function getTypeArguments(typeArguments) {
|
|
|
772
1391
|
const args = typeArguments.map((ta) => getType(ta));
|
|
773
1392
|
return `[${args.join(', ')}]`;
|
|
774
1393
|
}
|
|
1394
|
+
function getParameterGoType(param) {
|
|
1395
|
+
if (param.type) {
|
|
1396
|
+
const explicitType = getType(param.type);
|
|
1397
|
+
return explicitType === ':' ? 'interface{}' : explicitType;
|
|
1398
|
+
}
|
|
1399
|
+
if (param.initializer) {
|
|
1400
|
+
const inferredType = inferExpressionType(param.initializer);
|
|
1401
|
+
if (inferredType && inferredType !== 'nil' && inferredType !== ':') {
|
|
1402
|
+
return inferredType;
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
return 'interface{}';
|
|
1406
|
+
}
|
|
1407
|
+
function getFunctionParametersInfo(parameters) {
|
|
1408
|
+
if (parameters.length === 0) {
|
|
1409
|
+
return { signature: '', prefixBlockContent: '' };
|
|
1410
|
+
}
|
|
1411
|
+
const firstDefaultIndex = parameters.findIndex((p) => !!p.initializer);
|
|
1412
|
+
if (firstDefaultIndex === -1) {
|
|
1413
|
+
return {
|
|
1414
|
+
signature: parameters.map((p) => `${visit(p.name)} ${getParameterGoType(p)}`).join(', '),
|
|
1415
|
+
prefixBlockContent: ''
|
|
1416
|
+
};
|
|
1417
|
+
}
|
|
1418
|
+
const hasRequiredAfterDefault = parameters
|
|
1419
|
+
.slice(firstDefaultIndex)
|
|
1420
|
+
.some((p) => !p.initializer);
|
|
1421
|
+
if (hasRequiredAfterDefault) {
|
|
1422
|
+
return {
|
|
1423
|
+
signature: parameters.map((p) => `${visit(p.name)} ${getParameterGoType(p)}`).join(', '),
|
|
1424
|
+
prefixBlockContent: ''
|
|
1425
|
+
};
|
|
1426
|
+
}
|
|
1427
|
+
const requiredParams = parameters.slice(0, firstDefaultIndex);
|
|
1428
|
+
const defaultedParams = parameters.slice(firstDefaultIndex);
|
|
1429
|
+
const signatureParts = requiredParams.map((p) => `${visit(p.name)} ${getParameterGoType(p)}`);
|
|
1430
|
+
signatureParts.push('__defaultArgs ...interface{}');
|
|
1431
|
+
const prefixBlockContent = defaultedParams
|
|
1432
|
+
.map((param, index) => {
|
|
1433
|
+
const paramName = visit(param.name);
|
|
1434
|
+
const paramType = getParameterGoType(param);
|
|
1435
|
+
const defaultValue = visit(param.initializer);
|
|
1436
|
+
if (paramType === 'interface{}') {
|
|
1437
|
+
return `var ${paramName} interface{}\n\t\tif len(__defaultArgs) > ${index} {\n\t\t\t${paramName} = __defaultArgs[${index}]\n\t\t} else {\n\t\t\t${paramName} = ${defaultValue}\n\t\t}\n\t\t`;
|
|
1438
|
+
}
|
|
1439
|
+
return `var ${paramName} ${paramType}\n\t\tif len(__defaultArgs) > ${index} {\n\t\t\t${paramName} = __defaultArgs[${index}].(${paramType})\n\t\t} else {\n\t\t\t${paramName} = ${defaultValue}\n\t\t}\n\t\t`;
|
|
1440
|
+
})
|
|
1441
|
+
.join('');
|
|
1442
|
+
return {
|
|
1443
|
+
signature: signatureParts.join(', '),
|
|
1444
|
+
prefixBlockContent
|
|
1445
|
+
};
|
|
1446
|
+
}
|
|
775
1447
|
function getSafeName(name) {
|
|
776
1448
|
if (!dangerousNames.has(name)) {
|
|
777
1449
|
return name;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "typenative",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.17",
|
|
4
4
|
"description": "Build native applications using Typescript.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -25,7 +25,13 @@
|
|
|
25
25
|
"test11": "node ./bin/index --source test/test11.spec.ts --script",
|
|
26
26
|
"test12": "node ./bin/index --source test/test12.spec.ts --script",
|
|
27
27
|
"test13": "node ./bin/index --source test/test13.spec.ts --script",
|
|
28
|
-
"test14": "node ./bin/index --source test/test14.spec.ts --script"
|
|
28
|
+
"test14": "node ./bin/index --source test/test14.spec.ts --script",
|
|
29
|
+
"test15": "node ./bin/index --source test/test15.spec.ts --script",
|
|
30
|
+
"test16": "node ./bin/index --source test/test16.spec.ts --script",
|
|
31
|
+
"test17": "node ./bin/index --source test/test17.spec.ts --script",
|
|
32
|
+
"test18": "node ./bin/index --source test/test18.spec.ts --script",
|
|
33
|
+
"test19": "node ./bin/index --source test/test19.spec.ts --script",
|
|
34
|
+
"test20": "node ./bin/index --source test/Test20.spec.ts --script"
|
|
29
35
|
},
|
|
30
36
|
"repository": {
|
|
31
37
|
"type": "git",
|
package/types/typenative.d.ts
CHANGED
|
@@ -81,6 +81,22 @@ interface Array<T> extends IterableIterator<T> {
|
|
|
81
81
|
* Returns a copy of a section of an array.
|
|
82
82
|
*/
|
|
83
83
|
slice(start?: number, end?: number): T[];
|
|
84
|
+
/**
|
|
85
|
+
* Calls a defined callback function on each element of an array, and returns an array that contains the results.
|
|
86
|
+
*/
|
|
87
|
+
map<U>(callback: (value: T, index?: number, array?: T[]) => U): U[];
|
|
88
|
+
/**
|
|
89
|
+
* Returns the elements of an array that meet the condition specified in a callback function.
|
|
90
|
+
*/
|
|
91
|
+
filter(callback: (value: T, index?: number, array?: T[]) => boolean): T[];
|
|
92
|
+
/**
|
|
93
|
+
* Determines whether the specified callback function returns true for any element of an array.
|
|
94
|
+
*/
|
|
95
|
+
some(callback: (value: T, index?: number, array?: T[]) => boolean): boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Returns the value of the first element in the array where callback is true, and undefined otherwise.
|
|
98
|
+
*/
|
|
99
|
+
find(callback: (value: T, index?: number, array?: T[]) => boolean): T | undefined;
|
|
84
100
|
/**
|
|
85
101
|
* Returns the index of the first occurrence of a value in an array, or -1 if it is not present.
|
|
86
102
|
*/
|