typenative 0.0.21 → 0.1.1
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/ci.yml +29 -0
- package/.github/workflows/npm-publish-github-packages.yml +3 -3
- package/CHANGELOG.md +81 -0
- package/CONTRIBUTION.md +130 -0
- package/README.md +258 -183
- package/bin/index.js +2 -3
- package/bin/parse-node.js +2 -2
- package/bin/transpiler.js +6914 -1686
- package/conformance.md +651 -0
- package/package.json +10 -41
- package/tsparser/main.go +2 -2
- package/tsparser/tsparser.exe +2 -2
- package/TODO.md +0 -34
package/README.md
CHANGED
|
@@ -1,183 +1,258 @@
|
|
|
1
|
-
# TypeNative
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
51
|
-
|
|
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
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
|
117
|
-
|
|
|
118
|
-
|
|
|
119
|
-
|
|
|
120
|
-
|
|
|
121
|
-
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
|
142
|
-
|
|
|
143
|
-
|
|
|
144
|
-
|
|
|
145
|
-
|
|
|
146
|
-
|
|
|
147
|
-
|
|
|
148
|
-
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
1
|
+
# TypeNative
|
|
2
|
+
|
|
3
|
+
TypeNative is a TypeScript-to-Go transpiler, it turns TypeScript into Go code and compiles it to a single-file native executable — no Node.js runtime, no bundler, just a binary. Write TypeScript, ship native binaries.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
// hello.ts
|
|
7
|
+
console.log('Hello, native world!');
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
npx typenative --source hello.ts --script
|
|
12
|
+
# Hello, native world!
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
> Early development: the supported language subset grows with every release. See [conformance.md](conformance.md) for exactly what transpiles today.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Contents
|
|
20
|
+
|
|
21
|
+
- [Requirements](#requirements)
|
|
22
|
+
- [Install](#install)
|
|
23
|
+
- [Quick start](#quick-start)
|
|
24
|
+
- [CLI reference](#cli-reference)
|
|
25
|
+
- [Writing TypeNative-compatible TypeScript](#writing-typenative-compatible-typescript)
|
|
26
|
+
- [Examples](#examples)
|
|
27
|
+
- [How it works](#how-it-works)
|
|
28
|
+
- [Testing and conformance](#testing-and-conformance)
|
|
29
|
+
- [Self-hosted native compiler](#self-hosted-native-compiler)
|
|
30
|
+
- [License](#license)
|
|
31
|
+
|
|
32
|
+
## Requirements
|
|
33
|
+
|
|
34
|
+
- [Node.js v24](https://nodejs.org/en) or newer.
|
|
35
|
+
- [Go 1.26](https://go.dev/doc/install) or newer.
|
|
36
|
+
|
|
37
|
+
## Install
|
|
38
|
+
|
|
39
|
+
Use without installing:
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
npx typenative --source main.ts --script
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Or add to a project:
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
npm install typenative -D
|
|
49
|
+
npx typenative --source main.ts --output ./bin/myapp
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Generated projects pin it automatically as a dev dependency.
|
|
53
|
+
|
|
54
|
+
## Quick start
|
|
55
|
+
|
|
56
|
+
**1. Run a snippet directly (script mode):**
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
npx typenative --source hello.ts --script
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Transpiles `hello.ts` to `dist/code.go`, builds `dist/native(.exe)`, runs it, and forwards its exit code.
|
|
63
|
+
|
|
64
|
+
**2. Build a distributable binary:**
|
|
65
|
+
|
|
66
|
+
```sh
|
|
67
|
+
npx typenative --source main.ts --output ./bin/myapp
|
|
68
|
+
# Windows: --output ./bin/myapp.exe
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**3. Interactive mode (no flags):**
|
|
72
|
+
|
|
73
|
+
```sh
|
|
74
|
+
npx typenative
|
|
75
|
+
# prompts for TypeScript entry file and output path
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
npx typenative --script
|
|
80
|
+
# opens an editor prompt; runs what you type without saving a file
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**4. Scaffold a new project:**
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
npx typenative --new
|
|
87
|
+
# prompts for project name + whether to npm install
|
|
88
|
+
# creates main.ts, package.json (with execute/build scripts), tsconfig.json, README.md, .gitignore
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The scaffolded `package.json` gives you:
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"scripts": {
|
|
96
|
+
"execute": "npx typenative --source main.ts --script",
|
|
97
|
+
"build": "npx typenative --source main.ts --output bin/<name>"
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Scaffolded `tsconfig.json` targets the TypeNative type surface:
|
|
103
|
+
|
|
104
|
+
```json
|
|
105
|
+
{
|
|
106
|
+
"compilerOptions": {
|
|
107
|
+
"target": "es2020",
|
|
108
|
+
"strict": true,
|
|
109
|
+
"types": ["typenative", "typenative/go", "typenative/npm"]
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## CLI reference
|
|
115
|
+
|
|
116
|
+
| Flag | Mode | Description |
|
|
117
|
+
| ----------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
118
|
+
| `--source <file>` | build / script | TypeScript entry file. Relative imports (`./util`) and npm packages are resolved from its directory. |
|
|
119
|
+
| `--output <path>` | build | Where to copy the compiled binary. If omitted with `--script`, the temp binary in `dist/` is executed and kept there. |
|
|
120
|
+
| `--script` | run | Build to `dist/native(.exe)` and execute immediately with inherited stdio. Combine with `--source`, or omit `--source` to type code into the prompt. |
|
|
121
|
+
| `--new` | scaffold | Create a new project directory (`main.ts`, `package.json`, `tsconfig.json`, `README.md`, `.gitignore`). |
|
|
122
|
+
|
|
123
|
+
Exit codes from `--script` are the exit code of your program. A non-zero `go build` prints `go build failed:` plus the compiler output and exits `1`.
|
|
124
|
+
|
|
125
|
+
## Writing TypeNative-compatible TypeScript
|
|
126
|
+
|
|
127
|
+
TypeNative supports a growing subset of TypeScript, not the whole language. The source of truth is [conformance.md](conformance.md) — every supported feature links to a runnable probe in [conformance/](conformance/).
|
|
128
|
+
|
|
129
|
+
**Language highlights that work today:**
|
|
130
|
+
|
|
131
|
+
- `let`/`const`, functions, arrow functions, closures, recursion, rest/spread, default and optional params, destructured params.
|
|
132
|
+
- Classes (inheritance, static members, getters, parameter properties, abstract, `implements`), interfaces, type aliases, generics, enums (numeric + string).
|
|
133
|
+
- `if`/`switch` (incl. fallthrough), `for`/`for...of`/`while`/`do...while`, `try`/`catch`/`finally` (`throw` → `panic`, catch via `defer`/`recover`), ternaries, optional chaining, nullish coalescing, `in`, `typeof`, `instanceof`.
|
|
134
|
+
- `async`/`await`, generators, custom iterators, tagged templates.
|
|
135
|
+
|
|
136
|
+
**Standard library that works today:**
|
|
137
|
+
|
|
138
|
+
| Area | What to use |
|
|
139
|
+
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
140
|
+
| Console | `console.log`, `assert` (→ `panic` on failure) |
|
|
141
|
+
| `Array` | `push`/`pop`, `slice`/`splice`, `map`/`filter`/`reduce`, `find`/`some`/`every`, `sort` with comparator, `flat`/`flatMap`, `at`, `entries`, `join`, `reverse`, `shift`/`unshift` |
|
|
142
|
+
| `Object` | `assign`, `keys`/`values`/`entries`, spread of records → Go maps |
|
|
143
|
+
| `String` | `split`/`slice`/`replace`, `padStart`/`padEnd`, `repeat`, search/compare, char codes, unicode |
|
|
144
|
+
| `Number`/`Math` | `parseInt`/`parseFloat`, `toFixed`/`toString(radix)`, `isInteger`/`isNaN`, `min`/`max`/`random` |
|
|
145
|
+
| `Map`/`Set` | Full `set`/`get`/`has`/`delete`/`size` plus `for...of` iteration (→ Go maps) |
|
|
146
|
+
| `JSON` | `parse` / `stringify` |
|
|
147
|
+
| `RegExp` | Literals + `new RegExp()`, `test()`, `exec()` with groups, `i`/`m` flags (backreferences, named groups, stateful `/g` loops and lookbehind are not supported — Go `regexp` limitation) |
|
|
148
|
+
| `process` | `argv` (→ `os.Args`), `platform` (→ `runtime.GOOS`), `env` |
|
|
149
|
+
|
|
150
|
+
**Node built-ins (import with the `node:` prefix, mapped to Go helpers):**
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
import path from 'node:path';
|
|
154
|
+
import * as fs from 'node:fs';
|
|
155
|
+
import { platform } from 'node:os';
|
|
156
|
+
import * as childProcess from 'node:child_process';
|
|
157
|
+
|
|
158
|
+
path.join('a', 'b');
|
|
159
|
+
fs.readFileSync('file.txt', 'utf-8');
|
|
160
|
+
childProcess.spawnSync('go', ['version'], { encoding: 'utf-8' });
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Supported: `node:path` (`join`, `dirname`, `basename`, `extname`, `resolve`), `node:fs` (`read/write/append/exists/mkdir/readdir/copy/rm`), `node:os` (`platform`, `homedir`, `tmpdir`), `node:child_process` (sync `exec`/`execSync`/`spawnSync`/`spawnInherit` shape). `node:readline.question()` exists as a TypeNative sync extension for self-hosted prompts.
|
|
164
|
+
|
|
165
|
+
**Direct Go access (import with the `go:` prefix):**
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
import { Println, Sprintf } from 'go:fmt';
|
|
169
|
+
import { ToUpper } from 'go:strings';
|
|
170
|
+
|
|
171
|
+
Println(Sprintf('hi %s', ToUpper('bob')));
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Supported: `go:fmt` (`Println`, `Sprintf`), `go:strings` (`ToUpper`, `ToLower`), `go:strconv` (`FormatBool`).
|
|
175
|
+
|
|
176
|
+
**npm packages:**
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
import { helper } from 'my-lib';
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Resolved by walking up to `node_modules/<name>` (TypeScript source preferred, CommonJS normalized to ESM). Local ambient `.d.ts` declarations (`declare module "my-lib" { ... }`) are used to inject precise parameter/return types.
|
|
183
|
+
|
|
184
|
+
Type mappings to keep in mind: `number` → `float64`, `boolean` → `bool`, nullable `T | null` → Go pointer, `Record<K, V>` / key-indexed objects → Go maps, object types → Go structs (copied by value, unlike JS references).
|
|
185
|
+
|
|
186
|
+
## Examples
|
|
187
|
+
|
|
188
|
+
Hello world:
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
console.log('Hello, World!');
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
```sh
|
|
195
|
+
npx typenative --source hello.ts --script
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Files and paths:
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
import path from 'node:path';
|
|
202
|
+
import * as fs from 'node:fs';
|
|
203
|
+
|
|
204
|
+
const dir: string = path.dirname(path.resolve('data.txt'));
|
|
205
|
+
const text: string = fs.readFileSync(path.join(dir, 'data.txt'), 'utf-8');
|
|
206
|
+
console.log(text.toUpperCase());
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Classes and maps:
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
class Counter {
|
|
213
|
+
count: number = 0;
|
|
214
|
+
inc(): void {
|
|
215
|
+
this.count++;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const seen: Map<string, number> = new Map();
|
|
220
|
+
seen.set('a', 1);
|
|
221
|
+
const c: Counter = new Counter();
|
|
222
|
+
c.inc();
|
|
223
|
+
console.log(`count=${c.count} seen=${seen.get('a')}`);
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## How it works
|
|
227
|
+
|
|
228
|
+
```text
|
|
229
|
+
main.ts --(parse)--> normalized JSON AST --(transpileToNative)--> dist/code.go --(go build)--> dist/native(.exe) --run/copy--> your binary
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
- **Parse:** Node CLI uses the `typescript` npm package (`src/parse-node.ts`); the self-hosted binary spawns the Go `tsparser` tool (`src/parse-native.ts`). Both emit the same `{ kind: "Xxx", ... }` JSON shape so one transpiler consumes either.
|
|
233
|
+
- **Transpile:** `transpileToNative(code, { parse, readFile })` in `src/transpiler.ts` lowers the AST to Go, resolving relative and npm imports into additional Go files (`TranspileResult { main, files }`).
|
|
234
|
+
- **Build:** `run()` in `src/index.ts` writes `dist/code.go` (+ one Go file per module), cleans stale `dist/*.go`, shells out to `go build -o dist/native(.exe)`, then either executes it (`--script`, stdio inherited) or copies it to `--output`.
|
|
235
|
+
|
|
236
|
+
## Testing and conformance
|
|
237
|
+
|
|
238
|
+
`npm test` is `npm run conformance`: every `conformance/*.ts` probe is transpiled, built with `go`, executed, and must exit `0`. Results print per category (`syntax` / `semantics` / `lib`) plus a total pass rate; any failure exits non-zero and lists the first diagnostic line (`*.go:line`, `panic:`, `Unsupported syntax`, `Error`).
|
|
239
|
+
|
|
240
|
+
CI (`.github/workflows/ci.yml`) runs `npm ci`, `npm run build`, and `npm run conformance` on Ubuntu with Node 24 and Go. Releases are cut from `TypeNative_*` tags via trusted publishing.
|
|
241
|
+
|
|
242
|
+
When adding a feature: add a probe, link it from [conformance.md](conformance.md), and keep the ✅/❌ matrix honest — gaps are documented, not hidden.
|
|
243
|
+
|
|
244
|
+
## Self-hosted native compiler
|
|
245
|
+
|
|
246
|
+
TypeNative compiles itself. `src/main.ts` transpiles to Go and builds into a `typenative` binary that needs no Node.js at runtime and emits the same Go as the npm package:
|
|
247
|
+
|
|
248
|
+
```sh
|
|
249
|
+
npm run build
|
|
250
|
+
npm run build:native # builds native/tsparser + native/typenative side by side
|
|
251
|
+
native/typenative --source app.ts --script
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
`TYPENATIVE_TSPARSER` overrides parser discovery if you move the binaries apart. Verify parity with `node scripts/conformance.mjs --native`.
|
|
255
|
+
|
|
256
|
+
## License
|
|
257
|
+
|
|
258
|
+
MIT — see [LICENSE](LICENSE).
|
package/bin/index.js
CHANGED
|
@@ -149,8 +149,7 @@ function tryInjectDtsTypes(jsContent, packageName, searchDir) {
|
|
|
149
149
|
// Extract typed function signatures from the .d.ts module body
|
|
150
150
|
const signatures = new Map();
|
|
151
151
|
const sigRegex = /export function (\w+)\(([^)]*)\)\s*:\s*([^\n;]+)/g;
|
|
152
|
-
|
|
153
|
-
while ((m = sigRegex.exec(dtsBody)) !== null) {
|
|
152
|
+
for (const m of dtsBody.matchAll(sigRegex)) {
|
|
154
153
|
signatures.set(m[1], { params: m[2].trim(), returnType: m[3].trim() });
|
|
155
154
|
}
|
|
156
155
|
if (signatures.size === 0)
|
|
@@ -218,7 +217,7 @@ function getPackageJson(projectName) {
|
|
|
218
217
|
build: `npx typenative --source main.ts --output bin/${exeName}`
|
|
219
218
|
},
|
|
220
219
|
devDependencies: {
|
|
221
|
-
typenative: '^0.
|
|
220
|
+
typenative: '^0.1.1'
|
|
222
221
|
}
|
|
223
222
|
};
|
|
224
223
|
return JSON.stringify(pckg, null, 2);
|
package/bin/parse-node.js
CHANGED
|
@@ -92,8 +92,8 @@ function convertNode(node) {
|
|
|
92
92
|
if (arr.length > 0)
|
|
93
93
|
obj[key] = arr;
|
|
94
94
|
}
|
|
95
|
-
else if (typeof v === 'number' && key === 'operator') {
|
|
96
|
-
//
|
|
95
|
+
else if (typeof v === 'number' && (key === 'operator' || key === 'token')) {
|
|
96
|
+
// operator / heritage-clause token: emit the kind name (matches the Go producer)
|
|
97
97
|
obj[key] = KIND_NAMES[v] ?? String(v);
|
|
98
98
|
}
|
|
99
99
|
else if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean') {
|