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.
@@ -24,6 +24,8 @@ jobs:
24
24
  with:
25
25
  go-version: '1.21'
26
26
  - run: npm ci
27
+ - run: npm ci
28
+ working-directory: test
27
29
  - run: npm test
28
30
 
29
31
  release:
package/CHANGELOG.md CHANGED
@@ -5,6 +5,43 @@ 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.20] - 2026-03-16
9
+
10
+ ### Added
11
+
12
+ - **Spread in array literals**: `[...arr1, ...arr2]` → `append(append([]T{}, arr1...), arr2...)`
13
+ - **Rest parameters**: `function(...args: T[])` → Go variadic `func(...args T)`
14
+ - **Spread in function calls**: `fn(...args)` → `fn(args...)`
15
+ - **Array destructuring**: `const [a, b] = arr` → Go index assignments
16
+ - **Object shorthand**: `{ name }` → `{ name: name }` in struct literals
17
+ - **Static class members**: `static method()` / `static prop` → `ClassName_method()` / `ClassName_prop` package-level declarations; `ClassName.method()` calls correctly resolve
18
+ - **Getters/Setters**: `get prop()` → `Get_prop()` method, `set prop(v)` → `Set_prop(v)` method
19
+ - **`for...in` loops**: `for (const k in obj)` → `for k := range obj`
20
+ - **`Object.entries()` in `for...of`**: `for (const [k, v] of Object.entries(map))` unwraps to `for k, v := range map`
21
+ - **Named function expression IIFEs**: `(function name() { ... })()` → anonymous `func() { ... }()`
22
+ - **`process` global**: `process.argv` → `os.Args`, `process.platform` → `runtime.GOOS`, `process.exit()` → `os.Exit()`, `process.cwd()` → `os.Getwd()`
23
+ - **`JSON.stringify()` / `JSON.parse()`**: mapped to `encoding/json` `Marshal`/`Unmarshal`
24
+ - **`Object.keys()` / `Object.values()` / `Object.entries()`**: map iteration helpers
25
+ - **Array methods**: `findIndex`, `every`, `forEach`, `reduce`, `pop`, `shift`, `unshift`, `reverse`, `sort`, `concat`, `flat`, `at`
26
+ - **String methods**: `padStart`, `padEnd`, `match`, `matchAll`, `search`, `at`
27
+ - **Math methods**: `log`, `log2`, `log10`, `sin`, `cos`, `tan`, `trunc`, `sign`
28
+ - **`console.error()`**: maps to `fmt.Fprintln(os.Stderr, ...)`
29
+ - **`String()` / `Number()` / `Boolean()`** conversion functions
30
+ - **Go reserved words protection**: `getSafeName()` now covers all Go keywords (`break`, `case`, `chan`, `continue`, `default`, `defer`, `else`, `fallthrough`, `for`, `func`, `go`, `goto`, `if`, `import`, `interface`, `map`, `package`, `range`, `return`, `select`, `struct`, `switch`, `type`, `var`)
31
+ - **Default import namespaces from npm/local packages**: `import ts from 'typescript'` registers `ts` as a stripped namespace so `ts.method()` → `method()`
32
+ - **Better unsupported syntax warnings**: `console.warn` with syntax kind name and source snippet instead of `console.log`
33
+ - **Type definitions (`typenative.d.ts`)**: added `findIndex`, `every`, `forEach`, `reduce`, `pop`, `shift`, `unshift`, `reverse`, `sort`, `flat`, `concat`, `at` to `Array`; `padStart`, `padEnd`, `match`, `matchAll`, `search`, `at` to `String`; added `JSON`, `Object`, `Process`, extended `Math` and `Console`
34
+
35
+ ## [0.0.19] - 2026-03-07
36
+
37
+ ### Added
38
+
39
+ - Module/import support: `import { x } from './file'` transpiled to Go package imports for local TypeScript files
40
+ - Node.js built-in module imports: `import { join } from 'node:path'` and similar mapped to corresponding Go standard library packages
41
+ - npm package imports: `import { x } from 'pkg'` mapped to Go module imports via `typenative-npm.d.ts` type definitions
42
+ - Go package imports: `import { x } from 'go:package'` to import a Go library package
43
+ - Named exports: `export function` and `export const` declarations now transpiled correctly
44
+
8
45
  ## [0.0.18] - 2026-03-03
9
46
 
10
47
  ### Added
package/README.md CHANGED
@@ -29,10 +29,13 @@ TypeNative currently supports a focused subset of TypeScript syntax elements tha
29
29
 
30
30
  **Variables & Objects**
31
31
 
32
- | Feature | Supported | Notes |
33
- | --------------------- | :-------: | -------------------------------- |
34
- | Variable declarations | ✅ | `let` and `const` |
35
- | Object literals | ✅ | Transpiled to Go struct literals |
32
+ | Feature | Supported | Notes |
33
+ | ---------------------- | :-------: | ----------------------------------------------- |
34
+ | Variable declarations | ✅ | `let` and `const` |
35
+ | Object literals | ✅ | Transpiled to Go struct literals |
36
+ | Object shorthand | ✅ | `{ name }` → `{ name: name }` |
37
+ | Array destructuring | ✅ | `const [a, b] = arr` |
38
+ | Object destructuring | ✅ | `const { x, y } = obj` |
36
39
 
37
40
  **Operators**
38
41
 
@@ -42,6 +45,7 @@ TypeNative currently supports a focused subset of TypeScript syntax elements tha
42
45
  | Comparison operators | ✅ | `==`, `!=`, `===`, `!==`, etc. |
43
46
  | Logical operators | ✅ | `&&`, `\|\|` |
44
47
  | Increment/Decrement | ✅ | `++`, `--` |
48
+ | Spread operator | ✅ | `[...arr]`, `fn(...args)` |
45
49
  | Non-null assertion (`!`) | ✅ | Stripped during transpilation |
46
50
  | Ternary expressions | ✅ | `condition ? a : b` |
47
51
  | Nullish coalescing | ✅ | `??` operator |
@@ -49,37 +53,40 @@ TypeNative currently supports a focused subset of TypeScript syntax elements tha
49
53
 
50
54
  **Control Flow**
51
55
 
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 |
56
+ | Feature | Supported | Notes |
57
+ | ------------------ | :-------: | ------------------------------------------------------ |
58
+ | If/Else statements | ✅ | Fully supported |
59
+ | Switch statements | ✅ | Case and default statements |
60
+ | For loops | ✅ | Standard `for` loops |
61
+ | For...of loops | ✅ | Arrays, Maps, Sets; `Object.entries()` unwrapping |
62
+ | For...in loops | ✅ | Iterates keys via Go `range` |
63
+ | While loops | ✅ | Transpiled to Go's `for` loops |
64
+ | Do...while loops | ✅ | Implemented with conditional break |
60
65
  | Try/Catch/Finally | ✅ | `throw` → `panic`; catch/finally via `defer`/`recover` |
61
66
 
62
67
  **Data Structures & Array Methods**
63
68
 
64
- | Feature | Supported | Notes |
65
- | -------------------------- | :-------: | ---------------------------------------------------------------- |
66
- | Arrays | ✅ | Basic array operations |
67
- | Array methods | ✅ | `push`, `join`, `slice` |
68
- | Higher-order array methods | ✅ | `.map()`, `.filter()`, `.some()`, `.find()` |
69
- | Method chaining | ✅ | Chaining array methods such as `.map(...).filter(...).join(...)` |
70
- | Map | ✅ | `Map<K, V>` → Go `map[K]V`; `.set()`, `.get()`, `.has()`, `.delete()`, `.clear()`, `.size` |
71
- | Set | ✅ | `Set<T>` → Go `map[T]struct{}`; `.add()`, `.has()`, `.delete()`, `.clear()`, `.size` |
69
+ | Feature | Supported | Notes |
70
+ | -------------------------- | :-------: | --------------------------------------------------------------------------------------------- |
71
+ | Arrays | ✅ | Basic array operations |
72
+ | Array methods | ✅ | `push`, `pop`, `shift`, `unshift`, `join`, `slice`, `concat`, `reverse`, `sort`, `flat`, `at` |
73
+ | Higher-order array methods | ✅ | `.map()`, `.filter()`, `.some()`, `.find()`, `.findIndex()`, `.every()`, `.forEach()`, `.reduce()` |
74
+ | Method chaining | ✅ | e.g. `.map(...).filter(...).join(...)` |
75
+ | Map | ✅ | `Map<K, V>` → Go `map[K]V`; `.set()`, `.get()`, `.has()`, `.delete()`, `.clear()`, `.size` |
76
+ | Set | ✅ | `Set<T>` → Go `map[T]struct{}`; `.add()`, `.has()`, `.delete()`, `.clear()`, `.size` |
72
77
 
73
78
  **Functions**
74
79
 
75
- | Feature | Supported | Notes |
76
- | ---------------------------- | :-------: | ------------------------------------------------------------ |
77
- | Function declarations | ✅ | Transpiled to Go functions |
78
- | Arrow functions | ✅ | Transpiled to anonymous functions |
79
- | Closures over mutable state | ✅ | Functions capturing and mutating outer variables |
80
- | Function types | ✅ | `() => number`, `(x: number) => string` as type annotations |
81
- | Generics (functions/classes) | ✅ | Type parameters via Go generics |
82
- | Default parameter values | ✅ | `function(x = defaultValue)` |
80
+ | Feature | Supported | Notes |
81
+ | ---------------------------- | :-------: | ----------------------------------------------------------- |
82
+ | Function declarations | ✅ | Transpiled to Go functions |
83
+ | Arrow functions | ✅ | Transpiled to anonymous functions |
84
+ | IIFEs | ✅ | `(() => { ... })()` and `(function name() { ... })()` |
85
+ | Closures over mutable state | ✅ | Functions capturing and mutating outer variables |
86
+ | Function types | ✅ | `() => number`, `(x: number) => string` as type annotations |
87
+ | Generics (functions/classes) | ✅ | Type parameters via Go generics |
88
+ | Default parameter values | ✅ | `function(x = defaultValue)` |
89
+ | Rest parameters | ✅ | `function(...args: T[])` → Go variadic |
83
90
 
84
91
  **Classes & Interfaces**
85
92
 
@@ -87,6 +94,8 @@ TypeNative currently supports a focused subset of TypeScript syntax elements tha
87
94
  | ------------------- | :-------: | -------------------------------------------------------------- |
88
95
  | Classes | ✅ | Transpiled to Go structs with constructor and receiver methods |
89
96
  | Class inheritance | ✅ | `extends` via embedded structs, `super()` supported |
97
+ | Static members | ✅ | `static method()` / `static prop` → package-level declarations |
98
+ | Getters / Setters | ✅ | `get prop()` → `Get_prop()`, `set prop(v)` → `Set_prop(v)` |
90
99
  | Interfaces | ✅ | Transpiled to Go interfaces, supports `extends` |
91
100
  | Optional properties | ✅ | `prop?: Type` in interfaces/types |
92
101
  | Enums | ✅ | `enum` declarations and member access |
@@ -104,9 +113,16 @@ TypeNative currently supports a focused subset of TypeScript syntax elements tha
104
113
  | Feature | Supported | Notes |
105
114
  | --------------------- | :-------: | ----------------------------------------------------- |
106
115
  | console.log | ✅ | Mapped to `fmt.Println` |
116
+ | console.error | ✅ | Mapped to `fmt.Fprintln(os.Stderr, ...)` |
107
117
  | console.time/timeEnd | ✅ | Performance measurement via `time.Now` / `time.Since` |
108
118
  | assert | ✅ | Transpiled to `panic` on failure |
109
119
  | parseInt / parseFloat | ✅ | Mapped to Go's `strconv` package |
120
+ | JSON.stringify | ✅ | Mapped to `encoding/json` `Marshal` / `MarshalIndent` |
121
+ | JSON.parse | ✅ | Mapped to `encoding/json` `Unmarshal` |
122
+ | Object.keys/values | ✅ | Map key/value iteration helpers |
123
+ | process.argv | ✅ | Mapped to `os.Args` |
124
+ | process.platform | ✅ | Mapped to `runtime.GOOS` |
125
+ | process.exit | ✅ | Mapped to `os.Exit` |
110
126
 
111
127
  **Math Methods**
112
128
 
@@ -116,6 +132,9 @@ TypeNative currently supports a focused subset of TypeScript syntax elements tha
116
132
  | Math.floor / ceil / round | ✅ | Mapped to `math.Floor`, `math.Ceil`, `math.Round` |
117
133
  | Math.abs / sqrt / pow | ✅ | Mapped to corresponding `math` functions |
118
134
  | Math.min / max | ✅ | Mapped to `math.Min`, `math.Max` |
135
+ | Math.log / log2 / log10 | ✅ | Mapped to `math.Log`, `math.Log2`, `math.Log10` |
136
+ | Math.sin / cos / tan | ✅ | Mapped to `math.Sin`, `math.Cos`, `math.Tan` |
137
+ | Math.trunc / sign | ✅ | Mapped to `math.Trunc` and inline sign check |
119
138
 
120
139
  **String Methods**
121
140
 
@@ -129,6 +148,9 @@ TypeNative currently supports a focused subset of TypeScript syntax elements tha
129
148
  | replace / replaceAll | ✅ | Via `strings` package |
130
149
  | charAt / substring / slice | ✅ | Direct Go string indexing/slicing |
131
150
  | concat / repeat | ✅ | String concatenation and `strings.Repeat` |
151
+ | padStart / padEnd | ✅ | Via `strings.Repeat` |
152
+ | match / matchAll / search | ✅ | Via `regexp` package |
153
+ | at | ✅ | Supports negative indices |
132
154
 
133
155
  **Number / Object Methods**
134
156
 
@@ -145,10 +167,17 @@ TypeNative currently supports a focused subset of TypeScript syntax elements tha
145
167
  | test() | ✅ | Mapped to `regexp.MatchString` |
146
168
  | exec() | ✅ | Mapped to `regexp.FindStringSubmatch` |
147
169
 
148
- **Unsupported / Roadmap**
149
-
150
- | Feature | Supported | Notes |
151
- | --------------- | :-------: | -------------------------------- |
152
- | Modules/Imports | | `import` / `export` declarations |
170
+ **Modules & Imports**
171
+
172
+ | Feature | Supported | Notes |
173
+ | ------------------------ | :-------: | ------------------------------------------------------------------ |
174
+ | Named imports | | `import { x } from './file'` |
175
+ | Default imports | ✅ | `import x from 'pkg'` — namespace stripped in output |
176
+ | Namespace imports | ✅ | `import * as x from 'pkg'` |
177
+ | Local file imports | ✅ | Relative paths transpiled to a separate Go file |
178
+ | Node.js built-in imports | ✅ | `import { join } from 'node:path'` mapped to Go stdlib |
179
+ | Go package imports | ✅ | `import { x } from 'go:pkg'` |
180
+ | npm package imports | ✅ | `import { x } from 'pkg'` mapped to Go module imports |
181
+ | Named exports | ✅ | `export function` / `export const` declarations |
153
182
 
154
183
  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/index.js CHANGED
@@ -1,145 +1,281 @@
1
1
  #!/usr/bin/env node
2
2
  import inquirer from 'inquirer';
3
3
  import fs from 'fs-extra';
4
- import path from 'path';
4
+ import path from 'node:path';
5
5
  import { execa } from 'execa';
6
6
  import { transpileToNative } from './transpiler.js';
7
- import { fileURLToPath } from 'url';
7
+ import { fileURLToPath } from 'node:url';
8
8
  const __filename = fileURLToPath(import.meta.url);
9
9
  const __dirname = path.dirname(__filename);
10
10
  (async function main() {
11
- const scriptMode = process.argv.findIndex((a) => a === '--script') > -1;
12
- const newCommand = process.argv.findIndex((a) => a === '--new') > -1;
13
- const sourceIndex = process.argv.findIndex((a) => a === '--source');
14
- const source = sourceIndex > -1 ? process.argv[sourceIndex + 1] : null;
15
- const outputIndex = process.argv.findIndex((a) => a === '--output');
16
- const output = outputIndex > -1 ? process.argv[outputIndex + 1] : null;
17
- const answers = await inquirer.prompt([
18
- {
19
- type: 'input',
20
- name: 'projectName',
21
- message: 'Enter Project Name:',
22
- when: newCommand,
23
- validate: (input) => input.trim() !== ''
24
- },
25
- {
26
- type: 'confirm',
27
- name: 'installDependencies',
28
- message: 'Do you want to install dependencies?',
29
- when: newCommand
30
- },
31
- {
32
- type: 'input',
33
- name: 'path',
34
- message: 'Enter Path to typescript main file:',
35
- when: !newCommand && !scriptMode && !source,
36
- validate: (input) => input.trim() !== ''
37
- },
38
- {
39
- type: 'input',
40
- name: 'output',
41
- message: 'Enter Output Path:',
42
- when: !newCommand && !scriptMode && !output,
43
- validate: (input) => input.trim() !== ''
44
- },
45
- {
46
- type: 'editor',
47
- name: 'tsCode',
48
- message: 'Write your typescript code here:',
49
- when: !newCommand && scriptMode && !source,
50
- default: `console.log('Hello, World!');`
11
+ const scriptMode = process.argv.findIndex((a) => a === '--script') > -1;
12
+ const newCommand = process.argv.findIndex((a) => a === '--new') > -1;
13
+ const sourceIndex = process.argv.findIndex((a) => a === '--source');
14
+ const source = sourceIndex > -1 ? process.argv[sourceIndex + 1] : null;
15
+ const outputIndex = process.argv.findIndex((a) => a === '--output');
16
+ const output = outputIndex > -1 ? process.argv[outputIndex + 1] : null;
17
+ const answers = await inquirer.prompt([
18
+ {
19
+ type: 'input',
20
+ name: 'projectName',
21
+ message: 'Enter Project Name:',
22
+ when: newCommand,
23
+ validate: (input) => input.trim() !== ''
24
+ },
25
+ {
26
+ type: 'confirm',
27
+ name: 'installDependencies',
28
+ message: 'Do you want to install dependencies?',
29
+ when: newCommand
30
+ },
31
+ {
32
+ type: 'input',
33
+ name: 'path',
34
+ message: 'Enter Path to typescript main file:',
35
+ when: !newCommand && !scriptMode && !source,
36
+ validate: (input) => input.trim() !== ''
37
+ },
38
+ {
39
+ type: 'input',
40
+ name: 'output',
41
+ message: 'Enter Output Path:',
42
+ when: !newCommand && !scriptMode && !output,
43
+ validate: (input) => input.trim() !== ''
44
+ },
45
+ {
46
+ type: 'editor',
47
+ name: 'tsCode',
48
+ message: 'Write your typescript code here:',
49
+ when: !newCommand && scriptMode && !source,
50
+ default: `console.log('Hello, World!');`
51
+ }
52
+ ]);
53
+ if (newCommand) {
54
+ const projectName = answers.projectName.trim();
55
+ await fs.ensureDir(projectName);
56
+ await fs.writeFile(path.join(projectName, 'main.ts'), `// Write your TypeScript code here\nconsole.log('Hello, World!');\n`, { encoding: 'utf-8' });
57
+ await fs.writeFile(path.join(projectName, 'tsconfig.json'), getTsConfig(), {
58
+ encoding: 'utf-8'
59
+ });
60
+ await fs.writeFile(path.join(projectName, 'package.json'), getPackageJson(projectName), {
61
+ encoding: 'utf-8'
62
+ });
63
+ await fs.writeFile(path.join(projectName, '.gitignore'), getGitIgnore(), {
64
+ encoding: 'utf-8'
65
+ });
66
+ await fs.writeFile(path.join(projectName, 'README.md'), getReadMe(projectName), {
67
+ encoding: 'utf-8'
68
+ });
69
+ console.log(`Project "${projectName}" created successfully!`);
70
+ if (answers.installDependencies) {
71
+ console.log('Installing dependencies...');
72
+ await execa('npm', ['install'], { cwd: projectName, stdio: 'inherit' });
73
+ console.log('Dependencies installed successfully!');
74
+ }
75
+ return;
51
76
  }
52
- ]);
53
- if (newCommand) {
54
- const projectName = answers.projectName.trim();
55
- await fs.ensureDir(projectName);
56
- await fs.writeFile(
57
- path.join(projectName, 'main.ts'),
58
- `// Write your TypeScript code here\nconsole.log('Hello, World!');\n`,
59
- { encoding: 'utf-8' }
60
- );
61
- await fs.writeFile(path.join(projectName, 'tsconfig.json'), getTsConfig(), {
62
- encoding: 'utf-8'
63
- });
64
- await fs.writeFile(path.join(projectName, 'package.json'), getPackageJson(projectName), {
65
- encoding: 'utf-8'
66
- });
67
- await fs.writeFile(path.join(projectName, '.gitignore'), getGitIgnore(), {
68
- encoding: 'utf-8'
69
- });
70
- await fs.writeFile(path.join(projectName, 'README.md'), getReadMe(projectName), {
71
- encoding: 'utf-8'
72
- });
73
- console.log(`Project "${projectName}" created successfully!`);
74
- if (answers.installDependencies) {
75
- console.log('Installing dependencies...');
76
- await execa('npm', ['install'], { cwd: projectName, stdio: 'inherit' });
77
- console.log('Dependencies installed successfully!');
77
+ const sourcePath = answers.tsCode ? null : (source ?? answers.path ?? null);
78
+ const tsCode = answers.tsCode
79
+ ? answers.tsCode
80
+ : await fs.readFile(sourcePath, { encoding: 'utf-8' });
81
+ const sourceDir = sourcePath ? path.dirname(path.resolve(sourcePath)) : null;
82
+ const transpileResult = transpileToNative(tsCode, sourceDir
83
+ ? {
84
+ readFile: (specifier, fromDir) => {
85
+ const baseDir = fromDir ?? sourceDir;
86
+ // Relative or absolute path resolve from baseDir
87
+ if (specifier.startsWith('.') || specifier.startsWith('/')) {
88
+ for (const candidate of [specifier + '.ts', specifier]) {
89
+ try {
90
+ const fullPath = path.resolve(baseDir, candidate);
91
+ return {
92
+ content: fs.readFileSync(fullPath, 'utf-8'),
93
+ dir: path.dirname(fullPath)
94
+ };
95
+ }
96
+ catch {
97
+ /* not found */
98
+ }
99
+ }
100
+ return null;
101
+ }
102
+ // npm package — walk up from baseDir looking for node_modules/<name>
103
+ const resolved = resolveNpmPackage(baseDir, specifier);
104
+ if (!resolved)
105
+ return null;
106
+ let { content, dir } = resolved;
107
+ // Normalize CommonJS to ES module syntax
108
+ if (!content.includes('export ') && (content.includes('module.exports') || content.includes('exports.'))) {
109
+ content = normalizeCjsContent(content);
110
+ }
111
+ // Inject types from a local ambient .d.ts if available
112
+ const typed = tryInjectDtsTypes(content, specifier, sourceDir);
113
+ if (typed)
114
+ content = typed;
115
+ return { content, dir };
116
+ }
117
+ }
118
+ : undefined);
119
+ const exeName = process.platform === 'win32' ? 'native.exe' : 'native';
120
+ const exePath = `dist/${exeName}`;
121
+ await fs.ensureDir('dist');
122
+ // Clean up stale Go files from previous runs before writing new ones
123
+ for (const existing of await fs.readdir('dist')) {
124
+ if (existing.endsWith('.go'))
125
+ await fs.remove(`dist/${existing}`);
126
+ }
127
+ await fs.writeFile('dist/code.go', transpileResult.main, { encoding: 'utf-8' });
128
+ const goFiles = ['dist/code.go'];
129
+ for (const [filename, content] of transpileResult.files) {
130
+ await fs.writeFile(`dist/${filename}`, content, { encoding: 'utf-8' });
131
+ goFiles.push(`dist/${filename}`);
78
132
  }
79
- return;
80
- }
81
- const tsCode = answers.tsCode
82
- ? answers.tsCode
83
- : await fs.readFile(source ?? answers.path, { encoding: 'utf-8' });
84
- const nativeCode = transpileToNative(tsCode);
85
- const exeName = process.platform === 'win32' ? 'native.exe' : 'native';
86
- const exePath = `dist/${exeName}`;
87
- await fs.ensureDir('dist');
88
- await fs.writeFile('dist/code.go', nativeCode, { encoding: 'utf-8' });
89
- await execa('go', ['build', '-o', exePath, 'dist/code.go'], {
90
- stdio: 'inherit'
91
- });
92
- // await fs.remove('dist/code.go');
93
- if (scriptMode) {
94
- await execa(exePath, {
95
- stdio: 'inherit'
133
+ await execa('go', ['build', '-o', exePath, ...goFiles], {
134
+ stdio: 'inherit'
96
135
  });
97
- //await fs.remove(exePath);
98
- } else if (output || answers.output) {
99
- await fs.copy(exePath, output ?? answers.output, { overwrite: true });
100
- //await fs.remove(exePath);
101
- console.log(`Created native executable at: ${output ?? answers.output}`);
102
- }
136
+ // await fs.remove('dist/code.go');
137
+ if (scriptMode) {
138
+ await execa(exePath, {
139
+ stdio: 'inherit'
140
+ });
141
+ //await fs.remove(exePath);
142
+ }
143
+ else if (output || answers.output) {
144
+ await fs.copy(exePath, output ?? answers.output, { overwrite: true });
145
+ //await fs.remove(exePath);
146
+ console.log(`Created native executable at: ${output ?? answers.output}`);
147
+ }
103
148
  })();
104
- function getPackageJson(projectName) {
105
- const exeName = process.platform === 'win32' ? `${projectName}.exe` : projectName;
106
- const pckg = {
107
- name: projectName,
108
- version: '1.0.0',
109
- scripts: {
110
- execute: 'npx typenative --source main.ts --script',
111
- build: `npx typenative --source main.ts --output bin/${exeName}`
112
- },
113
- devDependencies: {
114
- typenative: '^0.0.16'
149
+ function normalizeCjsContent(code) {
150
+ code = code.replace(/['"]use strict['"];?\n?/g, '');
151
+ code = code.replace(/(?:module\.exports|exports)\.(\w+)\s*=\s*function\s*\w*\s*\(/g, 'export function $1(');
152
+ return code;
153
+ }
154
+ function tryInjectDtsTypes(jsContent, packageName, searchDir) {
155
+ if (!searchDir)
156
+ return null;
157
+ // Look for *.d.ts files in searchDir that declare the module
158
+ let dtsBody = null;
159
+ try {
160
+ const escaped = packageName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
161
+ for (const file of fs.readdirSync(searchDir)) {
162
+ if (!file.endsWith('.d.ts'))
163
+ continue;
164
+ const content = fs.readFileSync(path.join(searchDir, file), 'utf-8');
165
+ const match = content.match(new RegExp(`declare module ['"]${escaped}['"][^{]*\\{([\\s\\S]*?)\\}`));
166
+ if (match) {
167
+ dtsBody = match[1];
168
+ break;
169
+ }
170
+ }
115
171
  }
116
- };
117
- return JSON.stringify(pckg, null, 2);
172
+ catch {
173
+ return null;
174
+ }
175
+ if (!dtsBody)
176
+ return null;
177
+ // Extract typed function signatures from the .d.ts module body
178
+ const signatures = new Map();
179
+ const sigRegex = /export function (\w+)\(([^)]*)\)\s*:\s*([^\n;]+)/g;
180
+ let m;
181
+ while ((m = sigRegex.exec(dtsBody)) !== null) {
182
+ signatures.set(m[1], { params: m[2].trim(), returnType: m[3].trim() });
183
+ }
184
+ if (signatures.size === 0)
185
+ return null;
186
+ // Replace untyped signatures in the normalized JS with typed ones from .d.ts
187
+ return jsContent.replace(/export function (\w+)\s*\(([^)]*)\)/g, (match, name) => {
188
+ const sig = signatures.get(name);
189
+ if (!sig)
190
+ return match;
191
+ return `export function ${name}(${sig.params}): ${sig.returnType}`;
192
+ });
118
193
  }
119
- function getTsConfig() {
120
- const tsConfig = {
121
- include: ['**/*.ts'],
122
- compilerOptions: {
123
- target: 'es2020',
124
- lib: [],
125
- types: ['./node_modules/typenative/types/typenative.d.ts'],
126
- rootDir: '.',
127
- strict: true,
128
- noImplicitAny: true
194
+ function resolveNpmPackage(fromDir, packageName) {
195
+ // Walk up the directory tree looking for node_modules/<packageName>
196
+ let searchDir = fromDir;
197
+ while (true) {
198
+ const pkgDir = path.join(searchDir, 'node_modules', packageName);
199
+ const pkgJsonPath = path.join(pkgDir, 'package.json');
200
+ try {
201
+ const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));
202
+ // Build candidate entry points: TypeScript preferred, JavaScript as fallback
203
+ const tsCandidates = [];
204
+ const jsCandidates = [];
205
+ for (const field of ['source', 'main', 'module']) {
206
+ const entry = pkgJson[field];
207
+ if (!entry)
208
+ continue;
209
+ if (entry.endsWith('.ts'))
210
+ tsCandidates.push(entry);
211
+ else if (entry.endsWith('.js')) {
212
+ tsCandidates.push(entry.replace(/\.js$/, '.ts'));
213
+ jsCandidates.push(entry);
214
+ }
215
+ }
216
+ tsCandidates.push('index.ts', 'src/index.ts');
217
+ jsCandidates.push('index.js', 'src/index.js');
218
+ const candidates = [...tsCandidates, ...jsCandidates];
219
+ for (const candidate of candidates) {
220
+ const fullPath = path.resolve(pkgDir, candidate);
221
+ try {
222
+ return { content: fs.readFileSync(fullPath, 'utf-8'), dir: path.dirname(fullPath) };
223
+ }
224
+ catch {
225
+ /* try next candidate */
226
+ }
227
+ }
228
+ }
229
+ catch {
230
+ /* no package.json here, keep walking up */
231
+ }
232
+ const parent = path.dirname(searchDir);
233
+ if (parent === searchDir)
234
+ break; // filesystem root
235
+ searchDir = parent;
129
236
  }
130
- };
131
- return JSON.stringify(tsConfig, null, 2);
237
+ return null;
238
+ }
239
+ function getPackageJson(projectName) {
240
+ const exeName = process.platform === 'win32' ? `${projectName}.exe` : projectName;
241
+ const pckg = {
242
+ name: projectName,
243
+ version: '1.0.0',
244
+ scripts: {
245
+ execute: 'npx typenative --source main.ts --script',
246
+ build: `npx typenative --source main.ts --output bin/${exeName}`
247
+ },
248
+ devDependencies: {
249
+ typenative: '^0.0.19'
250
+ }
251
+ };
252
+ return JSON.stringify(pckg, null, 2);
253
+ }
254
+ function getTsConfig() {
255
+ const tsConfig = {
256
+ include: ['**/*.ts'],
257
+ compilerOptions: {
258
+ target: 'es2020',
259
+ lib: [],
260
+ types: ['typenative', 'typenative/go', 'typenative/npm'],
261
+ rootDir: '.',
262
+ strict: true,
263
+ noImplicitAny: true,
264
+ allowSyntheticDefaultImports: true
265
+ }
266
+ };
267
+ return JSON.stringify(tsConfig, null, 2);
132
268
  }
133
269
  function getGitIgnore() {
134
- return `# TypeNative generated files
270
+ return `# TypeNative generated files
135
271
  node_modules/
136
272
  dist/
137
273
  bin/
138
274
  `;
139
275
  }
140
276
  function getReadMe(projectName) {
141
- const exeName = process.platform === 'win32' ? `${projectName}.exe` : projectName;
142
- return `# ${projectName}
277
+ const exeName = process.platform === 'win32' ? `${projectName}.exe` : projectName;
278
+ return `# ${projectName}
143
279
 
144
280
  This project was created using TypeNative, a tool to transpile TypeScript code to native Go code.
145
281