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/README.md CHANGED
@@ -1,183 +1,258 @@
1
- # TypeNative
2
-
3
- Build native applications using Typescript.
4
-
5
- ## PreRequisites
6
-
7
- - [Nodejs v24](https://nodejs.org/en) or newer.
8
- - [Go 1.21](https://go.dev/doc/install) or newer.
9
-
10
- ## Get Started
11
-
12
- - Write a file `test.ts` with content `console.log('Hello World!');` or any other message
13
- - Run `npx typenative --source test.ts --script`
14
-
15
- ## Typescript Syntax Support
16
-
17
- TypeNative currently supports a focused subset of TypeScript syntax elements that are transpiled to Go code. The support is grouped by topic for easier scanning.
18
-
19
- **Basic Types**
20
-
21
- | Feature | Supported | Notes |
22
- | -------------- | :-------: | ------------------------------------------------------------- |
23
- | number | ✅ | Transpiled to `float64` |
24
- | boolean | ✅ | Transpiled to `bool` |
25
- | string | ✅ | |
26
- | null | ✅ | |
27
- | any | ✅ | Used for type inference |
28
- | Nullable types | ✅ | `T \| null` / `T \| undefined` transpiled to Go pointer types |
29
-
30
- **Variables & Objects**
31
-
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` |
39
-
40
- **Operators**
41
-
42
- | Feature | Supported | Notes |
43
- | ------------------------ | :-------: | ------------------------------ |
44
- | Arithmetic operators | ✅ | `+`, `-`, etc. |
45
- | Comparison operators | ✅ | `==`, `!=`, `===`, `!==`, etc. |
46
- | Logical operators | ✅ | `&&`, `\|\|` |
47
- | Increment/Decrement | ✅ | `++`, `--` |
48
- | Spread operator | ✅ | `[...arr]`, `fn(...args)` |
49
- | Non-null assertion (`!`) | ✅ | Stripped during transpilation |
50
- | Ternary expressions | ✅ | `condition ? a : b` |
51
- | Nullish coalescing | ✅ | `??` operator |
52
- | Optional chaining | ✅ | `obj?.prop`, `arr?.[i]` |
53
-
54
- **Control Flow**
55
-
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 |
65
- | Try/Catch/Finally | ✅ | `throw` → `panic`; catch/finally via `defer`/`recover` |
66
-
67
- **Data Structures & Array Methods**
68
-
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` |
77
-
78
- **Functions**
79
-
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 |
90
-
91
- **Classes & Interfaces**
92
-
93
- | Feature | Supported | Notes |
94
- | ------------------- | :-------: | -------------------------------------------------------------- |
95
- | Classes | ✅ | Transpiled to Go structs with constructor and receiver methods |
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)` |
99
- | Interfaces | ✅ | Transpiled to Go interfaces, supports `extends` |
100
- | Optional properties | ✅ | `prop?: Type` in interfaces/types |
101
- | Enums | ✅ | `enum` declarations and member access |
102
-
103
- **Async & Timing**
104
-
105
- | Feature | Supported | Notes |
106
- | ----------- | :-------: | ----------------------------------------------------------------- |
107
- | Async/Await | ✅ | `async` functions return Go channels, `await` reads from channels |
108
- | Promises | ✅ | `new Promise` transpiled to channel + goroutine pattern |
109
- | setTimeout | ✅ | Mapped to Go's `time.AfterFunc` |
110
-
111
- **Built-in Functions & Utilities**
112
-
113
- | Feature | Supported | Notes |
114
- | --------------------- | :-------: | ----------------------------------------------------- |
115
- | console.log | ✅ | Mapped to `fmt.Println` |
116
- | console.error | ✅ | Mapped to `fmt.Fprintln(os.Stderr, ...)` |
117
- | console.time/timeEnd | ✅ | Performance measurement via `time.Now` / `time.Since` |
118
- | assert | ✅ | Transpiled to `panic` on failure |
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` |
126
-
127
- **Math Methods**
128
-
129
- | Feature | Supported | Notes |
130
- | ------------------------- | :-------: | ------------------------------------------------- |
131
- | Math.random | ✅ | Mapped to `rand.Float64()` |
132
- | Math.floor / ceil / round | ✅ | Mapped to `math.Floor`, `math.Ceil`, `math.Round` |
133
- | Math.abs / sqrt / pow | ✅ | Mapped to corresponding `math` functions |
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 |
138
-
139
- **String Methods**
140
-
141
- | Feature | Supported | Notes |
142
- | -------------------------- | :-------: | --------------------------------------------- |
143
- | Template literals | ✅ | Backtick strings with `${expr}` interpolation |
144
- | toUpperCase / toLowerCase | ✅ | Via `strings` package |
145
- | trim / trimStart / trimEnd | ✅ | Via `strings` package |
146
- | split / includes / indexOf | ✅ | Via `strings` package |
147
- | startsWith / endsWith | ✅ | Via `strings` package |
148
- | replace / replaceAll | ✅ | Via `strings` package |
149
- | charAt / substring / slice | ✅ | Direct Go string indexing/slicing |
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 |
154
-
155
- **Number / Object Methods**
156
-
157
- | Feature | Supported | Notes |
158
- | -------- | :-------: | ----------------------------------------------------- |
159
- | toString | ✅ | Universal `toString()` via `fmt.Sprintf` for any type |
160
-
161
- **RegExp**
162
-
163
- | Feature | Supported | Notes |
164
- | -------------- | :-------: | --------------------------------------------------- |
165
- | Regex literals | ✅ | `/pattern/flags` transpiled to `regexp.MustCompile` |
166
- | new RegExp() | ✅ | Constructor with optional flags |
167
- | test() | ✅ | Mapped to `regexp.MatchString` |
168
- | exec() | ✅ | Mapped to `regexp.FindStringSubmatch` |
169
-
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 |
182
-
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.
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
- let m;
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.0.19'
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
- // unary operator: emit the kind name (matches the Go producer)
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') {