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/.github/workflows/npm-publish-github-packages.yml +2 -0
- package/CHANGELOG.md +37 -0
- package/README.md +62 -33
- package/bin/index.js +255 -119
- package/bin/transpiler.js +656 -24
- package/go.d.ts +1 -0
- package/index.d.ts +1 -0
- package/npm.d.ts +1 -0
- package/package.json +14 -6
- package/types/typenative-go.d.ts +15 -0
- package/types/typenative-npm.d.ts +5 -0
- package/types/typenative.d.ts +102 -2
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
|
|
33
|
-
|
|
|
34
|
-
| Variable declarations
|
|
35
|
-
| Object 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 | ✅ |
|
|
58
|
-
|
|
|
59
|
-
|
|
|
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 | ✅ |
|
|
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
|
-
|
|
|
80
|
-
|
|
|
81
|
-
|
|
|
82
|
-
|
|
|
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
|
-
**
|
|
149
|
-
|
|
150
|
-
| Feature
|
|
151
|
-
|
|
|
152
|
-
|
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
-
|
|
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(
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
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
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
142
|
-
|
|
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
|
|