typenative 0.0.13 → 0.0.15
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/.github/workflows/npm-publish-github-packages.yml +36 -0
- package/CHANGELOG.md +44 -0
- package/README.md +1 -1
- package/bin/index.js +1 -1
- package/bin/transpiler.js +765 -245
- package/package.json +26 -22
- package/types/typenative.d.ts +117 -1
package/bin/transpiler.js
CHANGED
|
@@ -1,14 +1,25 @@
|
|
|
1
|
-
import ts from 'typescript';
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
let
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
import { customAlphabet } from 'nanoid';
|
|
3
|
+
const goSafeId = customAlphabet('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', 8);
|
|
4
|
+
let TypeCheker;
|
|
5
|
+
const importedPackages = new Set();
|
|
6
|
+
let outsideNodes = [];
|
|
7
|
+
const classNames = new Set();
|
|
8
|
+
let promiseResolveName = '';
|
|
9
|
+
const dangerousNames = new Set(['main']);
|
|
10
|
+
const renamedFunctions = new Map();
|
|
11
|
+
const variableTypes = new Map();
|
|
12
|
+
export function transpileToNative(code) {
|
|
13
|
+
const sourceFile = ts.createSourceFile('main.ts', code, ts.ScriptTarget.ES2020, true, ts.ScriptKind.TS);
|
|
14
|
+
TypeCheker = ts.createProgram(['main.ts'], {}).getTypeChecker();
|
|
15
|
+
importedPackages.clear();
|
|
16
|
+
outsideNodes = [];
|
|
17
|
+
classNames.clear();
|
|
18
|
+
promiseResolveName = '';
|
|
19
|
+
renamedFunctions.clear();
|
|
20
|
+
variableTypes.clear();
|
|
21
|
+
const transpiledCode = visit(sourceFile, { addFunctionOutside: true });
|
|
22
|
+
const transpiledCodeOutside = outsideNodes.map((n) => visit(n, { isOutside: true })).join('\n');
|
|
12
23
|
return `package main
|
|
13
24
|
|
|
14
25
|
${[...importedPackages].map((pkg) => `import "${pkg}"`).join('\n')}
|
|
@@ -17,237 +28,746 @@ func main() {
|
|
|
17
28
|
${transpiledCode.trim()}
|
|
18
29
|
}
|
|
19
30
|
|
|
20
|
-
${transpiledCodeOutside.trim()}`;
|
|
21
|
-
}
|
|
22
|
-
export function visit(node, options = {}) {
|
|
23
|
-
let code = '';
|
|
24
|
-
if (ts.isSourceFile(node)) {
|
|
25
|
-
return node.statements
|
|
26
|
-
.map((n) => visit(n, { addFunctionOutside: true }))
|
|
27
|
-
.filter((n) => !!n)
|
|
28
|
-
.join(options.inline ? '' : '\n\t');
|
|
29
|
-
}
|
|
30
|
-
else if (ts.isIdentifier(node)) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return
|
|
59
|
-
}
|
|
60
|
-
else if (ts.
|
|
61
|
-
const
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
else if (ts.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
return
|
|
116
|
-
}
|
|
117
|
-
else if (ts.
|
|
118
|
-
return
|
|
119
|
-
}
|
|
120
|
-
else if (ts.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
return
|
|
217
|
-
}
|
|
218
|
-
else if (
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
}
|
|
31
|
+
${transpiledCodeOutside.trim()}`;
|
|
32
|
+
}
|
|
33
|
+
export function visit(node, options = {}) {
|
|
34
|
+
let code = '';
|
|
35
|
+
if (ts.isSourceFile(node)) {
|
|
36
|
+
return node.statements
|
|
37
|
+
.map((n) => visit(n, { addFunctionOutside: true }))
|
|
38
|
+
.filter((n) => !!n)
|
|
39
|
+
.join(options.inline ? '' : '\n\t');
|
|
40
|
+
}
|
|
41
|
+
else if (ts.isIdentifier(node)) {
|
|
42
|
+
if (node.text === 'undefined')
|
|
43
|
+
return 'nil';
|
|
44
|
+
return getSafeName(node.text);
|
|
45
|
+
}
|
|
46
|
+
else if (ts.isStringLiteral(node)) {
|
|
47
|
+
return `"${node.text}"`;
|
|
48
|
+
}
|
|
49
|
+
else if (ts.isNumericLiteral(node)) {
|
|
50
|
+
return `float64(${node.text})`;
|
|
51
|
+
}
|
|
52
|
+
else if (ts.isToken(node) && node.kind === ts.SyntaxKind.TrueKeyword) {
|
|
53
|
+
return `true`;
|
|
54
|
+
}
|
|
55
|
+
else if (ts.isToken(node) && node.kind === ts.SyntaxKind.FalseKeyword) {
|
|
56
|
+
return `false`;
|
|
57
|
+
}
|
|
58
|
+
else if (ts.isToken(node) && node.kind === ts.SyntaxKind.NullKeyword) {
|
|
59
|
+
return `nil`;
|
|
60
|
+
}
|
|
61
|
+
else if (ts.isArrayLiteralExpression(node)) {
|
|
62
|
+
const type = ts.isVariableDeclaration(node.parent) ? getType(node.parent.type, true) : '';
|
|
63
|
+
return `[]${type} {${node.elements.map((e) => visit(e)).join(', ')}}`;
|
|
64
|
+
}
|
|
65
|
+
else if (ts.isBlock(node)) {
|
|
66
|
+
return `{\n\t\t${node.statements.map((n) => visit(n)).join('\t')}${options.extraBlockContent ?? ''}}${options.inline ? '' : '\n\t'}`;
|
|
67
|
+
}
|
|
68
|
+
else if (ts.isElementAccessExpression(node)) {
|
|
69
|
+
return `${visit(node.expression)}[int(${visit(node.argumentExpression)})]`;
|
|
70
|
+
}
|
|
71
|
+
else if (ts.isPropertyAccessExpression(node)) {
|
|
72
|
+
const leftSide = visit(node.expression);
|
|
73
|
+
const rightSide = visit(node.name);
|
|
74
|
+
const objectType = resolveExpressionType(node.expression);
|
|
75
|
+
return getAcessString(leftSide, rightSide, objectType);
|
|
76
|
+
}
|
|
77
|
+
else if (ts.isVariableDeclaration(node)) {
|
|
78
|
+
const type = getType(node.type);
|
|
79
|
+
// Track variable type for type-aware method dispatch
|
|
80
|
+
if (ts.isIdentifier(node.name)) {
|
|
81
|
+
const cat = node.type ? getTypeCategory(node.type) : undefined;
|
|
82
|
+
if (cat) {
|
|
83
|
+
variableTypes.set(node.name.text, cat);
|
|
84
|
+
}
|
|
85
|
+
else if (node.initializer &&
|
|
86
|
+
ts.isNewExpression(node.initializer) &&
|
|
87
|
+
ts.isIdentifier(node.initializer.expression)) {
|
|
88
|
+
if (classNames.has(node.initializer.expression.text)) {
|
|
89
|
+
variableTypes.set(node.name.text, 'class');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
let initializer = node.initializer ? `= ${visit(node.initializer)}` : '';
|
|
94
|
+
// Wrap non-nil values assigned to nullable primitive pointer types
|
|
95
|
+
// Only wrap for primitive pointers (*string, *float64, *bool), not class pointers
|
|
96
|
+
if (node.initializer &&
|
|
97
|
+
type.startsWith('*') &&
|
|
98
|
+
!isNilLiteral(node.initializer) &&
|
|
99
|
+
['*string', '*float64', '*bool'].includes(type)) {
|
|
100
|
+
const value = visit(node.initializer);
|
|
101
|
+
initializer = `= func() ${type} { v := ${value}; return &v }()`;
|
|
102
|
+
}
|
|
103
|
+
return `${type === ':' ? '' : 'var '}${visit(node.name)} ${type}${type === ':' ? '' : ' '}${initializer}`;
|
|
104
|
+
}
|
|
105
|
+
else if (ts.isCallExpression(node)) {
|
|
106
|
+
// Handle setTimeout specially to get raw delay value
|
|
107
|
+
if (ts.isIdentifier(node.expression) && node.expression.text === 'setTimeout') {
|
|
108
|
+
importedPackages.add('time');
|
|
109
|
+
const callback = visit(node.arguments[0]);
|
|
110
|
+
const delayNode = node.arguments[1];
|
|
111
|
+
const delay = ts.isNumericLiteral(delayNode) ? delayNode.text : visit(delayNode);
|
|
112
|
+
return `time.AfterFunc(${delay} * time.Millisecond, ${callback.trimEnd()})`;
|
|
113
|
+
}
|
|
114
|
+
const caller = visit(node.expression);
|
|
115
|
+
const safeCaller = getSafeName(caller);
|
|
116
|
+
const typeArgs = getTypeArguments(node.typeArguments);
|
|
117
|
+
const args = node.arguments.map((a) => visit(a));
|
|
118
|
+
// Resolve object type for type-aware method dispatch
|
|
119
|
+
let objectType;
|
|
120
|
+
if (ts.isPropertyAccessExpression(node.expression)) {
|
|
121
|
+
objectType = resolveExpressionType(node.expression.expression);
|
|
122
|
+
}
|
|
123
|
+
return getCallString(safeCaller, args, typeArgs, objectType);
|
|
124
|
+
}
|
|
125
|
+
else if (ts.isPrefixUnaryExpression(node)) {
|
|
126
|
+
return `${getOperatorText(node.operator)}${visit(node.operand)}`;
|
|
127
|
+
}
|
|
128
|
+
else if (ts.isPostfixUnaryExpression(node)) {
|
|
129
|
+
return `${visit(node.operand, { inline: true })}${getOperatorText(node.operator)}`;
|
|
130
|
+
}
|
|
131
|
+
else if (ts.isBinaryExpression(node)) {
|
|
132
|
+
let op = node.operatorToken.getText();
|
|
133
|
+
if (op === '===')
|
|
134
|
+
op = '==';
|
|
135
|
+
if (op === '!==')
|
|
136
|
+
op = '!=';
|
|
137
|
+
return `${visit(node.left)} ${op} ${visit(node.right)}`;
|
|
138
|
+
}
|
|
139
|
+
else if (ts.isParenthesizedExpression(node)) {
|
|
140
|
+
return `(${visit(node.expression)})`;
|
|
141
|
+
}
|
|
142
|
+
else if (ts.isAwaitExpression(node)) {
|
|
143
|
+
return `<-${visit(node.expression)}`;
|
|
144
|
+
}
|
|
145
|
+
else if (ts.isVariableDeclarationList(node)) {
|
|
146
|
+
return (node.declarations.map((n) => visit(n)).join(options.inline ? ';' : ';\n\t') +
|
|
147
|
+
(options.inline ? '' : ';\n\t'));
|
|
148
|
+
}
|
|
149
|
+
else if (ts.isExpressionStatement(node)) {
|
|
150
|
+
return visit(node.expression) + (options.inline ? '' : ';\n\t');
|
|
151
|
+
}
|
|
152
|
+
else if (ts.isForStatement(node)) {
|
|
153
|
+
return `for ${visit(node.initializer, { inline: true })}; ${visit(node.condition, {
|
|
154
|
+
inline: true
|
|
155
|
+
})}; ${visit(node.incrementor, { inline: true })}${visit(node.statement)}`;
|
|
156
|
+
}
|
|
157
|
+
else if (ts.isForOfStatement(node)) {
|
|
158
|
+
return `for _,${visit(node.initializer, { inline: true })}= range ${visit(node.expression, {
|
|
159
|
+
inline: true
|
|
160
|
+
})}${visit(node.statement)}`;
|
|
161
|
+
}
|
|
162
|
+
else if (ts.isWhileStatement(node)) {
|
|
163
|
+
return `for ${visit(node.expression, { inline: true })}${visit(node.statement)}`;
|
|
164
|
+
}
|
|
165
|
+
else if (ts.isDoStatement(node)) {
|
|
166
|
+
const condition = `\tif !(${visit(node.expression, {
|
|
167
|
+
inline: true
|
|
168
|
+
})}) {\n\t\t\tbreak \n\t\t}\n\t`;
|
|
169
|
+
return `for ${visit(node.statement, { inline: true, extraBlockContent: condition })}`;
|
|
170
|
+
}
|
|
171
|
+
else if (ts.isIfStatement(node)) {
|
|
172
|
+
const condition = `if ${visit(node.expression, { inline: true })} ${visit(node.thenStatement, {
|
|
173
|
+
inline: !!node.elseStatement
|
|
174
|
+
})}`;
|
|
175
|
+
if (node.elseStatement) {
|
|
176
|
+
return `${condition} else ${visit(node.elseStatement)}`;
|
|
177
|
+
}
|
|
178
|
+
return condition;
|
|
179
|
+
}
|
|
180
|
+
else if (ts.isSwitchStatement(node)) {
|
|
181
|
+
return `switch ${visit(node.expression)} ${visit(node.caseBlock)}`;
|
|
182
|
+
}
|
|
183
|
+
else if (ts.isCaseBlock(node)) {
|
|
184
|
+
return `{\n\t\t${node.clauses.map((c) => visit(c)).join('\n\t\t')}\n\t}`;
|
|
185
|
+
}
|
|
186
|
+
else if (ts.isCaseClause(node)) {
|
|
187
|
+
const isFallThrough = !node.statements.some((c) => ts.isBreakStatement(c));
|
|
188
|
+
return `case ${visit(node.expression, { inline: true })}: \n\t\t\t${node.statements
|
|
189
|
+
.filter((n) => !ts.isBreakStatement(n))
|
|
190
|
+
.map((s) => visit(s))
|
|
191
|
+
.join('')}${isFallThrough ? 'fallthrough\n\t' : ''}`;
|
|
192
|
+
}
|
|
193
|
+
else if (ts.isDefaultClause(node)) {
|
|
194
|
+
return `default: \n\t\t\t${node.statements
|
|
195
|
+
.filter((n) => !ts.isBreakStatement(n))
|
|
196
|
+
.map((s) => visit(s))
|
|
197
|
+
.join('')}`;
|
|
198
|
+
}
|
|
199
|
+
else if (ts.isBreakStatement(node)) {
|
|
200
|
+
return 'break';
|
|
201
|
+
}
|
|
202
|
+
else if (ts.isReturnStatement(node)) {
|
|
203
|
+
// Handle return new Promise(...)
|
|
204
|
+
if (node.expression &&
|
|
205
|
+
ts.isNewExpression(node.expression) &&
|
|
206
|
+
ts.isIdentifier(node.expression.expression) &&
|
|
207
|
+
node.expression.expression.text === 'Promise') {
|
|
208
|
+
return visitPromiseReturn(node.expression, options);
|
|
209
|
+
}
|
|
210
|
+
return (`return ${node.expression ? visit(node.expression) : ''}` + (options.inline ? '' : ';\n\t'));
|
|
211
|
+
}
|
|
212
|
+
else if (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node)) {
|
|
213
|
+
if (options.addFunctionOutside) {
|
|
214
|
+
outsideNodes.push(node);
|
|
215
|
+
return '';
|
|
216
|
+
}
|
|
217
|
+
const name = visit(node.name, { inline: true });
|
|
218
|
+
const safeName = getSafeName(name);
|
|
219
|
+
const typeParams = getTypeParameters(node.typeParameters);
|
|
220
|
+
const parameters = node.parameters
|
|
221
|
+
.map((p) => `${visit(p.name)} ${getType(p.type)}`)
|
|
222
|
+
.join(', ');
|
|
223
|
+
const returnType = node.type ? ` ${getType(node.type)}` : '';
|
|
224
|
+
if (options.isOutside) {
|
|
225
|
+
return `func ${safeName}${typeParams}(${parameters})${returnType} ${visit(node.body)}`;
|
|
226
|
+
}
|
|
227
|
+
return `${safeName} := func${typeParams}(${parameters})${returnType} ${visit(node.body)}`;
|
|
228
|
+
}
|
|
229
|
+
else if (ts.isArrowFunction(node)) {
|
|
230
|
+
const parameters = node.parameters
|
|
231
|
+
.map((p) => `${visit(p.name)} ${getType(p.type)}`)
|
|
232
|
+
.join(', ');
|
|
233
|
+
const returnType = node.type ? ` ${getType(node.type)}` : '';
|
|
234
|
+
return `func(${parameters})${returnType} ${visit(node.body)}`;
|
|
235
|
+
}
|
|
236
|
+
else if (node.kind === ts.SyntaxKind.ThisKeyword) {
|
|
237
|
+
return 'self';
|
|
238
|
+
}
|
|
239
|
+
else if (ts.isInterfaceDeclaration(node)) {
|
|
240
|
+
if (options.addFunctionOutside) {
|
|
241
|
+
outsideNodes.push(node);
|
|
242
|
+
return '';
|
|
243
|
+
}
|
|
244
|
+
const name = visit(node.name);
|
|
245
|
+
const typeParams = getTypeParameters(node.typeParameters);
|
|
246
|
+
const extendedInterfaces = [];
|
|
247
|
+
if (node.heritageClauses) {
|
|
248
|
+
for (const clause of node.heritageClauses) {
|
|
249
|
+
if (clause.token === ts.SyntaxKind.ExtendsKeyword) {
|
|
250
|
+
for (const type of clause.types) {
|
|
251
|
+
extendedInterfaces.push(visit(type.expression));
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
const methods = [];
|
|
257
|
+
for (const member of node.members) {
|
|
258
|
+
if (ts.isMethodSignature(member)) {
|
|
259
|
+
const methodName = visit(member.name);
|
|
260
|
+
const params = member.parameters
|
|
261
|
+
.map((p) => `${visit(p.name)} ${getType(p.type)}`)
|
|
262
|
+
.join(', ');
|
|
263
|
+
const returnType = member.type ? ` ${getType(member.type)}` : '';
|
|
264
|
+
methods.push(`\t${methodName}(${params})${returnType}`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
const members = [...extendedInterfaces.map((e) => `\t${e}`), ...methods];
|
|
268
|
+
return `type ${name}${typeParams} interface {\n${members.join('\n')}\n}`;
|
|
269
|
+
}
|
|
270
|
+
else if (ts.isClassDeclaration(node)) {
|
|
271
|
+
if (options.addFunctionOutside) {
|
|
272
|
+
outsideNodes.push(node);
|
|
273
|
+
classNames.add(visit(node.name));
|
|
274
|
+
return '';
|
|
275
|
+
}
|
|
276
|
+
const name = visit(node.name);
|
|
277
|
+
const typeParams = getTypeParameters(node.typeParameters);
|
|
278
|
+
const typeParamNames = getTypeParameterNames(node.typeParameters);
|
|
279
|
+
let parentClass = null;
|
|
280
|
+
if (node.heritageClauses) {
|
|
281
|
+
for (const clause of node.heritageClauses) {
|
|
282
|
+
if (clause.token === ts.SyntaxKind.ExtendsKeyword) {
|
|
283
|
+
parentClass = visit(clause.types[0].expression);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
const fields = [];
|
|
288
|
+
if (parentClass) {
|
|
289
|
+
fields.push(`\t${parentClass}`);
|
|
290
|
+
}
|
|
291
|
+
for (const member of node.members) {
|
|
292
|
+
if (ts.isPropertyDeclaration(member)) {
|
|
293
|
+
const fieldName = visit(member.name);
|
|
294
|
+
let fieldType;
|
|
295
|
+
if (member.type && ts.isArrayTypeNode(member.type)) {
|
|
296
|
+
fieldType = `[]${getType(member.type, true)}`;
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
fieldType = member.type ? getType(member.type) : 'interface{}';
|
|
300
|
+
}
|
|
301
|
+
fields.push(`\t${fieldName} ${fieldType}`);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
let result = `type ${name}${typeParams} struct {\n${fields.join('\n')}\n}\n\n`;
|
|
305
|
+
const ctor = node.members.find((m) => ts.isConstructorDeclaration(m));
|
|
306
|
+
if (ctor) {
|
|
307
|
+
const params = ctor.parameters.map((p) => `${visit(p.name)} ${getType(p.type)}`).join(', ');
|
|
308
|
+
const bodyStatements = ctor.body?.statements
|
|
309
|
+
.filter((s) => {
|
|
310
|
+
if (ts.isExpressionStatement(s) && ts.isCallExpression(s.expression)) {
|
|
311
|
+
return s.expression.expression.kind !== ts.SyntaxKind.SuperKeyword;
|
|
312
|
+
}
|
|
313
|
+
return true;
|
|
314
|
+
})
|
|
315
|
+
.map((s) => visit(s))
|
|
316
|
+
.join('\t') ?? '';
|
|
317
|
+
result += `func New${name}${typeParams}(${params}) *${name}${typeParamNames} {\n\t\tself := &${name}${typeParamNames}{}\n\t\t${bodyStatements}return self;\n\t}\n\n`;
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
result += `func New${name}${typeParams}() *${name}${typeParamNames} {\n\t\treturn &${name}${typeParamNames}{}\n\t}\n\n`;
|
|
321
|
+
}
|
|
322
|
+
for (const member of node.members) {
|
|
323
|
+
if (ts.isMethodDeclaration(member)) {
|
|
324
|
+
const methodName = visit(member.name);
|
|
325
|
+
const params = member.parameters
|
|
326
|
+
.map((p) => `${visit(p.name)} ${getType(p.type)}`)
|
|
327
|
+
.join(', ');
|
|
328
|
+
const returnType = member.type ? ` ${getType(member.type)}` : '';
|
|
329
|
+
result += `func (self *${name}${typeParamNames}) ${methodName}(${params})${returnType} ${visit(member.body)}\n\n`;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return result.trim();
|
|
333
|
+
}
|
|
334
|
+
else if (ts.isNewExpression(node)) {
|
|
335
|
+
const className = visit(node.expression);
|
|
336
|
+
if (className === 'Promise') {
|
|
337
|
+
return visitNewPromise(node);
|
|
338
|
+
}
|
|
339
|
+
const typeArgs = getTypeArguments(node.typeArguments);
|
|
340
|
+
const args = node.arguments ? node.arguments.map((a) => visit(a)) : [];
|
|
341
|
+
return `New${className}${typeArgs}(${args.join(', ')})`;
|
|
342
|
+
}
|
|
343
|
+
else if (ts.isObjectLiteralExpression(node)) {
|
|
344
|
+
let typeName = '';
|
|
345
|
+
if (ts.isVariableDeclaration(node.parent) && node.parent.type) {
|
|
346
|
+
typeName = getTypeText(node.parent.type);
|
|
347
|
+
}
|
|
348
|
+
const properties = node.properties
|
|
349
|
+
.map((p) => {
|
|
350
|
+
if (ts.isPropertyAssignment(p)) {
|
|
351
|
+
return `${visit(p.name)}: ${visit(p.initializer)}`;
|
|
352
|
+
}
|
|
353
|
+
return '';
|
|
354
|
+
})
|
|
355
|
+
.filter((p) => p)
|
|
356
|
+
.join(', ');
|
|
357
|
+
return `${typeName}{${properties}}`;
|
|
358
|
+
}
|
|
359
|
+
else if (ts.isPropertyAssignment(node)) {
|
|
360
|
+
return `${visit(node.name)}: ${visit(node.initializer)}`;
|
|
361
|
+
}
|
|
362
|
+
else if (ts.isNonNullExpression(node)) {
|
|
363
|
+
return visit(node.expression);
|
|
364
|
+
}
|
|
365
|
+
const syntaxKind = ts.SyntaxKind[node.kind];
|
|
366
|
+
if (!['FirstStatement', 'EndOfFileToken'].includes(syntaxKind)) {
|
|
367
|
+
console.log(ts.SyntaxKind[node.kind], node.getText());
|
|
368
|
+
}
|
|
369
|
+
ts.forEachChild(node, (subNode) => {
|
|
370
|
+
code += visit(subNode);
|
|
371
|
+
});
|
|
372
|
+
return code;
|
|
373
|
+
}
|
|
374
|
+
function getTypeText(typeNode) {
|
|
375
|
+
if (!typeNode)
|
|
376
|
+
return ':';
|
|
377
|
+
if (ts.isTypeReferenceNode(typeNode) && ts.isIdentifier(typeNode.typeName)) {
|
|
378
|
+
return typeNode.typeName.text;
|
|
379
|
+
}
|
|
380
|
+
return getType(typeNode);
|
|
381
|
+
}
|
|
382
|
+
function getType(typeNode, getArrayType = false) {
|
|
383
|
+
if (!typeNode)
|
|
384
|
+
return ':';
|
|
385
|
+
// Handle union types (e.g. string | null, number | undefined)
|
|
386
|
+
if (ts.isUnionTypeNode(typeNode)) {
|
|
387
|
+
const nonNullTypes = typeNode.types.filter((t) => t.kind !== ts.SyntaxKind.NullKeyword &&
|
|
388
|
+
t.kind !== ts.SyntaxKind.UndefinedKeyword &&
|
|
389
|
+
!(ts.isLiteralTypeNode(t) && t.literal.kind === ts.SyntaxKind.NullKeyword));
|
|
390
|
+
if (nonNullTypes.length === 1 && nonNullTypes.length < typeNode.types.length) {
|
|
391
|
+
// This is a nullable type T | null or T | undefined
|
|
392
|
+
const innerType = getType(nonNullTypes[0]);
|
|
393
|
+
if (['float64', 'string', 'bool'].includes(innerType)) {
|
|
394
|
+
return `*${innerType}`;
|
|
395
|
+
}
|
|
396
|
+
// Pointer/interface types already support nil
|
|
397
|
+
return innerType;
|
|
398
|
+
}
|
|
399
|
+
// Non-nullable union or multi-type union → interface{}
|
|
400
|
+
return 'interface{}';
|
|
401
|
+
}
|
|
402
|
+
if (ts.isTypeReferenceNode(typeNode) && ts.isIdentifier(typeNode.typeName)) {
|
|
403
|
+
const name = typeNode.typeName.text;
|
|
404
|
+
if (name === 'Promise' && typeNode.typeArguments && typeNode.typeArguments.length > 0) {
|
|
405
|
+
return `chan ${getType(typeNode.typeArguments[0])}`;
|
|
406
|
+
}
|
|
407
|
+
const typeArgs = getTypeArguments(typeNode.typeArguments);
|
|
408
|
+
if (classNames.has(name)) {
|
|
409
|
+
return `*${name}${typeArgs}`;
|
|
410
|
+
}
|
|
411
|
+
return `${name}${typeArgs}`;
|
|
412
|
+
}
|
|
413
|
+
const type = TypeCheker.getTypeFromTypeNode(typeNode);
|
|
414
|
+
let typeName = TypeCheker.typeToString(type);
|
|
415
|
+
const isArray = typeName.includes('[]');
|
|
416
|
+
if (isArray) {
|
|
417
|
+
if (getArrayType) {
|
|
418
|
+
typeName = typeName.replace('[]', '');
|
|
419
|
+
}
|
|
420
|
+
else {
|
|
421
|
+
return ':';
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
switch (typeName) {
|
|
425
|
+
case 'number':
|
|
426
|
+
return 'float64';
|
|
427
|
+
case 'boolean':
|
|
428
|
+
return 'bool';
|
|
429
|
+
case 'any':
|
|
430
|
+
return ':';
|
|
431
|
+
case 'void':
|
|
432
|
+
return '';
|
|
433
|
+
default:
|
|
434
|
+
return typeName;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
function getTypeCategory(typeNode) {
|
|
438
|
+
if (!typeNode)
|
|
439
|
+
return undefined;
|
|
440
|
+
if (ts.isArrayTypeNode(typeNode))
|
|
441
|
+
return 'array';
|
|
442
|
+
if (typeNode.kind === ts.SyntaxKind.StringKeyword)
|
|
443
|
+
return 'string';
|
|
444
|
+
if (typeNode.kind === ts.SyntaxKind.NumberKeyword)
|
|
445
|
+
return 'number';
|
|
446
|
+
if (typeNode.kind === ts.SyntaxKind.BooleanKeyword)
|
|
447
|
+
return 'boolean';
|
|
448
|
+
if (ts.isUnionTypeNode(typeNode)) {
|
|
449
|
+
const nonNullTypes = typeNode.types.filter((t) => t.kind !== ts.SyntaxKind.NullKeyword &&
|
|
450
|
+
t.kind !== ts.SyntaxKind.UndefinedKeyword &&
|
|
451
|
+
!(ts.isLiteralTypeNode(t) && t.literal.kind === ts.SyntaxKind.NullKeyword));
|
|
452
|
+
if (nonNullTypes.length === 1)
|
|
453
|
+
return getTypeCategory(nonNullTypes[0]);
|
|
454
|
+
}
|
|
455
|
+
if (ts.isTypeReferenceNode(typeNode) && ts.isIdentifier(typeNode.typeName)) {
|
|
456
|
+
const name = typeNode.typeName.text;
|
|
457
|
+
if (classNames.has(name))
|
|
458
|
+
return 'class';
|
|
459
|
+
return name;
|
|
460
|
+
}
|
|
461
|
+
return undefined;
|
|
462
|
+
}
|
|
463
|
+
function resolveExpressionType(expr) {
|
|
464
|
+
if (ts.isIdentifier(expr)) {
|
|
465
|
+
return variableTypes.get(expr.text);
|
|
466
|
+
}
|
|
467
|
+
if (expr.kind === ts.SyntaxKind.ThisKeyword) {
|
|
468
|
+
return 'class';
|
|
469
|
+
}
|
|
470
|
+
return undefined;
|
|
471
|
+
}
|
|
472
|
+
function isNilLiteral(node) {
|
|
473
|
+
if (node.kind === ts.SyntaxKind.NullKeyword)
|
|
474
|
+
return true;
|
|
475
|
+
if (ts.isIdentifier(node) && node.text === 'undefined')
|
|
476
|
+
return true;
|
|
477
|
+
return false;
|
|
478
|
+
}
|
|
479
|
+
function getAcessString(leftSide, rightSide, objectType) {
|
|
480
|
+
if (rightSide === 'length' && objectType !== 'class') {
|
|
481
|
+
return `float64(len(${leftSide}))`;
|
|
482
|
+
}
|
|
483
|
+
return `${leftSide}.${rightSide}`;
|
|
484
|
+
}
|
|
485
|
+
const callHandlers = {
|
|
486
|
+
assert: (_caller, args) => {
|
|
487
|
+
const message = args.length > 1 ? args[1] : '"Assertion failed"';
|
|
488
|
+
return `if !(${args[0]}) {\n\t\tpanic(${message})\n\t}`;
|
|
489
|
+
},
|
|
490
|
+
'console.log': (_caller, args) => {
|
|
491
|
+
importedPackages.add('fmt');
|
|
492
|
+
return `fmt.Println(${args.join(', ')})`;
|
|
493
|
+
},
|
|
494
|
+
'console.time': (_caller, args) => {
|
|
495
|
+
importedPackages.add('time');
|
|
496
|
+
return `${getTimerName(args[0])} := time.Now()`;
|
|
497
|
+
},
|
|
498
|
+
'console.timeEnd': (_caller, args) => {
|
|
499
|
+
importedPackages.add('time');
|
|
500
|
+
importedPackages.add('fmt');
|
|
501
|
+
return `fmt.Println("Elapsed time:", time.Since(${getTimerName(args[0])}))`;
|
|
502
|
+
},
|
|
503
|
+
'Math.random': () => {
|
|
504
|
+
importedPackages.add('math/rand');
|
|
505
|
+
return 'rand.Float64()';
|
|
506
|
+
},
|
|
507
|
+
'Math.floor': (_caller, args) => {
|
|
508
|
+
importedPackages.add('math');
|
|
509
|
+
return `math.Floor(${args[0]})`;
|
|
510
|
+
},
|
|
511
|
+
'Math.ceil': (_caller, args) => {
|
|
512
|
+
importedPackages.add('math');
|
|
513
|
+
return `math.Ceil(${args[0]})`;
|
|
514
|
+
},
|
|
515
|
+
'Math.round': (_caller, args) => {
|
|
516
|
+
importedPackages.add('math');
|
|
517
|
+
return `math.Round(${args[0]})`;
|
|
518
|
+
},
|
|
519
|
+
'Math.abs': (_caller, args) => {
|
|
520
|
+
importedPackages.add('math');
|
|
521
|
+
return `math.Abs(${args[0]})`;
|
|
522
|
+
},
|
|
523
|
+
'Math.max': (_caller, args) => {
|
|
524
|
+
importedPackages.add('math');
|
|
525
|
+
return `math.Max(${args[0]}, ${args[1]})`;
|
|
526
|
+
},
|
|
527
|
+
'Math.min': (_caller, args) => {
|
|
528
|
+
importedPackages.add('math');
|
|
529
|
+
return `math.Min(${args[0]}, ${args[1]})`;
|
|
530
|
+
},
|
|
531
|
+
'Math.sqrt': (_caller, args) => {
|
|
532
|
+
importedPackages.add('math');
|
|
533
|
+
return `math.Sqrt(${args[0]})`;
|
|
534
|
+
},
|
|
535
|
+
'Math.pow': (_caller, args) => {
|
|
536
|
+
importedPackages.add('math');
|
|
537
|
+
return `math.Pow(${args[0]}, ${args[1]})`;
|
|
538
|
+
},
|
|
539
|
+
parseInt: (_caller, args) => {
|
|
540
|
+
importedPackages.add('strconv');
|
|
541
|
+
return `func() float64 { v, _ := strconv.Atoi(${args[0]}); return float64(v) }()`;
|
|
542
|
+
},
|
|
543
|
+
parseFloat: (_caller, args) => {
|
|
544
|
+
importedPackages.add('strconv');
|
|
545
|
+
return `func() float64 { v, _ := strconv.ParseFloat(${args[0]}, 64); return v }()`;
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
const stringMethodHandlers = {
|
|
549
|
+
split: (obj, args) => {
|
|
550
|
+
importedPackages.add('strings');
|
|
551
|
+
return `strings.Split(${obj}, ${args[0]})`;
|
|
552
|
+
},
|
|
553
|
+
trim: (obj) => {
|
|
554
|
+
importedPackages.add('strings');
|
|
555
|
+
return `strings.TrimSpace(${obj})`;
|
|
556
|
+
},
|
|
557
|
+
trimStart: (obj) => {
|
|
558
|
+
importedPackages.add('strings');
|
|
559
|
+
return `strings.TrimLeft(${obj}, " \\t\\n\\r")`;
|
|
560
|
+
},
|
|
561
|
+
trimEnd: (obj) => {
|
|
562
|
+
importedPackages.add('strings');
|
|
563
|
+
return `strings.TrimRight(${obj}, " \\t\\n\\r")`;
|
|
564
|
+
},
|
|
565
|
+
toUpperCase: (obj) => {
|
|
566
|
+
importedPackages.add('strings');
|
|
567
|
+
return `strings.ToUpper(${obj})`;
|
|
568
|
+
},
|
|
569
|
+
toLowerCase: (obj) => {
|
|
570
|
+
importedPackages.add('strings');
|
|
571
|
+
return `strings.ToLower(${obj})`;
|
|
572
|
+
},
|
|
573
|
+
indexOf: (obj, args) => {
|
|
574
|
+
importedPackages.add('strings');
|
|
575
|
+
return `float64(strings.Index(${obj}, ${args[0]}))`;
|
|
576
|
+
},
|
|
577
|
+
includes: (obj, args) => {
|
|
578
|
+
importedPackages.add('strings');
|
|
579
|
+
return `strings.Contains(${obj}, ${args[0]})`;
|
|
580
|
+
},
|
|
581
|
+
startsWith: (obj, args) => {
|
|
582
|
+
importedPackages.add('strings');
|
|
583
|
+
return `strings.HasPrefix(${obj}, ${args[0]})`;
|
|
584
|
+
},
|
|
585
|
+
endsWith: (obj, args) => {
|
|
586
|
+
importedPackages.add('strings');
|
|
587
|
+
return `strings.HasSuffix(${obj}, ${args[0]})`;
|
|
588
|
+
},
|
|
589
|
+
replace: (obj, args) => {
|
|
590
|
+
importedPackages.add('strings');
|
|
591
|
+
return `strings.Replace(${obj}, ${args[0]}, ${args[1]}, 1)`;
|
|
592
|
+
},
|
|
593
|
+
replaceAll: (obj, args) => {
|
|
594
|
+
importedPackages.add('strings');
|
|
595
|
+
return `strings.ReplaceAll(${obj}, ${args[0]}, ${args[1]})`;
|
|
596
|
+
},
|
|
597
|
+
repeat: (obj, args) => {
|
|
598
|
+
importedPackages.add('strings');
|
|
599
|
+
return `strings.Repeat(${obj}, int(${args[0]}))`;
|
|
600
|
+
},
|
|
601
|
+
charAt: (obj, args) => `string(${obj}[int(${args[0]})])`,
|
|
602
|
+
substring: (obj, args) => {
|
|
603
|
+
if (args.length >= 2)
|
|
604
|
+
return `${obj}[int(${args[0]}):int(${args[1]})]`;
|
|
605
|
+
return `${obj}[int(${args[0]}):]`;
|
|
606
|
+
},
|
|
607
|
+
slice: (obj, args) => {
|
|
608
|
+
if (args.length >= 2)
|
|
609
|
+
return `${obj}[int(${args[0]}):int(${args[1]})]`;
|
|
610
|
+
return `${obj}[int(${args[0]}):]`;
|
|
611
|
+
},
|
|
612
|
+
concat: (obj, args) => `${obj} + ${args.join(' + ')}`,
|
|
613
|
+
toString: (obj) => {
|
|
614
|
+
importedPackages.add('fmt');
|
|
615
|
+
return `fmt.Sprintf("%v", ${obj})`;
|
|
616
|
+
}
|
|
617
|
+
};
|
|
618
|
+
const arrayMethodHandlers = {
|
|
619
|
+
push: (obj, args) => `${obj} = append(${obj}, ${args.join(', ')})`,
|
|
620
|
+
join: (obj, args) => {
|
|
621
|
+
importedPackages.add('strings');
|
|
622
|
+
return `strings.Join(${obj}, ${args[0] ?? '""'})`;
|
|
623
|
+
},
|
|
624
|
+
slice: (obj, args) => {
|
|
625
|
+
if (args.length >= 2)
|
|
626
|
+
return `${obj}[int(${args[0]}):int(${args[1]})]`;
|
|
627
|
+
return `${obj}[int(${args[0]}):]`;
|
|
628
|
+
},
|
|
629
|
+
toString: (obj) => {
|
|
630
|
+
importedPackages.add('fmt');
|
|
631
|
+
return `fmt.Sprintf("%v", ${obj})`;
|
|
632
|
+
}
|
|
633
|
+
};
|
|
634
|
+
function getDynamicCallHandler(caller, objectType) {
|
|
635
|
+
if (promiseResolveName && caller === promiseResolveName) {
|
|
636
|
+
return (_caller, args) => `ch <- ${args[0]}`;
|
|
637
|
+
}
|
|
638
|
+
const dotIndex = caller.lastIndexOf('.');
|
|
639
|
+
if (dotIndex !== -1) {
|
|
640
|
+
const methodName = caller.substring(dotIndex + 1);
|
|
641
|
+
// Class instances use their own methods — never intercept
|
|
642
|
+
if (objectType === 'class')
|
|
643
|
+
return null;
|
|
644
|
+
let handler;
|
|
645
|
+
if (objectType === 'string') {
|
|
646
|
+
handler = stringMethodHandlers[methodName];
|
|
647
|
+
}
|
|
648
|
+
else if (objectType === 'array') {
|
|
649
|
+
handler = arrayMethodHandlers[methodName];
|
|
650
|
+
}
|
|
651
|
+
else {
|
|
652
|
+
// Unknown type: try both maps for backward compatibility
|
|
653
|
+
handler = stringMethodHandlers[methodName] ?? arrayMethodHandlers[methodName];
|
|
654
|
+
}
|
|
655
|
+
if (handler) {
|
|
656
|
+
return (c, args) => {
|
|
657
|
+
const obj = c.substring(0, dotIndex);
|
|
658
|
+
return handler(obj, args);
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
return null;
|
|
663
|
+
}
|
|
664
|
+
function getCallString(caller, args, typeArgs = '', objectType) {
|
|
665
|
+
const handler = callHandlers[caller] ?? getDynamicCallHandler(caller, objectType);
|
|
666
|
+
if (handler) {
|
|
667
|
+
return handler(caller, args, typeArgs);
|
|
668
|
+
}
|
|
669
|
+
return `${caller}${typeArgs}(${args.join(', ')})`;
|
|
670
|
+
}
|
|
671
|
+
function getOperatorText(operator) {
|
|
672
|
+
switch (operator) {
|
|
673
|
+
case ts.SyntaxKind.PlusToken:
|
|
674
|
+
return '+';
|
|
675
|
+
case ts.SyntaxKind.MinusToken:
|
|
676
|
+
return '-';
|
|
677
|
+
case ts.SyntaxKind.TildeToken:
|
|
678
|
+
return '~';
|
|
679
|
+
case ts.SyntaxKind.ExclamationToken:
|
|
680
|
+
return '!';
|
|
681
|
+
case ts.SyntaxKind.PlusPlusToken:
|
|
682
|
+
return '++';
|
|
683
|
+
case ts.SyntaxKind.MinusMinusToken:
|
|
684
|
+
return '--';
|
|
685
|
+
default:
|
|
686
|
+
console.error('Did not find operator', operator);
|
|
687
|
+
return '';
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
function getTimerName(name) {
|
|
691
|
+
return `__timer_${name.replaceAll(' ', '_').replaceAll('"', '')}__`;
|
|
692
|
+
}
|
|
693
|
+
function getTypeParameters(typeParameters) {
|
|
694
|
+
if (!typeParameters || typeParameters.length === 0)
|
|
695
|
+
return '';
|
|
696
|
+
const params = typeParameters.map((tp) => {
|
|
697
|
+
const name = visit(tp.name);
|
|
698
|
+
const constraint = tp.constraint ? getType(tp.constraint) : 'any';
|
|
699
|
+
return `${name} ${constraint}`;
|
|
700
|
+
});
|
|
701
|
+
return `[${params.join(', ')}]`;
|
|
702
|
+
}
|
|
703
|
+
function getTypeParameterNames(typeParameters) {
|
|
704
|
+
if (!typeParameters || typeParameters.length === 0)
|
|
705
|
+
return '';
|
|
706
|
+
const names = typeParameters.map((tp) => visit(tp.name));
|
|
707
|
+
return `[${names.join(', ')}]`;
|
|
708
|
+
}
|
|
709
|
+
function getTypeArguments(typeArguments) {
|
|
710
|
+
if (!typeArguments || typeArguments.length === 0)
|
|
711
|
+
return '';
|
|
712
|
+
const args = typeArguments.map((ta) => getType(ta));
|
|
713
|
+
return `[${args.join(', ')}]`;
|
|
714
|
+
}
|
|
715
|
+
function getSafeName(name) {
|
|
716
|
+
if (!dangerousNames.has(name)) {
|
|
717
|
+
return name;
|
|
718
|
+
}
|
|
719
|
+
if (!renamedFunctions.has(name)) {
|
|
720
|
+
renamedFunctions.set(name, `${name}_${goSafeId()}`);
|
|
721
|
+
}
|
|
722
|
+
return renamedFunctions.get(name);
|
|
723
|
+
}
|
|
724
|
+
function getPromiseChannelType(node) {
|
|
725
|
+
let parent = node.parent;
|
|
726
|
+
while (parent) {
|
|
727
|
+
if (ts.isFunctionDeclaration(parent) ||
|
|
728
|
+
ts.isMethodDeclaration(parent) ||
|
|
729
|
+
ts.isFunctionExpression(parent)) {
|
|
730
|
+
if (parent.type &&
|
|
731
|
+
ts.isTypeReferenceNode(parent.type) &&
|
|
732
|
+
ts.isIdentifier(parent.type.typeName)) {
|
|
733
|
+
if (parent.type.typeName.text === 'Promise' &&
|
|
734
|
+
parent.type.typeArguments &&
|
|
735
|
+
parent.type.typeArguments.length > 0) {
|
|
736
|
+
return getType(parent.type.typeArguments[0]);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
break;
|
|
740
|
+
}
|
|
741
|
+
parent = parent.parent;
|
|
742
|
+
}
|
|
743
|
+
return 'interface{}';
|
|
744
|
+
}
|
|
745
|
+
function visitPromiseReturn(node, options) {
|
|
746
|
+
const callback = node.arguments?.[0];
|
|
747
|
+
if (!callback || (!ts.isArrowFunction(callback) && !ts.isFunctionExpression(callback))) {
|
|
748
|
+
return `return ${visit(node)}` + (options.inline ? '' : ';\n\t');
|
|
749
|
+
}
|
|
750
|
+
const channelType = getPromiseChannelType(node);
|
|
751
|
+
const resolveParam = callback.parameters[0];
|
|
752
|
+
const resolveName = resolveParam ? visit(resolveParam.name) : '';
|
|
753
|
+
const prevResolveName = promiseResolveName;
|
|
754
|
+
promiseResolveName = resolveName;
|
|
755
|
+
const body = ts.isBlock(callback.body) ? visit(callback.body) : `{ ${visit(callback.body)} }`;
|
|
756
|
+
promiseResolveName = prevResolveName;
|
|
757
|
+
return (`ch := make(chan ${channelType})\n\t\tgo func() ${body.trimEnd()}()\n\t\treturn ch` +
|
|
758
|
+
(options.inline ? '' : ';\n\t'));
|
|
759
|
+
}
|
|
760
|
+
function visitNewPromise(node) {
|
|
761
|
+
const callback = node.arguments?.[0];
|
|
762
|
+
if (!callback || (!ts.isArrowFunction(callback) && !ts.isFunctionExpression(callback))) {
|
|
763
|
+
return 'NewPromise()';
|
|
764
|
+
}
|
|
765
|
+
const channelType = getPromiseChannelType(node);
|
|
766
|
+
const resolveParam = callback.parameters[0];
|
|
767
|
+
const resolveName = resolveParam ? visit(resolveParam.name) : '';
|
|
768
|
+
const prevResolveName = promiseResolveName;
|
|
769
|
+
promiseResolveName = resolveName;
|
|
770
|
+
const body = ts.isBlock(callback.body) ? visit(callback.body) : `{ ${visit(callback.body)} }`;
|
|
771
|
+
promiseResolveName = prevResolveName;
|
|
772
|
+
return `func() chan ${channelType} {\n\t\tch := make(chan ${channelType})\n\t\tgo func() ${body.trimEnd()}()\n\t\treturn ch;\n\t}()`;
|
|
773
|
+
}
|