typenative 0.0.18 → 0.0.20

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/bin/transpiler.js CHANGED
@@ -6,7 +6,16 @@ const importedPackages = new Set();
6
6
  let outsideNodes = [];
7
7
  const classNames = new Set();
8
8
  let promiseResolveName = '';
9
- const dangerousNames = new Set(['main']);
9
+ // Go keywords that cannot be used as identifiers
10
+ const dangerousNames = new Set([
11
+ 'main',
12
+ // Go reserved keywords
13
+ 'break', 'case', 'chan', 'const', 'continue',
14
+ 'default', 'defer', 'else', 'fallthrough', 'for',
15
+ 'func', 'go', 'goto', 'if', 'import',
16
+ 'interface', 'map', 'package', 'range', 'return',
17
+ 'select', 'struct', 'switch', 'type', 'var',
18
+ ]);
10
19
  const renamedFunctions = new Map();
11
20
  const variableTypes = new Map();
12
21
  const variableGoTypes = new Map();
@@ -17,7 +26,29 @@ const interfacePropertyTypes = new Map();
17
26
  const typeAliases = new Map();
18
27
  const enumNames = new Set();
19
28
  const enumBaseTypes = new Map();
20
- export function transpileToNative(code) {
29
+ // Maps local TS name → Go qualified name (e.g. 'Println' → 'fmt.Println', 'myFmt' → 'fmt')
30
+ const importAliases = new Map();
31
+ // Tracks static methods per class: Set of "ClassName.methodName" strings
32
+ const classStaticMethods = new Set();
33
+ // Tracks static properties per class: Set of "ClassName.propName" strings
34
+ const classStaticProps = new Set();
35
+ // Callback for resolving import specifiers to source code.
36
+ // specifier: the raw import string (relative path or package name)
37
+ // fromDir: directory of the file containing the import (null = main file's dir)
38
+ // Returns the file content and its directory (for resolving that file's own imports)
39
+ let fileResolver = null;
40
+ // Directory of the file currently being processed (null = main entry file)
41
+ let currentFileDir = null;
42
+ // Tracks already-included files by a stable key to prevent duplicates/cycles
43
+ const includedLocalImports = new Set();
44
+ // Collects Go source files generated from local TS imports (filename → content)
45
+ let localImportFiles = new Map();
46
+ // Default import namespaces from npm/local packages (e.g. `import ts from 'typescript'` → 'ts')
47
+ // Property accesses on these are stripped: ts.createSourceFile → createSourceFile
48
+ const defaultImportNamespaces = new Set();
49
+ export function transpileToNative(code, options) {
50
+ fileResolver = options?.readFile ?? null;
51
+ currentFileDir = null;
21
52
  const sourceFile = ts.createSourceFile('main.ts', code, ts.ScriptTarget.ES2020, true, ts.ScriptKind.TS);
22
53
  TypeCheker = ts.createProgram(['main.ts'], {}).getTypeChecker();
23
54
  importedPackages.clear();
@@ -34,17 +65,24 @@ export function transpileToNative(code) {
34
65
  typeAliases.clear();
35
66
  enumNames.clear();
36
67
  enumBaseTypes.clear();
68
+ importAliases.clear();
69
+ includedLocalImports.clear();
70
+ localImportFiles = new Map();
71
+ defaultImportNamespaces.clear();
72
+ classStaticMethods.clear();
73
+ classStaticProps.clear();
37
74
  const transpiledCode = visit(sourceFile, { addFunctionOutside: true });
38
75
  const transpiledCodeOutside = outsideNodes.map((n) => visit(n, { isOutside: true })).join('\n');
39
- return `package main
76
+ const main = `package main
40
77
 
41
78
  ${[...importedPackages].map((pkg) => `import "${pkg}"`).join('\n')}
42
79
 
43
80
  func main() {
44
81
  ${transpiledCode.trim()}
45
82
  }
46
-
83
+
47
84
  ${transpiledCodeOutside.trim()}`;
85
+ return { main, files: localImportFiles };
48
86
  }
49
87
  export function visit(node, options = {}) {
50
88
  let code = '';
@@ -57,6 +95,9 @@ export function visit(node, options = {}) {
57
95
  else if (ts.isIdentifier(node)) {
58
96
  if (node.text === 'undefined')
59
97
  return 'nil';
98
+ const goAlias = importAliases.get(node.text);
99
+ if (goAlias)
100
+ return goAlias;
60
101
  return getSafeName(node.text);
61
102
  }
62
103
  else if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {
@@ -95,6 +136,10 @@ export function visit(node, options = {}) {
95
136
  }
96
137
  else if (ts.isArrayLiteralExpression(node)) {
97
138
  const type = ts.isVariableDeclaration(node.parent) ? getType(node.parent.type, true) : '';
139
+ const hasSpread = node.elements.some((e) => ts.isSpreadElement(e));
140
+ if (hasSpread) {
141
+ return visitSpreadArrayLiteral(node, type);
142
+ }
98
143
  return `[]${type} {${node.elements.map((e) => visit(e)).join(', ')}}`;
99
144
  }
100
145
  else if (ts.isBlock(node)) {
@@ -115,12 +160,57 @@ export function visit(node, options = {}) {
115
160
  if (ts.isIdentifier(node.expression) && enumNames.has(node.expression.text)) {
116
161
  return `${getSafeName(node.expression.text)}_${getEnumMemberName(node.name)}`;
117
162
  }
163
+ // Strip default import namespace: `ts.createSourceFile` → `createSourceFile`
164
+ if (ts.isIdentifier(node.expression) && defaultImportNamespaces.has(node.expression.text)) {
165
+ return visit(node.name);
166
+ }
167
+ // Static member access: `Counter.count` → `Counter_count`
168
+ if (ts.isIdentifier(node.expression)) {
169
+ const key = `${node.expression.text}.${node.name.text}`;
170
+ if (classStaticMethods.has(key) || classStaticProps.has(key)) {
171
+ return `${node.expression.text}_${node.name.text}`;
172
+ }
173
+ }
118
174
  const leftSide = visit(node.expression);
119
175
  const rightSide = visit(node.name);
120
176
  const objectType = resolveExpressionType(node.expression);
121
177
  return getAcessString(leftSide, rightSide, objectType);
122
178
  }
123
179
  else if (ts.isVariableDeclaration(node)) {
180
+ // Object destructuring: const { x, y } = obj
181
+ if (ts.isObjectBindingPattern(node.name) && node.initializer) {
182
+ const initExpr = visit(node.initializer);
183
+ const parts = node.name.elements.map((el) => {
184
+ const localName = visit(el.name);
185
+ const propName = el.propertyName ? visit(el.propertyName) : localName;
186
+ const defaultVal = el.initializer ? visit(el.initializer) : undefined;
187
+ if (defaultVal) {
188
+ return `${localName} := func() interface{} { if ${initExpr}.${propName} == nil { return ${defaultVal} }; return ${initExpr}.${propName} }()`;
189
+ }
190
+ return `${localName} := ${initExpr}.${propName}`;
191
+ });
192
+ return parts.join(';\n\t');
193
+ }
194
+ // Array destructuring: const [a, b] = arr
195
+ if (ts.isArrayBindingPattern(node.name) && node.initializer) {
196
+ const initExpr = visit(node.initializer);
197
+ const tmpVar = getTempName('arr');
198
+ const parts = [`${tmpVar} := ${initExpr}`];
199
+ node.name.elements.forEach((el, idx) => {
200
+ if (ts.isOmittedExpression(el))
201
+ return;
202
+ const bindEl = el;
203
+ const localName = visit(bindEl.name);
204
+ // Variables starting with _ are intentionally unused — use blank identifier
205
+ if (localName === '_' || localName.startsWith('_')) {
206
+ parts.push(`_ = ${tmpVar}[${idx}]`);
207
+ }
208
+ else {
209
+ parts.push(`${localName} := ${tmpVar}[${idx}]`);
210
+ }
211
+ });
212
+ return parts.join(';\n\t');
213
+ }
124
214
  const type = getType(node.type);
125
215
  // Track variable type for type-aware method dispatch
126
216
  if (ts.isIdentifier(node.name)) {
@@ -175,6 +265,19 @@ export function visit(node, options = {}) {
175
265
  (ts.isPropertyAccessExpression(node.expression) && hasQuestionDot(node.expression))) {
176
266
  return visitOptionalCall(node);
177
267
  }
268
+ // IIFE with named function expression: (function name() { ... })()
269
+ if (ts.isParenthesizedExpression(node.expression) &&
270
+ ts.isFunctionExpression(node.expression.expression)) {
271
+ const fn = node.expression.expression;
272
+ const parameterInfo = getFunctionParametersInfo(fn.parameters);
273
+ if (fn.body && ts.isBlock(fn.body)) {
274
+ prescanVariableDeclarations(fn.body);
275
+ }
276
+ const inferredRetType = inferFunctionBodyReturnType(fn);
277
+ const returnType = inferredRetType ? ` ${inferredRetType}` : '';
278
+ const args = node.arguments.map((a) => visit(a)).join(', ');
279
+ return `func(${parameterInfo.signature})${returnType} ${visit(fn.body, { prefixBlockContent: parameterInfo.prefixBlockContent })}(${args})`;
280
+ }
178
281
  // Handle setTimeout specially to get raw delay value
179
282
  if (ts.isIdentifier(node.expression) && node.expression.text === 'setTimeout') {
180
283
  importedPackages.add('time');
@@ -190,7 +293,11 @@ export function visit(node, options = {}) {
190
293
  const caller = visit(node.expression);
191
294
  const safeCaller = getSafeName(caller);
192
295
  const typeArgs = getTypeArguments(node.typeArguments);
193
- const args = node.arguments.map((a) => visit(a));
296
+ // Handle spread arguments: fn(...arr) fn(arr...)
297
+ const hasSpreadArg = node.arguments.some((a) => ts.isSpreadElement(a));
298
+ const args = hasSpreadArg
299
+ ? node.arguments.map((a) => ts.isSpreadElement(a) ? `${visit(a.expression)}...` : visit(a))
300
+ : node.arguments.map((a) => visit(a));
194
301
  // Resolve object type for type-aware method dispatch
195
302
  let objectType;
196
303
  if (ts.isPropertyAccessExpression(node.expression)) {
@@ -236,9 +343,25 @@ export function visit(node, options = {}) {
236
343
  inline: true
237
344
  })}; ${visit(node.incrementor, { inline: true })}${visit(node.statement)}`;
238
345
  }
346
+ else if (ts.isForInStatement(node)) {
347
+ const varName = ts.isVariableDeclarationList(node.initializer)
348
+ ? visit(node.initializer.declarations[0].name)
349
+ : visit(node.initializer);
350
+ return `for ${varName} := range ${visit(node.expression, { inline: true })}${visit(node.statement)}`;
351
+ }
239
352
  else if (ts.isForOfStatement(node)) {
240
- const iterExpr = visit(node.expression, { inline: true });
241
- const iterType = inferExpressionType(node.expression);
353
+ // Unwrap Object.entries(x) treat x as the iterable
354
+ let iterNode = node.expression;
355
+ if (ts.isCallExpression(iterNode) &&
356
+ ts.isPropertyAccessExpression(iterNode.expression) &&
357
+ ts.isIdentifier(iterNode.expression.expression) &&
358
+ iterNode.expression.expression.text === 'Object' &&
359
+ iterNode.expression.name.text === 'entries' &&
360
+ iterNode.arguments.length > 0) {
361
+ iterNode = iterNode.arguments[0];
362
+ }
363
+ const iterExpr = visit(iterNode, { inline: true });
364
+ const iterType = inferExpressionType(iterNode);
242
365
  if (iterType && iterType.startsWith('map[')) {
243
366
  const valueType = extractMapValueType(iterType);
244
367
  const isSet = valueType === 'struct{}';
@@ -436,11 +559,23 @@ export function visit(node, options = {}) {
436
559
  const properties = new Map();
437
560
  const methods = new Map();
438
561
  for (const member of node.members) {
562
+ const memberModifiers = member.modifiers;
563
+ const isStatic = memberModifiers?.some((m) => m.kind === ts.SyntaxKind.StaticKeyword);
439
564
  if (ts.isPropertyDeclaration(member) && ts.isIdentifier(member.name)) {
440
- properties.set(member.name.text, getOptionalNodeType(member.type, !!member.questionToken));
565
+ if (isStatic) {
566
+ classStaticProps.add(`${className}.${member.name.text}`);
567
+ }
568
+ else {
569
+ properties.set(member.name.text, getOptionalNodeType(member.type, !!member.questionToken));
570
+ }
441
571
  }
442
572
  if (ts.isMethodDeclaration(member) && ts.isIdentifier(member.name)) {
443
- methods.set(member.name.text, member.type ? getType(member.type) : 'interface{}');
573
+ if (isStatic) {
574
+ classStaticMethods.add(`${className}.${member.name.text}`);
575
+ }
576
+ else {
577
+ methods.set(member.name.text, member.type ? getType(member.type) : 'interface{}');
578
+ }
444
579
  }
445
580
  }
446
581
  classPropertyTypes.set(className, properties);
@@ -498,9 +633,36 @@ export function visit(node, options = {}) {
498
633
  const methodName = visit(member.name);
499
634
  const methodParameterInfo = getFunctionParametersInfo(member.parameters);
500
635
  const returnType = member.type ? ` ${getType(member.type)}` : '';
501
- result += `func (self *${name}${typeParamNames}) ${methodName}(${methodParameterInfo.signature})${returnType} ${visit(member.body, {
502
- prefixBlockContent: methodParameterInfo.prefixBlockContent
503
- })}\n\n`;
636
+ const isStatic = member.modifiers?.some((m) => m.kind === ts.SyntaxKind.StaticKeyword);
637
+ if (isStatic) {
638
+ // Static methods become package-level functions named ClassName_methodName
639
+ result += `func ${name}_${methodName}(${methodParameterInfo.signature})${returnType} ${visit(member.body, { prefixBlockContent: methodParameterInfo.prefixBlockContent })}\n\n`;
640
+ }
641
+ else {
642
+ result += `func (self *${name}${typeParamNames}) ${methodName}(${methodParameterInfo.signature})${returnType} ${visit(member.body, { prefixBlockContent: methodParameterInfo.prefixBlockContent })}\n\n`;
643
+ }
644
+ }
645
+ else if (ts.isGetAccessor(member)) {
646
+ // Getter: get prop() { ... } → func (self *T) Prop() RetType { ... }
647
+ const getterName = visit(member.name);
648
+ const returnType = member.type ? ` ${getType(member.type)}` : ' interface{}';
649
+ result += `func (self *${name}${typeParamNames}) Get_${getterName}()${returnType} ${visit(member.body)}\n\n`;
650
+ }
651
+ else if (ts.isSetAccessor(member)) {
652
+ // Setter: set prop(val) { ... } → func (self *T) SetProp(val ValType) { ... }
653
+ const setterName = visit(member.name);
654
+ const parameterInfo = getFunctionParametersInfo(member.parameters);
655
+ result += `func (self *${name}${typeParamNames}) Set_${setterName}(${parameterInfo.signature}) ${visit(member.body, { prefixBlockContent: parameterInfo.prefixBlockContent })}\n\n`;
656
+ }
657
+ }
658
+ // Static property declarations → package-level vars named ClassName_propName
659
+ for (const member of node.members) {
660
+ if (ts.isPropertyDeclaration(member) &&
661
+ member.modifiers?.some((m) => m.kind === ts.SyntaxKind.StaticKeyword)) {
662
+ const fieldName = visit(member.name);
663
+ const fieldType = getOptionalNodeType(member.type, !!member.questionToken);
664
+ const initializer = member.initializer ? ` = ${visit(member.initializer)}` : '';
665
+ result += `var ${name}_${fieldName} ${fieldType}${initializer}\n\n`;
504
666
  }
505
667
  }
506
668
  return result.trim();
@@ -543,6 +705,12 @@ export function visit(node, options = {}) {
543
705
  if (ts.isPropertyAssignment(p)) {
544
706
  return `${visit(p.name)}: ${visit(p.initializer)}`;
545
707
  }
708
+ // Shorthand: { name } → name: name
709
+ if (ts.isShorthandPropertyAssignment(p)) {
710
+ const name = visit(p.name);
711
+ return `${name}: ${name}`;
712
+ }
713
+ // Spread: { ...obj } — not easily supported in Go structs, omit
546
714
  return '';
547
715
  })
548
716
  .filter((p) => p)
@@ -555,9 +723,16 @@ export function visit(node, options = {}) {
555
723
  else if (ts.isNonNullExpression(node)) {
556
724
  return visit(node.expression);
557
725
  }
726
+ else if (ts.isImportDeclaration(node)) {
727
+ return visitImportDeclaration(node);
728
+ }
729
+ else if (ts.isExportDeclaration(node) || ts.isExportAssignment(node)) {
730
+ return '';
731
+ }
558
732
  const syntaxKind = ts.SyntaxKind[node.kind];
559
733
  if (!['FirstStatement', 'EndOfFileToken'].includes(syntaxKind)) {
560
- console.log(ts.SyntaxKind[node.kind], node.getText());
734
+ const snippet = node.getText().substring(0, 60).replace(/\n/g, ' ');
735
+ console.warn(`[TypeNative] Unsupported syntax: ${syntaxKind} — "${snippet}"`);
561
736
  }
562
737
  ts.forEachChild(node, (subNode) => {
563
738
  code += visit(subNode);
@@ -575,6 +750,34 @@ function getTypeText(typeNode) {
575
750
  function toGoStringLiteral(value) {
576
751
  return JSON.stringify(value);
577
752
  }
753
+ function visitSpreadArrayLiteral(node, elemType) {
754
+ const chunks = [];
755
+ for (const el of node.elements) {
756
+ if (ts.isSpreadElement(el)) {
757
+ chunks.push({ isSpread: true, items: [el.expression] });
758
+ }
759
+ else {
760
+ const last = chunks[chunks.length - 1];
761
+ if (last && !last.isSpread) {
762
+ last.items.push(el);
763
+ }
764
+ else {
765
+ chunks.push({ isSpread: false, items: [el] });
766
+ }
767
+ }
768
+ }
769
+ const baseType = elemType || 'interface{}';
770
+ let result = `[]${baseType}{}`;
771
+ for (const chunk of chunks) {
772
+ if (chunk.isSpread) {
773
+ result = `append(${result}, ${visit(chunk.items[0])}...)`;
774
+ }
775
+ else {
776
+ result = `append(${result}, ${chunk.items.map((e) => visit(e)).join(', ')})`;
777
+ }
778
+ }
779
+ return result;
780
+ }
578
781
  function visitTemplateExpression(node) {
579
782
  const parts = [];
580
783
  if (node.head.text.length > 0) {
@@ -656,9 +859,7 @@ function inferFunctionBodyReturnType(node) {
656
859
  return undefined;
657
860
  }
658
861
  function inferArrowFunctionGoType(node) {
659
- const params = node.parameters
660
- .map((p) => (p.type ? getType(p.type) : 'interface{}'))
661
- .join(', ');
862
+ const params = node.parameters.map((p) => (p.type ? getType(p.type) : 'interface{}')).join(', ');
662
863
  const retType = inferFunctionBodyReturnType(node);
663
864
  return `func(${params})${retType ? ` ${retType}` : ''}`;
664
865
  }
@@ -937,8 +1138,8 @@ function buildArrayCallbackInfo(callback, elementType, forcedReturnType) {
937
1138
  params.push(`${visit(callback.parameters[2].name)} []${elementType}`);
938
1139
  }
939
1140
  const body = ts.isBlock(callback.body)
940
- ? visit(callback.body)
941
- : `{\n\t\treturn ${visit(callback.body)};\n\t}`;
1141
+ ? visit(callback.body, { inline: true })
1142
+ : `{ return ${visit(callback.body)}; }`;
942
1143
  return {
943
1144
  fnExpr: `func(${params.join(', ')}) ${callbackReturnType} ${body}`,
944
1145
  paramCount,
@@ -961,11 +1162,24 @@ function buildArrayCallbackInvocation(callbackInfo, itemVar, indexVar, arrayVar)
961
1162
  args.push(arrayVar);
962
1163
  return `(${callbackInfo.fnExpr})(${args.join(', ')})`;
963
1164
  }
1165
+ // Like buildArrayCallbackInvocation but for reduce: (acc, item, idx, arr)
1166
+ function buildArrayCallbackInvocationReduce(callbackInfo, accVar, itemVar, indexVar, arrayVar) {
1167
+ const args = [];
1168
+ if (callbackInfo.paramCount > 0)
1169
+ args.push(accVar);
1170
+ if (callbackInfo.paramCount > 1)
1171
+ args.push(itemVar);
1172
+ if (callbackInfo.paramCount > 2)
1173
+ args.push(`float64(${indexVar})`);
1174
+ if (callbackInfo.paramCount > 3)
1175
+ args.push(arrayVar);
1176
+ return `(${callbackInfo.fnExpr})(${args.join(', ')})`;
1177
+ }
964
1178
  function visitArrayHigherOrderCall(node) {
965
1179
  if (!ts.isPropertyAccessExpression(node.expression))
966
1180
  return undefined;
967
1181
  const methodName = node.expression.name.text;
968
- if (!['map', 'filter', 'some', 'find', 'join'].includes(methodName)) {
1182
+ if (!['map', 'filter', 'some', 'find', 'findIndex', 'every', 'forEach', 'reduce', 'join'].includes(methodName)) {
969
1183
  return undefined;
970
1184
  }
971
1185
  const arrayExprNode = node.expression.expression;
@@ -975,6 +1189,9 @@ function visitArrayHigherOrderCall(node) {
975
1189
  ? getArrayElementTypeFromGoType(ownerType)
976
1190
  : 'interface{}';
977
1191
  if (methodName === 'join') {
1192
+ // Only intercept array.join — if owner type is unknown/not array, fall through to callHandlers
1193
+ if (!isArrayLikeGoType(ownerType))
1194
+ return undefined;
978
1195
  importedPackages.add('strings');
979
1196
  importedPackages.add('fmt');
980
1197
  const separator = node.arguments[0] ? visit(node.arguments[0]) : '""';
@@ -1010,6 +1227,43 @@ function visitArrayHigherOrderCall(node) {
1010
1227
  const callbackCall = buildArrayCallbackInvocation(callbackInfo, itemVar, idxVar, arrVar);
1011
1228
  return `func() bool { ${arrVar} := ${arrayExpr}; for ${rangeIndexVar}, ${itemVar} := range ${arrVar} { if ${callbackCall} { return true } }; return false }()`;
1012
1229
  }
1230
+ if (methodName === 'findIndex') {
1231
+ const callbackInfo = buildArrayCallbackInfo(callback, elementType, 'bool');
1232
+ const callbackCall = buildArrayCallbackInvocation(callbackInfo, itemVar, idxVar, arrVar);
1233
+ return `func() float64 { ${arrVar} := ${arrayExpr}; for ${idxVar}, ${itemVar} := range ${arrVar} { if ${callbackCall} { return float64(${idxVar}) } }; return float64(-1) }()`;
1234
+ }
1235
+ if (methodName === 'every') {
1236
+ const callbackInfo = buildArrayCallbackInfo(callback, elementType, 'bool');
1237
+ const rangeIndexVar = callbackInfo.paramCount > 1 ? idxVar : '_';
1238
+ const callbackCall = buildArrayCallbackInvocation(callbackInfo, itemVar, idxVar, arrVar);
1239
+ return `func() bool { ${arrVar} := ${arrayExpr}; for ${rangeIndexVar}, ${itemVar} := range ${arrVar} { if !(${callbackCall}) { return false } }; return true }()`;
1240
+ }
1241
+ if (methodName === 'forEach') {
1242
+ const callbackInfo = buildArrayCallbackInfo(callback, elementType, '');
1243
+ const rangeIndexVar = callbackInfo.paramCount > 1 ? idxVar : '_';
1244
+ const callbackCall = buildArrayCallbackInvocation(callbackInfo, itemVar, idxVar, arrVar);
1245
+ return `func() { ${arrVar} := ${arrayExpr}; for ${rangeIndexVar}, ${itemVar} := range ${arrVar} { ${callbackCall} } }()`;
1246
+ }
1247
+ if (methodName === 'reduce') {
1248
+ const reduceCallback = node.arguments[0];
1249
+ if (!reduceCallback)
1250
+ return undefined;
1251
+ const initialValue = node.arguments[1] ? visit(node.arguments[1]) : undefined;
1252
+ const accType = initialValue
1253
+ ? (inferExpressionType(node.arguments[1]) ?? elementType)
1254
+ : elementType;
1255
+ const accVar = getTempName('acc');
1256
+ // Build a callback that takes (acc, item, idx, arr) — param count determines what gets passed
1257
+ const cbInfo = buildArrayCallbackInfo(reduceCallback, elementType, accType ?? 'interface{}');
1258
+ const cbCall = buildArrayCallbackInvocationReduce(cbInfo, accVar, itemVar, idxVar, arrVar);
1259
+ // Only include the index loop var if the callback uses it (paramCount > 2)
1260
+ const reduceIdxVar = cbInfo.paramCount > 2 ? idxVar : '_';
1261
+ if (initialValue !== undefined) {
1262
+ return `func() ${accType} { ${arrVar} := ${arrayExpr}; ${accVar} := ${initialValue}; for ${reduceIdxVar}, ${itemVar} := range ${arrVar} { ${accVar} = ${cbCall} }; return ${accVar} }()`;
1263
+ }
1264
+ return `func() ${elementType} { ${arrVar} := ${arrayExpr}; ${accVar} := ${arrVar}[0]; for ${reduceIdxVar}, ${itemVar} := range ${arrVar}[1:] { ${accVar} = ${cbCall} }; return ${accVar} }()`;
1265
+ }
1266
+ // find
1013
1267
  const callbackInfo = buildArrayCallbackInfo(callback, elementType, 'bool');
1014
1268
  const rangeIndexVar = callbackInfo.paramCount > 1 ? idxVar : '_';
1015
1269
  const callbackCall = buildArrayCallbackInvocation(callbackInfo, itemVar, idxVar, arrVar);
@@ -1263,6 +1517,21 @@ function getAcessString(leftSide, rightSide, objectType) {
1263
1517
  if (rightSide === 'size' && (objectType === 'Map' || objectType === 'Set')) {
1264
1518
  return `float64(len(${leftSide}))`;
1265
1519
  }
1520
+ // process global properties
1521
+ if (leftSide === 'process') {
1522
+ if (rightSide === 'argv') {
1523
+ importedPackages.add('os');
1524
+ return 'os.Args';
1525
+ }
1526
+ if (rightSide === 'platform') {
1527
+ importedPackages.add('runtime');
1528
+ return 'runtime.GOOS';
1529
+ }
1530
+ if (rightSide === 'env') {
1531
+ // process.env.X is handled by nested property access; just return a placeholder object
1532
+ return 'os.Environ()';
1533
+ }
1534
+ }
1266
1535
  return `${leftSide}.${rightSide}`;
1267
1536
  }
1268
1537
  const callHandlers = {
@@ -1326,7 +1595,84 @@ const callHandlers = {
1326
1595
  parseFloat: (_caller, args) => {
1327
1596
  importedPackages.add('strconv');
1328
1597
  return `func() float64 { v, _ := strconv.ParseFloat(${args[0]}, 64); return v }()`;
1329
- }
1598
+ },
1599
+ 'process.exit': (_caller, args) => {
1600
+ importedPackages.add('os');
1601
+ return `os.Exit(int(${args[0] ?? '0'}))`;
1602
+ },
1603
+ 'process.cwd': () => {
1604
+ importedPackages.add('os');
1605
+ return `func() string { __d, _ := os.Getwd(); return __d }()`;
1606
+ },
1607
+ 'JSON.stringify': (_caller, args) => {
1608
+ importedPackages.add('encoding/json');
1609
+ if (args.length >= 3) {
1610
+ return `func() string { __b, _ := json.MarshalIndent(${args[0]}, "", " "); return string(__b) }()`;
1611
+ }
1612
+ return `func() string { __b, _ := json.Marshal(${args[0]}); return string(__b) }()`;
1613
+ },
1614
+ 'JSON.parse': (_caller, args) => {
1615
+ importedPackages.add('encoding/json');
1616
+ return `func() interface{} { var __v interface{}; json.Unmarshal([]byte(${args[0]}), &__v); return __v }()`;
1617
+ },
1618
+ 'Object.keys': (_caller, args) => {
1619
+ importedPackages.add('maps');
1620
+ return `func() []string { __k := make([]string, 0); for k := range ${args[0]} { __k = append(__k, k) }; return __k }()`;
1621
+ },
1622
+ 'Object.values': (_caller, args) => {
1623
+ return `func() []interface{} { __v := make([]interface{}, 0); for _, v := range ${args[0]} { __v = append(__v, v) }; return __v }()`;
1624
+ },
1625
+ 'Object.entries': (_caller, args) => {
1626
+ // When used outside for...of, produce a slice of [key, value] pairs — rarely needed
1627
+ return args[0];
1628
+ },
1629
+ 'Math.log': (_caller, args) => {
1630
+ importedPackages.add('math');
1631
+ return `math.Log(${args[0]})`;
1632
+ },
1633
+ 'Math.log2': (_caller, args) => {
1634
+ importedPackages.add('math');
1635
+ return `math.Log2(${args[0]})`;
1636
+ },
1637
+ 'Math.log10': (_caller, args) => {
1638
+ importedPackages.add('math');
1639
+ return `math.Log10(${args[0]})`;
1640
+ },
1641
+ 'Math.sin': (_caller, args) => {
1642
+ importedPackages.add('math');
1643
+ return `math.Sin(${args[0]})`;
1644
+ },
1645
+ 'Math.cos': (_caller, args) => {
1646
+ importedPackages.add('math');
1647
+ return `math.Cos(${args[0]})`;
1648
+ },
1649
+ 'Math.tan': (_caller, args) => {
1650
+ importedPackages.add('math');
1651
+ return `math.Tan(${args[0]})`;
1652
+ },
1653
+ 'Math.trunc': (_caller, args) => {
1654
+ importedPackages.add('math');
1655
+ return `math.Trunc(${args[0]})`;
1656
+ },
1657
+ 'Math.sign': (_caller, args) => {
1658
+ return `func() float64 { if ${args[0]} > 0 { return 1 }; if ${args[0]} < 0 { return -1 }; return 0 }()`;
1659
+ },
1660
+ 'console.error': (_caller, args) => {
1661
+ importedPackages.add('fmt');
1662
+ importedPackages.add('os');
1663
+ return `fmt.Fprintln(os.Stderr, ${args.join(', ')})`;
1664
+ },
1665
+ 'String': (_caller, args) => {
1666
+ importedPackages.add('fmt');
1667
+ return `fmt.Sprintf("%v", ${args[0]})`;
1668
+ },
1669
+ 'Number': (_caller, args) => {
1670
+ importedPackages.add('strconv');
1671
+ return `func() float64 { v, _ := strconv.ParseFloat(fmt.Sprintf("%v", ${args[0]}), 64); return v }()`;
1672
+ },
1673
+ 'Boolean': (_caller, args) => {
1674
+ return `(${args[0]} != nil && ${args[0]} != false && ${args[0]} != 0 && ${args[0]} != "")`;
1675
+ },
1330
1676
  };
1331
1677
  const stringMethodHandlers = {
1332
1678
  split: (obj, args) => {
@@ -1393,6 +1739,32 @@ const stringMethodHandlers = {
1393
1739
  return `${obj}[int(${args[0]}):]`;
1394
1740
  },
1395
1741
  concat: (obj, args) => `${obj} + ${args.join(' + ')}`,
1742
+ padStart: (obj, args) => {
1743
+ importedPackages.add('fmt');
1744
+ importedPackages.add('strings');
1745
+ const pad = args[1] ?? '" "';
1746
+ return `func() string { __s := ${obj}; __n := int(${args[0]}) - len(__s); if __n > 0 { __s = strings.Repeat(${pad}, __n)[:__n] + __s }; return __s }()`;
1747
+ },
1748
+ padEnd: (obj, args) => {
1749
+ importedPackages.add('strings');
1750
+ const pad = args[1] ?? '" "';
1751
+ return `func() string { __s := ${obj}; __n := int(${args[0]}) - len(__s); if __n > 0 { __s = __s + strings.Repeat(${pad}, __n)[:__n] }; return __s }()`;
1752
+ },
1753
+ match: (obj, args) => {
1754
+ importedPackages.add('regexp');
1755
+ return `regexp.MustCompile(${args[0]}).FindStringSubmatch(${obj})`;
1756
+ },
1757
+ matchAll: (obj, args) => {
1758
+ importedPackages.add('regexp');
1759
+ return `regexp.MustCompile(${args[0]}).FindAllStringSubmatch(${obj}, -1)`;
1760
+ },
1761
+ search: (obj, args) => {
1762
+ importedPackages.add('regexp');
1763
+ return `float64(regexp.MustCompile(${args[0]}).FindStringIndex(${obj})[0])`;
1764
+ },
1765
+ at: (obj, args) => {
1766
+ return `func() string { __i := int(${args[0]}); if __i < 0 { __i = len(${obj}) + __i }; return string(${obj}[__i]) }()`;
1767
+ },
1396
1768
  toString: (obj) => {
1397
1769
  importedPackages.add('fmt');
1398
1770
  return `fmt.Sprintf("%v", ${obj})`;
@@ -1404,6 +1776,13 @@ const regexpMethodHandlers = {
1404
1776
  };
1405
1777
  const arrayMethodHandlers = {
1406
1778
  push: (obj, args) => `${obj} = append(${obj}, ${args.join(', ')})`,
1779
+ pop: (obj) => {
1780
+ return `func() interface{} { if len(${obj}) == 0 { return nil }; __last := ${obj}[len(${obj})-1]; ${obj} = ${obj}[:len(${obj})-1]; return __last }()`;
1781
+ },
1782
+ shift: (obj) => {
1783
+ return `func() interface{} { if len(${obj}) == 0 { return nil }; __first := ${obj}[0]; ${obj} = ${obj}[1:]; return __first }()`;
1784
+ },
1785
+ unshift: (obj, args) => `${obj} = append([]interface{}{${args.join(', ')}}, ${obj}...)`,
1407
1786
  join: (obj, args) => {
1408
1787
  importedPackages.add('strings');
1409
1788
  return `strings.Join(${obj}, ${args[0] ?? '""'})`;
@@ -1413,10 +1792,30 @@ const arrayMethodHandlers = {
1413
1792
  return `${obj}[int(${args[0]}):int(${args[1]})]`;
1414
1793
  return `${obj}[int(${args[0]}):]`;
1415
1794
  },
1795
+ reverse: (obj) => {
1796
+ importedPackages.add('slices');
1797
+ return `func() interface{} { slices.Reverse(${obj}); return nil }()`;
1798
+ },
1799
+ sort: (obj) => {
1800
+ importedPackages.add('sort');
1801
+ return `func() interface{} { sort.Slice(${obj}, func(i, j int) bool { return fmt.Sprintf("%v", ${obj}[i]) < fmt.Sprintf("%v", ${obj}[j]) }); return nil }()`;
1802
+ },
1803
+ indexOf: (obj, args) => {
1804
+ return `func() float64 { for __i, __v := range ${obj} { if fmt.Sprintf("%v", __v) == fmt.Sprintf("%v", ${args[0]}) { return float64(__i) } }; return float64(-1) }()`;
1805
+ },
1806
+ includes: (obj, args) => {
1807
+ return `func() bool { for _, __v := range ${obj} { if fmt.Sprintf("%v", __v) == fmt.Sprintf("%v", ${args[0]}) { return true } }; return false }()`;
1808
+ },
1809
+ concat: (obj, args) => `append(${obj}, ${args.join(', ')}...)`,
1810
+ flat: (obj) => obj,
1416
1811
  toString: (obj) => {
1417
1812
  importedPackages.add('fmt');
1418
1813
  return `fmt.Sprintf("%v", ${obj})`;
1419
- }
1814
+ },
1815
+ // padStart / padEnd for string arrays (rarely used, but added for completeness)
1816
+ at: (obj, args) => {
1817
+ return `func() interface{} { __i := int(${args[0]}); if __i < 0 { __i = len(${obj}) + __i }; if __i < 0 || __i >= len(${obj}) { return nil }; return ${obj}[__i] }()`;
1818
+ },
1420
1819
  };
1421
1820
  const mapMethodHandlers = {
1422
1821
  set: (obj, args) => `${obj}[${args[0]}] = ${args[1]}`,
@@ -1549,6 +1948,17 @@ function getTypeArguments(typeArguments) {
1549
1948
  return `[${args.join(', ')}]`;
1550
1949
  }
1551
1950
  function getParameterGoType(param) {
1951
+ // Rest parameter: ...args — use variadic syntax
1952
+ if (param.dotDotDotToken) {
1953
+ if (param.type) {
1954
+ let baseType = getType(param.type);
1955
+ // If annotated as T[], the variadic type is T
1956
+ if (baseType.startsWith('[]'))
1957
+ baseType = baseType.slice(2);
1958
+ return `...${baseType}`;
1959
+ }
1960
+ return '...interface{}';
1961
+ }
1552
1962
  if (param.type) {
1553
1963
  const explicitType = getType(param.type);
1554
1964
  return explicitType === ':' ? 'interface{}' : explicitType;
@@ -1572,9 +1982,7 @@ function getFunctionParametersInfo(parameters) {
1572
1982
  prefixBlockContent: ''
1573
1983
  };
1574
1984
  }
1575
- const hasRequiredAfterDefault = parameters
1576
- .slice(firstDefaultIndex)
1577
- .some((p) => !p.initializer);
1985
+ const hasRequiredAfterDefault = parameters.slice(firstDefaultIndex).some((p) => !p.initializer);
1578
1986
  if (hasRequiredAfterDefault) {
1579
1987
  return {
1580
1988
  signature: parameters.map((p) => `${visit(p.name)} ${getParameterGoType(p)}`).join(', '),
@@ -1714,6 +2122,230 @@ function visitNewSet(node) {
1714
2122
  const values = initArg.elements.map((el) => `${tmp}[${visit(el)}] = struct{}{}`).join('; ');
1715
2123
  return `func() ${setType} { ${tmp} := make(${setType}); ${values}; return ${tmp} }()`;
1716
2124
  }
2125
+ function specifierToGoFileName(specifier) {
2126
+ const segments = specifier.split(/[/\\]/);
2127
+ let name = segments[segments.length - 1] || segments[segments.length - 2] || 'import';
2128
+ // Strip all extensions (e.g. .spec.ts → '', .ts → '')
2129
+ name = name.replace(/(\.[^.]+)+$/, '');
2130
+ name = name.replace(/[^a-zA-Z0-9]+/g, '_').replace(/^_+|_+$/g, '');
2131
+ if (!name)
2132
+ name = 'import';
2133
+ // Deduplicate filename if already taken by a different import
2134
+ let candidate = name + '.go';
2135
+ let i = 2;
2136
+ while (localImportFiles.has(candidate)) {
2137
+ candidate = `${name}_${i}.go`;
2138
+ i++;
2139
+ }
2140
+ return candidate;
2141
+ }
2142
+ function normalizeCjsToEsm(code) {
2143
+ // Remove 'use strict' directive
2144
+ code = code.replace(/['"]use strict['"];?\n?/g, '');
2145
+ // module.exports.X = function(...) { } or exports.X = function(...) { }
2146
+ code = code.replace(/(?:module\.exports|exports)\.(\w+)\s*=\s*function\s*\w*\s*\(/g, 'export function $1(');
2147
+ return code;
2148
+ }
2149
+ function includeLocalImport(code, dir, goFileName) {
2150
+ const prevDir = currentFileDir;
2151
+ currentFileDir = dir;
2152
+ // Normalize CommonJS modules to ES module syntax before parsing
2153
+ if (!code.includes('export ') && (code.includes('module.exports') || code.includes('exports.'))) {
2154
+ code = normalizeCjsToEsm(code);
2155
+ }
2156
+ if (!goFileName) {
2157
+ // Inline mode (npm packages): pull declarations into the current transpilation context
2158
+ const sf = ts.createSourceFile('imported.ts', code, ts.ScriptTarget.ES2020, true, ts.ScriptKind.TS);
2159
+ for (const stmt of sf.statements) {
2160
+ visit(stmt, { addFunctionOutside: true });
2161
+ }
2162
+ currentFileDir = prevDir;
2163
+ return;
2164
+ }
2165
+ // Separate-file mode (local TS imports): transpile to its own Go file
2166
+ const savedOutsideNodes = outsideNodes;
2167
+ const savedPackages = [...importedPackages];
2168
+ outsideNodes = [];
2169
+ importedPackages.clear();
2170
+ const sf = ts.createSourceFile('imported.ts', code, ts.ScriptTarget.ES2020, true, ts.ScriptKind.TS);
2171
+ const inlineLines = [];
2172
+ for (const stmt of sf.statements) {
2173
+ const result = visit(stmt, { addFunctionOutside: true });
2174
+ if (result.trim())
2175
+ inlineLines.push(result);
2176
+ }
2177
+ const fileImports = [...importedPackages].map((pkg) => `import "${pkg}"`).join('\n');
2178
+ const fileOutside = outsideNodes.map((n) => visit(n, { isOutside: true })).join('\n');
2179
+ const fileInline = inlineLines.join('\n');
2180
+ const parts = ['package main'];
2181
+ if (fileImports)
2182
+ parts.push(fileImports);
2183
+ if (fileInline.trim())
2184
+ parts.push(fileInline.trim());
2185
+ if (fileOutside.trim())
2186
+ parts.push(fileOutside.trim());
2187
+ localImportFiles.set(goFileName, parts.join('\n\n'));
2188
+ // Restore main-file state
2189
+ outsideNodes = savedOutsideNodes;
2190
+ importedPackages.clear();
2191
+ for (const p of savedPackages)
2192
+ importedPackages.add(p);
2193
+ currentFileDir = prevDir;
2194
+ }
2195
+ function registerGoPackageAliases(node, goPkg) {
2196
+ const pkgName = goPkg.split('/').pop();
2197
+ if (!node.importClause)
2198
+ return;
2199
+ const clause = node.importClause;
2200
+ // Default import: `import fmt from 'go:fmt'` or `import myFmt from 'go:fmt'`
2201
+ if (clause.name && clause.name.text !== pkgName) {
2202
+ importAliases.set(clause.name.text, pkgName);
2203
+ }
2204
+ if (clause.namedBindings) {
2205
+ if (ts.isNamespaceImport(clause.namedBindings)) {
2206
+ // `import * as myFmt from 'go:fmt'`
2207
+ const localName = clause.namedBindings.name.text;
2208
+ if (localName !== pkgName) {
2209
+ importAliases.set(localName, pkgName);
2210
+ }
2211
+ }
2212
+ else if (ts.isNamedImports(clause.namedBindings)) {
2213
+ // `import { Println, Sprintf as Spf } from 'go:fmt'`
2214
+ for (const el of clause.namedBindings.elements) {
2215
+ if (el.isTypeOnly)
2216
+ continue;
2217
+ const localName = el.name.text;
2218
+ const importedName = el.propertyName?.text ?? localName;
2219
+ importAliases.set(localName, `${pkgName}.${importedName}`);
2220
+ }
2221
+ }
2222
+ }
2223
+ }
2224
+ function getImportLocalName(node) {
2225
+ const clause = node.importClause;
2226
+ if (!clause)
2227
+ return null;
2228
+ if (clause.name)
2229
+ return clause.name.text;
2230
+ if (clause.namedBindings) {
2231
+ if (ts.isNamespaceImport(clause.namedBindings))
2232
+ return clause.namedBindings.name.text;
2233
+ }
2234
+ return null;
2235
+ }
2236
+ // Per-module table: maps Node.js function name → Go expression template.
2237
+ // For default/namespace imports (e.g. `import path from 'node:path'`), entries are registered
2238
+ // as `callHandlers[localName.funcName]`. For named imports (e.g. `import { join } from 'node:path'`),
2239
+ // the Go identifier is stored in importAliases so bare calls like `join(...)` resolve correctly.
2240
+ const nodeModuleMappings = {
2241
+ path: {
2242
+ goPackage: 'path/filepath',
2243
+ functions: {
2244
+ join: (args) => `filepath.Join(${args.join(', ')})`,
2245
+ dirname: (args) => `filepath.Dir(${args[0]})`,
2246
+ basename: (args) => args[1]
2247
+ ? `strings.TrimSuffix(filepath.Base(${args[0]}), ${args[1]})`
2248
+ : `filepath.Base(${args[0]})`,
2249
+ extname: (args) => `filepath.Ext(${args[0]})`,
2250
+ resolve: (args) => `func() string { p, _ := filepath.Abs(filepath.Join(${args.join(', ')})); return p }()`
2251
+ }
2252
+ }
2253
+ // Future node stdlib modules can be added here as additional keys:
2254
+ // fs: { goPackage: 'os', functions: { ... } },
2255
+ // os: { goPackage: 'os', functions: { ... } },
2256
+ };
2257
+ // Mapping from Node.js stdlib module names to Go setup functions.
2258
+ // Each entry adds the required Go imports and registers call handlers for the local identifier.
2259
+ function setupNodeModuleImport(node, nodeModule) {
2260
+ const mapping = nodeModuleMappings[nodeModule];
2261
+ if (!mapping)
2262
+ return;
2263
+ importedPackages.add(mapping.goPackage);
2264
+ const clause = node.importClause;
2265
+ if (!clause)
2266
+ return;
2267
+ if (clause.namedBindings && ts.isNamedImports(clause.namedBindings)) {
2268
+ // Named imports: `import { join, dirname } from 'node:path'`
2269
+ // Map each local name directly to its Go qualified function via importAliases,
2270
+ // so bare calls like `join(...)` resolve to `filepath.Join(...)`.
2271
+ for (const el of clause.namedBindings.elements) {
2272
+ if (el.isTypeOnly)
2273
+ continue;
2274
+ const localName = el.name.text;
2275
+ const importedName = el.propertyName?.text ?? localName;
2276
+ const fn = mapping.functions[importedName];
2277
+ if (fn) {
2278
+ // Register a call handler keyed on the local name
2279
+ callHandlers[localName] = (_caller, args) => fn(args);
2280
+ }
2281
+ }
2282
+ }
2283
+ else {
2284
+ // Default import (`import path from 'node:path'`) or
2285
+ // namespace import (`import * as path from 'node:path'`)
2286
+ const localName = getImportLocalName(node) ?? nodeModule;
2287
+ for (const [funcName, fn] of Object.entries(mapping.functions)) {
2288
+ callHandlers[`${localName}.${funcName}`] = (_caller, args) => fn(args);
2289
+ }
2290
+ }
2291
+ }
2292
+ function visitImportDeclaration(node) {
2293
+ if (!ts.isStringLiteral(node.moduleSpecifier))
2294
+ return '';
2295
+ const moduleSpec = node.moduleSpecifier.text;
2296
+ // Relative imports → transpile to a separate Go file
2297
+ if (moduleSpec.startsWith('.') || moduleSpec.startsWith('/')) {
2298
+ // Key combines current dir + specifier to avoid cross-package collisions
2299
+ const key = `${currentFileDir ?? ''}::${moduleSpec}`;
2300
+ if (fileResolver && !includedLocalImports.has(key)) {
2301
+ includedLocalImports.add(key);
2302
+ const resolved = fileResolver(moduleSpec, currentFileDir);
2303
+ if (resolved) {
2304
+ const goFileName = specifierToGoFileName(moduleSpec);
2305
+ includeLocalImport(resolved.content, resolved.dir, goFileName);
2306
+ }
2307
+ }
2308
+ return '';
2309
+ }
2310
+ // Type-only imports contribute nothing to runtime
2311
+ if (node.importClause?.isTypeOnly)
2312
+ return '';
2313
+ // Go standard library: `import { Println } from 'go:fmt'` → import "fmt"
2314
+ if (moduleSpec.startsWith('go:')) {
2315
+ const goPkg = moduleSpec.slice(3);
2316
+ importedPackages.add(goPkg);
2317
+ registerGoPackageAliases(node, goPkg);
2318
+ return '';
2319
+ }
2320
+ // Node.js standard library: `import path from 'node:path'` → mapped Go packages
2321
+ if (moduleSpec.startsWith('node:')) {
2322
+ const nodeModule = moduleSpec.slice(5);
2323
+ setupNodeModuleImport(node, nodeModule);
2324
+ return '';
2325
+ }
2326
+ // npm package (bare specifier) → transpile to its own Go file
2327
+ const npmKey = `npm::${moduleSpec}`;
2328
+ if (fileResolver && !includedLocalImports.has(npmKey)) {
2329
+ includedLocalImports.add(npmKey);
2330
+ const resolved = fileResolver(moduleSpec, currentFileDir);
2331
+ if (resolved) {
2332
+ const goFileName = specifierToGoFileName(moduleSpec);
2333
+ includeLocalImport(resolved.content, resolved.dir, goFileName);
2334
+ }
2335
+ }
2336
+ // Register default/namespace import name as a "stripped" namespace
2337
+ // e.g. `import ts from 'typescript'` → ts.createSourceFile → createSourceFile
2338
+ if (node.importClause) {
2339
+ const clause = node.importClause;
2340
+ if (clause.name) {
2341
+ defaultImportNamespaces.add(clause.name.text);
2342
+ }
2343
+ else if (clause.namedBindings && ts.isNamespaceImport(clause.namedBindings)) {
2344
+ defaultImportNamespaces.add(clause.namedBindings.name.text);
2345
+ }
2346
+ }
2347
+ return '';
2348
+ }
1717
2349
  function getForOfVarNames(initializer) {
1718
2350
  if (!ts.isVariableDeclarationList(initializer) || initializer.declarations.length === 0) {
1719
2351
  return ['_'];