xbintsc 0.3.46 → 0.3.49

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.
Files changed (91) hide show
  1. package/AGENTS.md +95 -0
  2. package/README.md +25 -0
  3. package/README.zh-CN.md +23 -0
  4. package/dist/src/cli/hints.d.ts +54 -0
  5. package/dist/src/cli/hints.js +165 -0
  6. package/dist/src/cli/hints.js.map +1 -0
  7. package/dist/src/cli/main.js +73 -9
  8. package/dist/src/cli/main.js.map +1 -1
  9. package/dist/src/codegen/generator/tables.d.ts +26 -0
  10. package/dist/src/codegen/generator/tables.js +64 -12
  11. package/dist/src/codegen/generator/tables.js.map +1 -1
  12. package/dist/src/diagnostics/source-text.d.ts +22 -0
  13. package/dist/src/diagnostics/source-text.js +76 -0
  14. package/dist/src/diagnostics/source-text.js.map +1 -0
  15. package/dist/src/driver/bundler/graph.js +2 -1
  16. package/dist/src/driver/bundler/graph.js.map +1 -1
  17. package/dist/src/driver/compiler.js +3 -2
  18. package/dist/src/driver/compiler.js.map +1 -1
  19. package/dist/src/lexer/scanner/strings.js +16 -3
  20. package/dist/src/lexer/scanner/strings.js.map +1 -1
  21. package/dist/tests/cli/hints.test.d.ts +9 -0
  22. package/dist/tests/cli/hints.test.js +143 -0
  23. package/dist/tests/cli/hints.test.js.map +1 -0
  24. package/dist/tests/cli/main.test.js +6 -4
  25. package/dist/tests/cli/main.test.js.map +1 -1
  26. package/dist/tests/codegen/llvm.test.js +17 -2
  27. package/dist/tests/codegen/llvm.test.js.map +1 -1
  28. package/dist/tests/helpers.js +3 -2
  29. package/dist/tests/helpers.js.map +1 -1
  30. package/dist/tests/lexer/strings.test.js +14 -2
  31. package/dist/tests/lexer/strings.test.js.map +1 -1
  32. package/doc/DESIGN.md +117 -0
  33. package/doc/ai/README.md +63 -0
  34. package/doc/ai/build-recipe.md +137 -0
  35. package/doc/ai/cli.md +142 -0
  36. package/doc/ai/contributing.md +196 -0
  37. package/doc/ai/extensions.md +148 -0
  38. package/doc/ai/language-support.md +152 -0
  39. package/doc/ai/troubleshooting.md +163 -0
  40. package/doc/ai/zh-CN/README.md +56 -0
  41. package/doc/ai/zh-CN/build-recipe.md +132 -0
  42. package/doc/ai/zh-CN/cli.md +127 -0
  43. package/doc/ai/zh-CN/contributing.md +173 -0
  44. package/doc/ai/zh-CN/extensions.md +139 -0
  45. package/doc/ai/zh-CN/language-support.md +147 -0
  46. package/doc/ai/zh-CN/troubleshooting.md +150 -0
  47. package/doc/gui-scripts.md +350 -0
  48. package/doc/gui.md +646 -0
  49. package/doc/icon.md +265 -0
  50. package/doc/implemented.md +373 -0
  51. package/doc/node-implemented.md +588 -0
  52. package/doc/node-unimplemented.md +167 -0
  53. package/doc/post/announce.md +43 -0
  54. package/doc/requirements.md +145 -0
  55. package/doc/unimplemented.md +286 -0
  56. package/doc/xbintsc.config.schema.json +67 -0
  57. package/doc/zh-CN/DESIGN.md +104 -0
  58. package/doc/zh-CN/gui-scripts.md +329 -0
  59. package/doc/zh-CN/gui.md +588 -0
  60. package/doc/zh-CN/icon.md +241 -0
  61. package/doc/zh-CN/implemented.md +365 -0
  62. package/doc/zh-CN/node-implemented.md +533 -0
  63. package/doc/zh-CN/node-unimplemented.md +141 -0
  64. package/doc/zh-CN/plan-require-node-modules.md +284 -0
  65. package/doc/zh-CN/post/announce.md +47 -0
  66. package/doc/zh-CN/requirements.md +134 -0
  67. package/doc/zh-CN/unimplemented.md +247 -0
  68. package/llms.txt +45 -0
  69. package/package.json +4 -1
  70. package/runtime/ext_gui/gui.cpp +3 -1
  71. package/runtime/ext_gui/renderer.cpp +13 -11
  72. package/runtime/ext_gui/renderer_image.cpp +12 -8
  73. package/runtime/ext_gui/renderer_shaders.h +131 -4
  74. package/runtime/ext_gui/renderer_shaders_data.h +1809 -0
  75. package/runtime/ext_gui/renderer_text.cpp +12 -8
  76. package/runtime/ext_gui/shaders.hlsl +98 -0
  77. package/runtime/ext_gui/spirv/fill.frag +19 -0
  78. package/runtime/ext_gui/spirv/fill.vert +42 -0
  79. package/runtime/ext_gui/spirv/image.frag +16 -0
  80. package/runtime/ext_gui/spirv/quad.vert +30 -0
  81. package/runtime/ext_gui/spirv/text.frag +16 -0
  82. package/scripts/build-gui-shaders.mjs +204 -0
  83. package/scripts/build-gui.ts +35 -0
  84. package/scripts/check-file-length.ts +5 -1
  85. package/src/cli/hints.ts +194 -0
  86. package/src/cli/main.ts +82 -9
  87. package/src/codegen/generator/tables.ts +60 -14
  88. package/src/diagnostics/source-text.ts +78 -0
  89. package/src/driver/bundler/graph.ts +2 -1
  90. package/src/driver/compiler.ts +3 -2
  91. package/src/lexer/scanner/strings.ts +16 -3
@@ -0,0 +1,588 @@
1
+ # xbintsc Node Extension Implemented Features
2
+
3
+ This document was compiled by checking the Node extension source
4
+ (`src/extensions/node/`) and the C runtime (`runtime/ext_node/`) file by file,
5
+ and lists the features and interfaces that the **Node extension actually
6
+ provides today**.
7
+
8
+ > Related documents:
9
+ > - Core language capabilities: [implemented.md](./implemented.md) / [unimplemented.md](./unimplemented.md)
10
+ > - Unimplemented parts of the Node extension: [node-unimplemented.md](./node-unimplemented.md)
11
+
12
+ > Language: **English** | [简体中文](./zh-CN/node-implemented.md)
13
+
14
+ ---
15
+
16
+ ## 1. Extension mechanism (implemented)
17
+
18
+ Location: `src/extensions/node/index.ts`, `src/extensions/node/module.ts`, `src/extensions/registry.ts`
19
+
20
+ - The Node extension plugs in through the uniform `Extension` object; its C sources are compiled and linked only when it is registered.
21
+ - Enable it via the CLI:
22
+
23
+ ```bash
24
+ xbintsc run examples/node/read.ts --ext node
25
+ ```
26
+
27
+ - Modular organisation: one subdirectory per Node module, in one-to-one correspondence with its C implementation:
28
+
29
+ ```
30
+ src/extensions/node/ runtime/ext_node/
31
+ index.ts # nodeExtension fs/read_file.c
32
+ module.ts # NodeModule iface fs/write_file.c
33
+ fs/index.ts fs/fs_ops.c
34
+ fs/read-file.ts fs/fs_common.h
35
+ fs/write-file.ts fs/promises.c
36
+ fs/fs-ops.ts fs/streams.c
37
+ fs/streams.ts fs/fd_ops.c
38
+ path/index.ts fs/meta_ops.c
39
+ os/index.ts fs/link_ops.c
40
+ process/index.ts fs/copy_ops.c
41
+ buffer/index.ts fs/dir.c
42
+ stream/index.ts fs/glob.c
43
+ net/index.ts fs/watch.c
44
+ dgram/index.ts fs/constants.c
45
+ http/index.ts path/path.c
46
+ fs-promises/index.ts os/os.c
47
+ crypto/index.ts process/process.c
48
+ url/index.ts buffer/buffer.c
49
+ child_process/index.ts stream/stream.c
50
+ events/index.ts net/net.c
51
+ util/index.ts dgram/dgram.c
52
+ querystring/index.ts http/http.c
53
+ assert/index.ts node_common.h (event emitter / encoding helpers)
54
+ test/index.ts crypto/crypto.c
55
+ zlib/index.ts url/url.c
56
+ stream-promises/index.ts child_process/child_process.c
57
+ worker_threads/index.ts events/events.c
58
+ util/util.c
59
+ querystring/querystring.c
60
+ assert/assert.c
61
+ test/test.c
62
+ zlib/zlib.c
63
+ stream/pipeline.c
64
+ worker_threads/worker_threads.c
65
+ ```
66
+
67
+ - Core event loop: `runtime/xt_loop.c` (a `select(2)` reactor). The generated module's `main` calls `xt_run_event_loop()` after draining microtasks; it returns immediately when no fds or timers are registered, so pure-computation programs are unaffected.
68
+
69
+ - The `NodeModule` interface:
70
+ - `name`: the module name (e.g. `fs`)
71
+ - `runtimeSources()`: the module's C sources
72
+ - `builtins()`: global identifier → runtime symbol mapping (`fs` returns its exports here; `path` / `os` / `process` dispatch through namespaces, so they return an empty table)
73
+ - `namespace` / `exports()`: the module's importable namespace and named exports (`import { join } from "path"`, `import path from "path"`)
74
+ - `resolveFrom(importMetaUrl, relative)`: resolves a path relative to the current module's directory into an absolute path, used to locate C sources.
75
+
76
+ ---
77
+
78
+ ## 2. The `fs` module (implemented, synchronous API only)
79
+
80
+ Location: `src/extensions/node/fs/*.ts`, `runtime/ext_node/fs/*.c`
81
+
82
+ ### 2.1 Available functions (imported from `fs`)
83
+
84
+ | Imported function | Runtime symbol | Notes |
85
+ | --- | --- | --- |
86
+ | `readFileSync(path[, options])` | `xt_node_read_text_file` | synchronously read a file, returns a string; supports encoding options |
87
+ | `readTextFile(path)` | `xt_node_read_text_file` | alias of `readFileSync` (same symbol) |
88
+ | `writeFileSync(path, data[, options])` | `xt_node_write_file` | overwrite write; accepts a string or a `Buffer` |
89
+ | `appendFileSync(path, data[, options])` | `xt_node_append_file` | append write; accepts a string or a `Buffer` |
90
+ | `existsSync(path)` | `xt_node_exists` | whether it exists, returns a boolean |
91
+ | `readdirSync(path[, options])` | `xt_node_read_dir` | directory entry names; `{ withFileTypes: true }` returns `Dirent`s, `{ recursive: true }` recurses |
92
+ | `mkdirSync(path[, options])` | `xt_node_mkdir` | create a directory; `{ recursive: true }` creates recursively, `{ mode }` is honoured |
93
+ | `rmSync(path[, options])` | `xt_node_rm` | delete a file/directory; `{ recursive: true }` deletes recursively |
94
+ | `rmdirSync(path[, options])` | `xt_node_rmdir` | delete an empty directory |
95
+ | `unlinkSync(path)` | `xt_node_unlink` | delete a file |
96
+ | `renameSync(oldPath, newPath)` | `xt_node_rename` | rename / move |
97
+ | `copyFileSync(src, dest[, flags])` | `xt_node_copy_file` | copy a file; honours `COPYFILE_EXCL` |
98
+ | `cpSync(src, dest[, options])` | `xt_node_cp` | recursive copy; `recursive`, `force`, `errorOnExist`, `dereference`, `preserveTimestamps` |
99
+ | `realpathSync(path)` | `xt_node_realpath` | resolve to an absolute path |
100
+ | `statSync(path)` | `xt_node_stat` | file metadata object (follows symlinks) |
101
+ | `lstatSync(path)` | `xt_node_lstat` | file metadata object (does not follow symlinks) |
102
+ | `statfsSync(path)` | `xt_node_statfs` | filesystem statistics (`bsize`, `blocks`, `bfree`, …) |
103
+ | `accessSync(path[, mode])` | `xt_node_access` | check accessibility |
104
+ | `chmodSync(path, mode)` | `xt_node_chmod` | change permissions |
105
+ | `lchmodSync(path, mode)` | `xt_node_lchmod` | change symlink permissions |
106
+ | `chownSync(path, uid, gid)` | `xt_node_chown` | change ownership |
107
+ | `lchownSync(path, uid, gid)` | `xt_node_lchown` | change symlink ownership |
108
+ | `truncateSync(path[, len])` | `xt_node_truncate` | truncate a file |
109
+ | `utimesSync(path, atime, mtime)` | `xt_node_utimes` | set access/modification time (number of seconds or a `Date`) |
110
+ | `lutimesSync(path, atime, mtime)` | `xt_node_lutimes` | set symlink times |
111
+ | `mkdtempSync(prefix)` | `xt_node_mkdtemp` | create a unique temporary directory |
112
+ | `linkSync(existing, newPath)` | `xt_node_link` | hard link |
113
+ | `symlinkSync(target, path[, type])` | `xt_node_symlink` | symbolic link |
114
+ | `readlinkSync(path)` | `xt_node_readlink` | read a symbolic link target |
115
+ | `opendirSync(path[, options])` | `xt_node_opendir` | returns a `Dir` (`readSync` / `closeSync` / `read` / `close`) |
116
+ | `globSync(pattern[, options])` | `xt_node_glob` | glob matching (`*`, `?`, `[...]`, `**`), `{ cwd, withFileTypes }` |
117
+ | `openSync(path[, flags[, mode]])` | `xt_node_open` | open a file descriptor |
118
+ | `closeSync(fd)` | `xt_node_close` | close a descriptor |
119
+ | `readSync(fd, buffer, offset, length, position)` | `xt_node_read` | read into a `Buffer` |
120
+ | `writeSync(fd, data[, offset[, length[, position]]])` | `xt_node_write` | write a string / `Buffer` |
121
+ | `readvSync(fd, buffers[, position])` | `xt_node_readv` | scatter read |
122
+ | `writevSync(fd, buffers[, position])` | `xt_node_writev` | gather write |
123
+ | `fstatSync(fd)` | `xt_node_fstat` | `stat` for a descriptor |
124
+ | `fsyncSync(fd)` / `fdatasyncSync(fd)` | `xt_node_fsync` / `xt_node_fdatasync` | flush a descriptor |
125
+ | `ftruncateSync(fd[, len])` | `xt_node_ftruncate` | truncate a descriptor |
126
+ | `fchmodSync(fd, mode)` | `xt_node_fchmod` | `chmod` for a descriptor |
127
+ | `fchownSync(fd, uid, gid)` | `xt_node_fchown` | `chown` for a descriptor |
128
+ | `futimesSync(fd, atime, mtime)` | `xt_node_futimes` | `utimes` for a descriptor |
129
+ | `watch(filename[, options][, listener])` | `xt_node_watch` | returns an emitter-shaped watcher (never fires; see §2.6) |
130
+ | `watchFile(filename[, options], listener)` | `xt_node_watch_file` | polling-shaped `StatWatcher` (never fires) |
131
+ | `unwatchFile(filename[, listener])` | `xt_node_unwatch_file` | stop watching |
132
+ | `constants` | `xt_fs_constants` | `F_OK` / `R_OK` / `W_OK` / `X_OK`, `COPYFILE_*`, `O_*`, `S_IF*` (host values) |
133
+ | `promises` | `xt_fs_promises` | the `fs/promises` facade (see §11) |
134
+
135
+ ### 2.2 Encoding support
136
+
137
+ The `options` of `readFileSync` / `writeFileSync` / `appendFileSync` may be an
138
+ encoding string or `{ encoding: "..." }`:
139
+
140
+ | Encoding | Read | Write |
141
+ | --- | --- | --- |
142
+ | default / `utf8` / `utf-8` / `ascii` / `latin1` / `binary` | raw UTF-8 text | write as text bytes |
143
+ | `hex` | lowercase hex string | parse hex then write |
144
+ | `base64` | Base64 string | parse Base64 then write |
145
+ | `base64url` | Base64url string | parse Base64url then write |
146
+ | `utf16le` / `ucs2` | raw bytes read as text (no UTF-16 decoding) | write as UTF-8 text |
147
+
148
+ > `readFileSync` still returns a **string** by default rather than a `Buffer`,
149
+ > even though the `Buffer` class exists, so that `console.log(readFileSync(p))`
150
+ > keeps printing text.
151
+
152
+ ### 2.3 `statSync` return structure
153
+
154
+ Returns a plain object with numeric properties: `size`, `mode`, `uid`, `gid`, `dev`, `ino`, `nlink`, `rdev`, `blksize`, `blocks`, `atimeMs`, `mtimeMs`, `ctimeMs`, `birthtimeMs`.
155
+ Methods (native closures, callable): `isFile()`, `isDirectory()`, `isSymbolicLink()`, `isFIFO()`, `isSocket()`, `isBlockDevice()`, `isCharacterDevice()`.
156
+
157
+ ### 2.4 How to call
158
+
159
+ `fs` exports are reached through an `import` (or the `node:fs` alias), not as bare
160
+ globals:
161
+
162
+ ```ts
163
+ import { readFileSync, writeFileSync, existsSync } from "fs";
164
+
165
+ const text = readFileSync("examples/data.txt");
166
+ writeFileSync("/tmp/out.txt", text);
167
+ console.log(existsSync("/tmp/out.txt"));
168
+ ```
169
+
170
+ ### 2.5 Error handling
171
+
172
+ On failure the functions **throw** a Node-shaped `Error` object carrying
173
+ `name` (`Error`), `message`, `code` (e.g. `ENOENT`), `errno` (the numeric
174
+ `errno`), `syscall` and `path`. `existsSync` still returns a boolean and never
175
+ throws.
176
+
177
+ ```ts
178
+ import { readFileSync } from "fs";
179
+ try {
180
+ readFileSync("/does/not/exist");
181
+ } catch (error) {
182
+ console.log((error as any).code); // ENOENT
183
+ }
184
+ ```
185
+
186
+ ### 2.6 Deviations from Node
187
+
188
+ - **No asynchronous I/O scheduler** (the event loop is a `select(2)` reactor
189
+ with timers and sockets but no callback-style `fs` backend), so the
190
+ callback-style `fs` functions (`readFile`, `writeFile`, `open`, …) are *not*
191
+ provided; use `fs/promises` or the `*Sync` forms.
192
+ - `watch` / `watchFile` / `unwatchFile` return API-shaped emitter objects whose
193
+ `.close()` / `.on()` methods exist but which **never emit** events.
194
+ - `Dir.read(cb)` / `Dir.close(cb)` invoke the callback **synchronously**.
195
+ - `readFileSync` returns a string by default instead of a `Buffer`.
196
+ - `utf16le` / `ucs2` are treated as raw bytes on read (no UTF-16 decoding).
197
+ - `mkdtempSync` appends 6 random characters to the prefix regardless of whether
198
+ it ends in `XXXXXX`.
199
+ - `globSync` supports `*`, `?`, `[...]` and `**` but not the `exclude` callback
200
+ or `follow`; `**` does not descend through symlinks (matching Node's default).
201
+ - `cpSync` is implemented on top of the synchronous helpers; symlinks are copied
202
+ as symlinks unless `dereference: true` is set.
203
+ - **Windows**: `readlinkSync` raises `ENOSYS`; `chmodSync` / `lchmodSync` /
204
+ `chownSync` / `lchownSync` / `fchmodSync` / `fchownSync` are no-ops;
205
+ `statfsSync` returns zeroed fields.
206
+ - **macOS / Windows**: `lutimesSync` falls back to `utimesSync`.
207
+
208
+ ---
209
+
210
+ ## 3. The `path` module (implemented)
211
+
212
+ Location: `src/extensions/node/path/index.ts`, `runtime/ext_node/path/path.c`
213
+
214
+ Uses `path.<name>(...)` namespace calls, which the compiler lowers to
215
+ `xt_path_static(<name>, argc, argv)`. Results are produced with the POSIX `/`
216
+ separator on every platform (Windows accepts `/`), while inputs may use native
217
+ Windows separators: on Windows both `/` and `\` are recognised and drive
218
+ prefixes (`C:`) are preserved, so the self-hosted compiler resolves
219
+ drive-letter paths correctly.
220
+ Import the module as a namespace (`import path from "path"` / `import * as path
221
+ from "path"`) or pull in individual methods (`import { join } from "path"`).
222
+
223
+ | Method | Notes |
224
+ | --- | --- |
225
+ | `path.join(...parts)` | join and normalize |
226
+ | `path.resolve(...parts)` | resolve to an absolute path |
227
+ | `path.normalize(path)` | normalize |
228
+ | `path.dirname(path)` | directory name |
229
+ | `path.basename(path[, ext])` | file name, optionally without extension |
230
+ | `path.extname(path)` | extension |
231
+ | `path.isAbsolute(path)` | whether it is an absolute path |
232
+ | `path.relative(from, to)` | relative path |
233
+
234
+ ```ts
235
+ import path from "path";
236
+ import { basename } from "path";
237
+
238
+ console.log(path.join("a", "b", "..", "c")); // a/c
239
+ console.log(basename("/x/y/z.txt")); // z.txt
240
+ ```
241
+
242
+ ---
243
+
244
+ ## 4. The `os` module (implemented)
245
+
246
+ Location: `src/extensions/node/os/index.ts`, `runtime/ext_node/os/os.c`
247
+
248
+ Uses `os.<name>(...)` namespace calls, lowered to `xt_os_static(<name>, argc, argv)`.
249
+ Import the module as a namespace (`import os from "os"`) or pull in individual
250
+ functions (`import { platform } from "os"`).
251
+
252
+ | Method | Notes |
253
+ | --- | --- |
254
+ | `os.platform()` | `darwin` / `linux` / `win32` / ... |
255
+ | `os.arch()` | `x64` / `arm64` / `ia32` / `arm` |
256
+ | `os.type()` | `Darwin` / `Linux` / `Windows_NT` / ... |
257
+ | `os.release()` | kernel version |
258
+ | `os.endianness()` | `LE` / `BE` |
259
+ | `os.homedir()` | user home directory |
260
+ | `os.tmpdir()` | temporary directory |
261
+ | `os.hostname()` | hostname |
262
+ | `os.totalmem()` / `os.freemem()` | total / free memory (bytes) |
263
+ | `os.cpus()` | array of CPU entries (`model` / `speed` placeholders) |
264
+
265
+ ---
266
+
267
+ ## 5. The `process` object (implemented)
268
+
269
+ Location: `src/extensions/node/process/index.ts`, `runtime/ext_node/process/process.c`
270
+
271
+ Method calls lower to `xt_process_call(<name>, argc, argv)`, property access to `xt_process_get(<name>)`.
272
+ Import the object (`import process from "process"`) to reach these.
273
+
274
+ | Method / property | Notes |
275
+ | --- | --- |
276
+ | `process.cwd()` | current working directory |
277
+ | `process.exit([code])` | exit the process |
278
+ | `process.uptime()` | process uptime (seconds) |
279
+ | `process.hrtime()` | `[seconds, nanoseconds]` array |
280
+ | `process.getuid()` | user ID (returns 0 on Windows) |
281
+ | `process.platform` / `process.arch` | platform / architecture |
282
+ | `process.pid` / `process.ppid` | process ID / parent process ID |
283
+ | `process.argv` | argument array (`argv[0]` is the executable) |
284
+ | `process.env` | environment variable object |
285
+ | `process.version` / `process.title` | placeholder strings |
286
+
287
+ > `argv` is captured by the generated `main` via `xt_set_program_args` and provided to the runtime.
288
+
289
+ ---
290
+
291
+ ## 6. The `buffer` module (implemented)
292
+
293
+ Location: `src/extensions/node/buffer/index.ts`, `runtime/ext_node/buffer/buffer.c`
294
+
295
+ xbintsc has no native binary value type, so `Buffer` is represented as a
296
+ **plain object**: each byte is a numeric property `"0".."n-1"`, plus a `length`
297
+ property, sharing the `xt_buffer_proto()` prototype that provides instance
298
+ methods. `xt_node_is_buffer` / `xt_node_buffer_bytes` let other modules access
299
+ bytes across modules.
300
+
301
+ | Static method | Notes |
302
+ | --- | --- |
303
+ | `Buffer.from(value[, encoding])` | construct from a string (hex / base64 / utf8), array or Buffer |
304
+ | `Buffer.alloc(size[, fill])` | allocate and fill |
305
+ | `Buffer.allocUnsafe(size)` | allocate |
306
+ | `Buffer.isBuffer(value)` | test |
307
+ | `Buffer.byteLength(value[, encoding])` | byte length |
308
+ | `Buffer.concat(list[, totalLength])` | concatenate |
309
+ | `Buffer.compare(a, b)` | compare |
310
+
311
+ Instance methods: `toString([encoding])`, `toJSON()`, `slice(start, end)`, `subarray(...)`, `equals(other)`, `compare(other)`, `copy(target[, targetStart, sourceStart, sourceEnd])`, `write(string[, offset[, length[, encoding]]])`, `fill(value)`, `reverse()`, `indexOf(value)`, `lastIndexOf(value)`, `includes(value)`, `keys()`, `values()`, plus `readUInt8/UInt16LE/UInt16BE/UInt32LE/UInt32BE`, `writeUInt8/UInt16LE/UInt16BE/UInt32LE/UInt32BE`.
312
+
313
+ ```ts
314
+ const buf = Buffer.from("hello");
315
+ console.log(buf.toString(), buf.length); // hello 5
316
+ console.log(Buffer.alloc(4, 65).toString()); // AAAA
317
+ ```
318
+
319
+ ---
320
+
321
+ ## 7. The `stream` module (implemented)
322
+
323
+ Location: `src/extensions/node/stream/index.ts`, `runtime/ext_node/stream/stream.c`
324
+
325
+ `Readable` / `Writable` / `Duplex` / `Transform` / `PassThrough` are used as
326
+ **global constructors** (`new Readable()` etc.); statics such as
327
+ `stream.Readable.from(...)` are resolved through the `stream` namespace. Streams
328
+ are EventEmitters with a **synchronous event model**: `on('data')` flushes the
329
+ `push` buffer, and `write` delivers immediately.
330
+
331
+ | Method | Notes |
332
+ | --- | --- |
333
+ | `push(chunk)` / `read([n])` | Readable side |
334
+ | `write(chunk)` / `end([chunk])` | Writable side |
335
+ | `pipe(destination)` | forward data |
336
+ | `on('data' / 'end' / 'finish')` | events |
337
+ | `pause()` / `resume()` / `setEncoding(enc)` / `destroy()` | flow control |
338
+
339
+ ---
340
+
341
+ ## 8. The `net` module (implemented)
342
+
343
+ Location: `src/extensions/node/net/index.ts`, `runtime/ext_node/net/net.c`
344
+
345
+ TCP server and client, built on the core event loop.
346
+
347
+ | API | Notes |
348
+ | --- | --- |
349
+ | `net.createServer([connectionListener])` | create a TCP server (equivalent to the `Server` constructor) |
350
+ | `net.connect(...)` / `net.createConnection(...)` | connect (blocking connect, then registers with the event loop) |
351
+ | `net.isIP(s)` / `net.isIPv4(s)` / `net.isIPv6(s)` | address test |
352
+
353
+ `Server`: `listen(port[, host][, cb])`, `close([cb])`, `address()`, `getConnections(cb)`, events `listening` / `connection` / `close`.
354
+
355
+ `Socket`: `write(data[, cb])`, `end([data])`, `destroy()`, `address()`, `setEncoding(enc)`, `pause()` / `resume()`, events `data` / `end` / `close` / `connect` / `error`.
356
+
357
+ ---
358
+
359
+ ## 9. The `dgram` module (implemented)
360
+
361
+ Location: `src/extensions/node/dgram/index.ts`, `runtime/ext_node/dgram/dgram.c`
362
+
363
+ UDP sockets. `dgram.createSocket(type | options[, cb])` returns an EventEmitter.
364
+
365
+ | Method | Notes |
366
+ | --- | --- |
367
+ | `bind([port][, address][, cb])` | bind (`send` auto-binds if unbound) |
368
+ | `send(msg[, offset, length,] port[, address][, cb])` | send a datagram |
369
+ | `close([cb])` / `address()` | close / query address |
370
+ | `setBroadcast(b)` / `setTTL(n)` / `setMulticastTTL(n)` | socket options |
371
+ | `on('message', (msg, rinfo) => ...)` | receive a datagram; `rinfo` has `address` / `port` / `family` / `size` |
372
+
373
+ ---
374
+
375
+ ## 10. The `http` module (implemented)
376
+
377
+ Location: `src/extensions/node/http/index.ts`, `runtime/ext_node/http/http.c`
378
+
379
+ The server wraps a `net` server: each connection accumulates bytes until a
380
+ complete request (request line + headers + `Content-Length` body) is available,
381
+ then invokes the `request` listener with `req`/`res`. The client wraps a `net`
382
+ socket, writes an HTTP/1.1 request and parses the response after the connection
383
+ closes.
384
+
385
+ | API | Notes |
386
+ | --- | --- |
387
+ | `http.createServer([requestListener])` | create an HTTP server |
388
+ | `http.request(options[, cb])` | create a `ClientRequest` (`write` / `end` / `setHeader`) |
389
+ | `http.get(url[, cb])` | issue a GET |
390
+
391
+ `IncomingMessage` (`req` / response): `method`, `url`, `httpVersion`, `headers`, `statusCode`, `data` / `end` events, `setEncoding`.
392
+
393
+ `ServerResponse` (`res`): `writeHead(status[, message][, headers])`, `setHeader` / `getHeader` / `removeHeader` / `getHeaders`, `write(chunk)`, `end([chunk])`, events `finish` / `close`. Responses always carry `Connection: close` (no keep-alive).
394
+
395
+ ---
396
+
397
+ ## 11. The `fs/promises` module (implemented)
398
+
399
+ Location: `src/extensions/node/fs-promises/index.ts`, `runtime/ext_node/fs/promises.c`
400
+
401
+ There is no asynchronous I/O scheduler, so each function wraps the corresponding
402
+ synchronous `fs` implementation in an **already-settled Promise**. Failures
403
+ **reject** with the same Node-shaped `Error` (with `code` / `errno` / `syscall` /
404
+ `path`) that the synchronous form throws. `fs.promises` is also reachable from
405
+ the `fs` module (`import { promises as fsp } from "fs"`), and both namespaces
406
+ expose a `constants` object.
407
+
408
+ Promise exports: `readFile`, `writeFile`, `appendFile`, `mkdir`, `readdir`,
409
+ `rm`, `unlink`, `rmdir`, `rename`, `copyFile`, `cp`, `realpath`, `stat`,
410
+ `lstat`, `statfs`, `access`, `open`, `chmod`, `lchmod`, `chown`, `lchown`,
411
+ `truncate`, `utimes`, `lutimes`, `link`, `symlink`, `readlink`, `mkdtemp`,
412
+ `opendir`, `glob`, `watch`.
413
+
414
+ `open(...)` resolves to a **`FileHandle`** with:
415
+ `read`, `write`, `readFile`, `writeFile`, `appendFile`, `close`, `stat`,
416
+ `truncate`, `chmod`, `chown`, `utimes`, `sync`, `datasync`.
417
+
418
+ ```ts
419
+ import { readFile, writeFile, open } from "fs/promises";
420
+
421
+ async function main(): Promise<void> {
422
+ await writeFile("/tmp/a.txt", "hi");
423
+ console.log(await readFile("/tmp/a.txt"));
424
+ const handle = await open("/tmp/a.txt", "r");
425
+ console.log(await handle.readFile("utf8"));
426
+ await handle.close();
427
+ }
428
+ main();
429
+ ```
430
+
431
+ ### 11.1 Deviations from Node
432
+
433
+ - Because I/O is synchronous, the Promise settles before the returned value is
434
+ awaited (the event loop does not yield).
435
+ - `FileHandle.appendFile` behaves like `writeFile` (it writes at the current
436
+ file position rather than appending).
437
+ - `FileHandle.readFile()` reads from the current file-descriptor offset.
438
+ - `Dir.read` / `Dir.close` (both the sync and promise/callback forms) complete
439
+ immediately.
440
+ - `watch` resolves to the same never-emitting watcher object as `fs.watch`.
441
+
442
+ ---
443
+
444
+ ## 12. The `child_process` module (implemented)
445
+
446
+ Location: `src/extensions/node/child_process/index.ts`, `runtime/ext_node/child_process/child_process.c`
447
+
448
+ `spawnSync(command, args[, options])` runs a program to completion and returns
449
+ `{ status, stdout, stderr }`. `options.cwd` sets the working directory and
450
+ `options.stdio: "inherit"` hands the child the parent's stdout/stderr (used by
451
+ `xbintsc run`, so a compiled program's output streams live); otherwise
452
+ stdout/stderr are captured as UTF-8 strings.
453
+
454
+ | Option | Notes |
455
+ | --- | --- |
456
+ | `cwd` | working directory for the child |
457
+ | `stdio: "inherit"` | share the parent's stdout/stderr instead of capturing |
458
+ | `encoding` | accepted and ignored (output is always decoded as UTF-8) |
459
+
460
+ ```ts
461
+ import { spawnSync } from "child_process";
462
+
463
+ const result = spawnSync("clang", ["--version"], { encoding: "utf8" });
464
+ console.log(result.status, result.stdout.split("\n")[0]);
465
+ ```
466
+
467
+ ---
468
+
469
+ ## 13. The `events` module (implemented)
470
+
471
+ Location: `src/extensions/node/events/index.ts`, `runtime/ext_node/events/events.c`
472
+
473
+ Provides a standalone `EventEmitter`, available both as a **global constructor**
474
+ (`new EventEmitter()`) and as a named export
475
+ (`import { EventEmitter } from "events"`). Instances share the runtime emitter
476
+ used by `stream` / `net` / `http` (listeners live in an internal `__xt_events`
477
+ property), with the fuller `events` surface layered on top:
478
+
479
+ | Method | Notes |
480
+ | --- | --- |
481
+ | `on(name, fn)` / `addListener(name, fn)` | append a listener |
482
+ | `once(name, fn)` | fire at most once, then remove itself |
483
+ | `prependListener(name, fn)` / `prependOnceListener(name, fn)` | insert at the front |
484
+ | `off(name, fn)` / `removeListener(name, fn)` | remove a listener |
485
+ | `removeAllListeners([name])` | clear one event (or all events) |
486
+ | `emit(name[, ...args])` | invoke listeners |
487
+ | `listeners(name)` / `rawListeners(name)` | listener array |
488
+ | `listenerCount(name)` | number of listeners |
489
+ | `eventNames()` | names that currently have listeners |
490
+ | `setMaxListeners(n)` / `getMaxListeners()` | bookkeeping (default 10) |
491
+
492
+ Statics reachable through the namespace (`import ee from "events"`):
493
+ `listenerCount`, `getEventListeners`, `getMaxListeners`, `setMaxListeners`,
494
+ `once`, `addAbortListener`.
495
+
496
+ ```ts
497
+ import { EventEmitter } from "events";
498
+
499
+ const em = new EventEmitter();
500
+ em.once("ready", () => console.log("ready"));
501
+ em.emit("ready"); // ready
502
+ em.emit("ready"); // nothing: the listener already ran
503
+ ```
504
+
505
+ ---
506
+
507
+ ## 14. The `util` module (implemented)
508
+
509
+ Location: `src/extensions/node/util/index.ts`, `runtime/ext_node/util/util.c`
510
+
511
+ Both named imports (`import { format } from "util"`) and namespace calls
512
+ (`import util from "util"` / `import * as util from "util"`) are supported.
513
+
514
+ | Function | Notes |
515
+ | --- | --- |
516
+ | `format(fmt, ...args)` | `%s` `%d` `%i` `%f` `%j` `%o` `%O` `%c` `%%` placeholders |
517
+ | `formatWithOptions(opts, fmt, ...args)` | options accepted and ignored |
518
+ | `inspect(value)` | recursive printer (depth-limited, strings quoted) |
519
+ | `isDeepStrictEqual(a, b)` | structural comparison (`NaN` equals `NaN`) |
520
+ | `inherits(ctor, superCtor)` | prototype wiring |
521
+ | `deprecate(fn, msg)` | returns `fn` unchanged (there is no warning channel) |
522
+ | `promisify(fn)` | wraps a trailing-callback function into a `Promise` |
523
+ | `isString` `isNumber` `isBoolean` `isUndefined` `isNull` `isFunction` `isArray` `isObject` `isBuffer` `isDate` `isRegExp` `isPromise` `isError` | type predicates |
524
+
525
+ ```ts
526
+ import { format, promisify } from "util";
527
+
528
+ console.log(format("%s=%d", "n", 3)); // n=3
529
+ ```
530
+
531
+ ---
532
+
533
+ ## 15. The `querystring` module (implemented)
534
+
535
+ Location: `src/extensions/node/querystring/index.ts`, `runtime/ext_node/querystring/querystring.c`
536
+
537
+ | Function | Notes |
538
+ | --- | --- |
539
+ | `parse(str[, sep[, eq]])` / `decode` | parse into an object; repeated keys become arrays |
540
+ | `stringify(obj[, sep[, eq]])` / `encode` | serialize; spaces become `+`, arrays repeat the key |
541
+ | `escape(str)` / `unescape(str)` | percent-encode / decode (`+` decodes to a space) |
542
+
543
+ Defaults: `sep = "&"`, `eq = "="`.
544
+
545
+ ```ts
546
+ import { parse, stringify } from "querystring";
547
+
548
+ const q = parse("a=1&b=2&b=3"); // { a: "1", b: ["2", "3"] }
549
+ console.log(stringify({ x: "a b" })); // x=a+b
550
+ ```
551
+
552
+ ---
553
+
554
+ ## 16. Implemented Node capabilities quick reference
555
+
556
+ | Category | Contents |
557
+ | --- | --- |
558
+ | Extension registration | `nodeExtension` (`--ext node`), `NodeModule` interface, `resolveFrom` utility |
559
+ | fs read | `readFileSync`, `readTextFile` (`xt_node_read_text_file`), supports hex / base64 / base64url |
560
+ | fs write | `writeFileSync`, `appendFileSync`, supports hex / base64 / base64url; string or `Buffer` |
561
+ | fs directories | `readdirSync` (`withFileTypes` / `recursive`), `mkdirSync`, `rmSync`, `unlinkSync`, `rmdirSync`, `opendirSync` (`Dir`), `globSync`, `mkdtempSync` |
562
+ | fs other | `existsSync`, `renameSync`, `copyFileSync`, `cpSync`, `realpathSync`, `statSync`, `lstatSync`, `statfsSync`, `accessSync`, `chmodSync`, `chownSync`, `lchmodSync`, `lchownSync`, `truncateSync`, `utimesSync`, `lutimesSync`, `linkSync`, `symlinkSync`, `readlinkSync`, `watch`, `watchFile`, `unwatchFile` |
563
+ | fs descriptors | `openSync`, `closeSync`, `readSync`, `writeSync`, `readvSync`, `writevSync`, `fstatSync`, `fsyncSync`, `fdatasyncSync`, `ftruncateSync`, `fchmodSync`, `fchownSync`, `futimesSync` |
564
+ | fs constants | `constants` (`F_OK`, `R_OK`, `W_OK`, `X_OK`, `COPYFILE_*`, `O_*`, `S_IF*`) |
565
+ | path | `join` `resolve` `normalize` `dirname` `basename` `extname` `isAbsolute` `relative` |
566
+ | os | `platform` `arch` `type` `release` `endianness` `homedir` `tmpdir` `hostname` `totalmem` `freemem` `cpus` |
567
+ | process | `cwd` `exit` `uptime` `hrtime` `getuid`; `platform` `arch` `pid` `ppid` `argv` `env` `version` `title` |
568
+ | buffer | `Buffer.from/alloc/allocUnsafe/isBuffer/byteLength/concat/compare`; instances `toString/toJSON/slice/.../readUInt32BE/writeUInt32BE` |
569
+ | stream | `Readable` `Writable` `Duplex` `Transform` `PassThrough`; `push/read/write/end/pipe/on` |
570
+ | net | `createServer` `connect` `createConnection` `isIP/isIPv4/isIPv6`; `Server` `Socket` |
571
+ | dgram | `createSocket`; `bind/send/close/address/setBroadcast/setTTL` |
572
+ | http | `createServer` `request` `get`; `ClientRequest`, `IncomingMessage`, `ServerResponse` |
573
+ | child_process | `spawnSync(command, args[, {cwd, stdio}])` returning `status` / `stdout` / `stderr` |
574
+ | assert | `ok/equal/notEqual/strictEqual/notStrictEqual/deepStrictEqual/notDeepStrictEqual/throws/doesNotThrow/ifError/match/doesNotMatch/fail` (`import assert from "node:assert"`) |
575
+ | test | `test(name, fn)` / `it` / `describe` / `skip` / `todo` (`import test from "node:test"`), TAP output, non-zero exit on failure |
576
+ | zlib | `createGzip()` (consumed by `stream/promises` pipeline) |
577
+ | stream/promises | `pipeline(...)` (synchronous drain, returns a resolved Promise) |
578
+ | worker_threads | `Worker`, `isMainThread`, `workerData`, `parentPort` (re-executes the binary as a child process) |
579
+ | events | `EventEmitter` (global + named); `on/once/off/emit/listeners/listenerCount/eventNames`; statics `listenerCount/getEventListeners/getMaxListeners/setMaxListeners/once/addAbortListener` |
580
+ | util | `format` `formatWithOptions` `inspect` `isDeepStrictEqual` `inherits` `deprecate` `promisify`; `isString/isNumber/isBoolean/isUndefined/isNull/isFunction/isArray/isObject/isBuffer/isDate/isRegExp/isPromise/isError` |
581
+ | querystring | `parse`/`decode` `stringify`/`encode` `escape` `unescape` |
582
+ | crypto | `createHash(algorithm)` with `update`/`digest` and the streaming API (`setEncoding`/`write`/`end`/`read`); SHA-1 and SHA-256 |
583
+ | globals | `btoa` / `atob` base64 helpers; timers `setTimeout` / `clearTimeout` / `setInterval` / `clearInterval` (numeric ids, no `Timeout` object) |
584
+ | url | `pathToFileURL` `fileURLToPath` |
585
+ | fs/promises | `readFile` `writeFile` `appendFile` `mkdir` `readdir` `rm` `unlink` `rmdir` `rename` `copyFile` `cp` `realpath` `stat` `lstat` `statfs` `access` `open` `chmod` `lchmod` `chown` `lchown` `truncate` `utimes` `lutimes` `link` `symlink` `readlink` `mkdtemp` `opendir` `glob` `watch` `constants`; `FileHandle` |
586
+ | Event loop | `xt_loop` (`select` reactor), `xt_run_event_loop()`, `xt_loop_add/update/remove`, timer queue (`xt_set_timeout` / `xt_set_interval` / `xt_clear_*`) |
587
+ | Calling convention | uniform `(argc, argv)` ABI, returns `xt_value` |
588
+ | Linking | after registration, compiles `runtime/ext_node/**` and links it with the runtime |