xbintsc 0.5.20 → 0.5.21
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/AGENTS.md +5 -3
- package/dist/src/driver/compiler.js +1 -1
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/runtime-objects.d.ts +1 -1
- package/dist/src/driver/runtime-objects.js +1 -0
- package/dist/src/driver/runtime-objects.js.map +1 -1
- package/dist/src/driver/version.d.ts +1 -1
- package/dist/src/driver/version.js +1 -1
- package/dist/src/extensions/node/fs/index.d.ts +4 -3
- package/dist/src/extensions/node/fs/index.js +12 -3
- package/dist/src/extensions/node/fs/index.js.map +1 -1
- package/dist/src/extensions/node/fs-promises/index.d.ts +5 -5
- package/dist/src/extensions/node/fs-promises/index.js +15 -6
- package/dist/src/extensions/node/fs-promises/index.js.map +1 -1
- package/dist/tests/e2e/async-await.test.js +1 -1
- package/dist/tests/e2e/async-fs.test.d.ts +9 -0
- package/dist/tests/e2e/async-fs.test.js +119 -0
- package/dist/tests/e2e/async-fs.test.js.map +1 -0
- package/dist/tests/e2e/fetch.test.js +24 -0
- package/dist/tests/e2e/fetch.test.js.map +1 -1
- package/dist/tests/e2e/gui-inline-svg.test.d.ts +11 -0
- package/dist/tests/e2e/gui-inline-svg.test.js +160 -0
- package/dist/tests/e2e/gui-inline-svg.test.js.map +1 -0
- package/doc/ai/contributing.md +2 -1
- package/doc/ai/extensions.md +4 -3
- package/doc/ai/language-support.md +2 -1
- package/doc/ai/zh-CN/contributing.md +1 -1
- package/doc/ai/zh-CN/extensions.md +4 -3
- package/doc/ai/zh-CN/language-support.md +2 -1
- package/doc/gui/api.md +8 -0
- package/doc/gui/known-issues.md +10 -9
- package/doc/gui/media.md +32 -3
- package/doc/gui.md +24 -2
- package/doc/implemented/async.md +16 -3
- package/doc/implemented/fetch.md +38 -6
- package/doc/implemented/node/fs-promises.md +19 -8
- package/doc/implemented/node.md +1 -1
- package/doc/implemented.md +1 -1
- package/doc/unimplemented/deviations.md +1 -1
- package/doc/unimplemented/node/async.md +6 -3
- package/doc/unimplemented/node/fs-promises.md +10 -6
- package/doc/unimplemented/node/fs.md +7 -8
- package/doc/unimplemented/node.md +2 -2
- package/doc/unimplemented/toolchain.md +1 -1
- package/doc/zh-CN/gui/api.md +7 -0
- package/doc/zh-CN/gui/known-issues.md +8 -7
- package/doc/zh-CN/gui/media.md +26 -2
- package/doc/zh-CN/gui.md +18 -1
- package/doc/zh-CN/implemented/async.md +13 -2
- package/doc/zh-CN/implemented/fetch.md +23 -4
- package/doc/zh-CN/implemented/node/fs-promises.md +6 -3
- package/doc/zh-CN/implemented/node.md +1 -1
- package/doc/zh-CN/implemented.md +1 -1
- package/doc/zh-CN/unimplemented/deviations.md +1 -1
- package/doc/zh-CN/unimplemented/node/async.md +6 -3
- package/doc/zh-CN/unimplemented/node/fs-promises.md +4 -4
- package/doc/zh-CN/unimplemented/node/fs.md +2 -2
- package/doc/zh-CN/unimplemented/node.md +2 -2
- package/doc/zh-CN/unimplemented/toolchain.md +1 -1
- package/package.json +1 -1
- package/runtime/ext_gui/inline_svg.cpp +219 -0
- package/runtime/ext_gui/inline_svg.h +41 -0
- package/runtime/ext_gui/layout.cpp +18 -0
- package/runtime/ext_gui/layout.h +7 -0
- package/runtime/ext_gui/layout_flow.cpp +4 -3
- package/runtime/ext_gui/paint.cpp +14 -0
- package/runtime/ext_gui/paint.h +5 -1
- package/runtime/ext_gui/renderer_image.cpp +53 -25
- package/runtime/ext_gui/style_ua.cpp +3 -0
- package/runtime/ext_gui/svg.cpp +122 -39
- package/runtime/ext_gui/svg.h +14 -3
- package/runtime/ext_gui/window.cpp +28 -0
- package/runtime/ext_node/fs/async_api.c +314 -0
- package/runtime/ext_node/fs/async_complete.c +99 -0
- package/runtime/ext_node/fs/async_fh.c +206 -0
- package/runtime/ext_node/fs/async_job.c +81 -0
- package/runtime/ext_node/fs/async_job.h +132 -0
- package/runtime/ext_node/fs/async_worker.c +534 -0
- package/runtime/ext_node/fs/async_worker_dir.c +439 -0
- package/runtime/ext_node/fs/async_worker_dir.h +33 -0
- package/runtime/ext_node/fs/async_worker_fd.c +74 -0
- package/runtime/ext_node/fs/dir.c +60 -15
- package/runtime/ext_node/fs/fs_common.h +9 -0
- package/runtime/ext_node/fs/fs_ops.c +18 -29
- package/runtime/ext_node/fs/parts/builtins.inc +34 -0
- package/runtime/ext_node/fs/parts/platform.inc +66 -0
- package/runtime/ext_node/fs/promises.c +44 -234
- package/runtime/rt_internal.h +2 -0
- package/runtime/xt_async_io.c +333 -0
- package/runtime/xt_async_io.h +47 -0
- package/runtime/xt_fetch/async.inc +295 -0
- package/runtime/xt_fetch/request.inc +6 -183
- package/runtime/xt_fetch/socket.inc +5 -4
- package/runtime/xt_fetch.c +6 -4
- package/runtime/xt_loop.c +44 -3
- package/src/driver/compiler.ts +1 -1
- package/src/driver/runtime-objects.ts +1 -0
- package/src/driver/version.ts +1 -1
- package/src/extensions/node/fs/index.ts +12 -3
- package/src/extensions/node/fs-promises/index.ts +15 -6
|
@@ -2,15 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
> Part of [Node extension: unimplemented](../node.md) · [简体中文](../../zh-CN/unimplemented/node/fs-promises.md)
|
|
4
4
|
|
|
5
|
-
`fs/promises`
|
|
6
|
-
|
|
7
|
-
[implemented: `fs/promises`](../../implemented/node/fs-promises.md))
|
|
5
|
+
`fs/promises` now offloads its blocking I/O to the async I/O pool (the
|
|
6
|
+
implemented surface is in
|
|
7
|
+
[implemented: `fs/promises`](../../implemented/node/fs-promises.md)); the
|
|
8
|
+
remaining differences are behavioural:
|
|
8
9
|
|
|
9
|
-
- I/O is synchronous: the promise is settled before it is awaited, so awaiting
|
|
10
|
-
it does not yield to the event loop.
|
|
11
10
|
- `FileHandle.appendFile` behaves like `writeFile` (it writes at the current
|
|
12
11
|
file position instead of appending).
|
|
13
12
|
- `FileHandle.readFile()` reads from the current file-descriptor offset.
|
|
14
|
-
- `Dir.read` / `Dir.close` (sync and promise forms) complete
|
|
13
|
+
- `Dir.read` / `Dir.close` (sync and promise forms) complete their callbacks
|
|
14
|
+
immediately; `Dir.readSync` / `closeSync` remain synchronous.
|
|
15
15
|
- `watch` resolves to the same never-emitting watcher as `fs.watch`; there is no
|
|
16
16
|
real file-watching backend.
|
|
17
|
+
- Reads and writes are whole-file/one-shot operations; there are no streaming
|
|
18
|
+
`FileHandle` variants and no `AbortSignal` cancellation.
|
|
19
|
+
- The pool has four workers; very many simultaneous operations queue behind
|
|
20
|
+
them (they still do not block the event loop).
|
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
> Part of [Node extension: unimplemented](../node.md) · [简体中文](../../zh-CN/unimplemented/node/fs.md)
|
|
4
4
|
|
|
5
|
-
`fs`
|
|
6
|
-
descriptors, metadata, links, `cp`, `glob`, `Dir`, `constants`) and
|
|
7
|
-
`fs/promises`
|
|
5
|
+
`fs` implements the **synchronous** API surface (files, directories,
|
|
6
|
+
descriptors, metadata, links, `cp`, `glob`, `Dir`, `constants`), and
|
|
7
|
+
`fs/promises` runs every file/descriptor operation on the asynchronous I/O pool
|
|
8
8
|
(see [implemented: `fs`](../../implemented/node/fs.md) and
|
|
9
|
-
[implemented: `fs/promises`](../../implemented/node/fs-promises.md)).
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
provide timers and sockets):
|
|
9
|
+
[implemented: `fs/promises`](../../implemented/node/fs-promises.md)). What is
|
|
10
|
+
still missing is mostly about APIs that need a different backend or callback
|
|
11
|
+
plumbing:
|
|
13
12
|
|
|
14
13
|
| Unimplemented API | Category |
|
|
15
14
|
| --- | --- |
|
|
@@ -24,7 +23,7 @@ provide timers and sockets):
|
|
|
24
23
|
- `readFileSync` supports encoding options (default/`utf8`/`ascii`/`latin1`/`binary`/ `hex`/`base64`/`base64url`), but **does not return a `Buffer`** by default: even though `Buffer` exists (simulated as a plain object), `readFileSync` still returns a string. Pass a `Buffer`-producing path or read raw bytes explicitly.
|
|
25
24
|
- `utf16le` / `ucs2` decoding is not implemented (the bytes are returned as text).
|
|
26
25
|
- `watch` / `watchFile` / `unwatchFile` return API-shaped emitter objects whose `.close()` / `.on()` methods exist but which **never fire** events.
|
|
27
|
-
- `Dir.read(cb)` / `Dir.close(cb)`
|
|
26
|
+
- `Dir.read(cb)` / `Dir.close(cb)` complete **synchronously** (the callback is invoked immediately); `FileHandle` methods do return real promises now.
|
|
28
27
|
- `mkdtempSync` always appends 6 random characters to the prefix (it does not require a trailing `XXXXXX`).
|
|
29
28
|
- `globSync` supports `*`, `?`, `[...]` and `**` but not the `exclude` callback or `follow`; `**` does not descend through symlinks (matching Node's default).
|
|
30
29
|
- `cpSync` symlink handling follows Node for the common cases but `verbatimSymlinks` is not supported.
|
|
@@ -10,10 +10,10 @@ is missing or differs from Node.
|
|
|
10
10
|
## Contents
|
|
11
11
|
|
|
12
12
|
- [`fs`](./node/fs.md) — callback-style async operations, real file watching, option callbacks
|
|
13
|
-
- [`fs/promises`](./node/fs-promises.md) —
|
|
13
|
+
- [`fs/promises`](./node/fs-promises.md) — `FileHandle` append/read offsets, immediate `Dir` callbacks, inert `watch`, no cancellation
|
|
14
14
|
- [Fully unimplemented modules](./node/modules.md) — `https`, `readline`, `tls`, `cluster`, `vm`, ...
|
|
15
15
|
- [Global objects and namespaces](./node/globals.md) — `global`, `__dirname`, `require` outside `node_modules`
|
|
16
|
-
- [Async and the event-loop model](./node/async.md) —
|
|
16
|
+
- [Async and the event-loop model](./node/async.md) — blocked file watching, blocking `net.connect`, no keep-alive, fixed-size offload pool
|
|
17
17
|
- [The Bun extension](./node/bun.md) — design example only
|
|
18
18
|
|
|
19
19
|
A module's implemented page links to its limitation page; when a limitation is
|
|
@@ -9,6 +9,6 @@
|
|
|
9
9
|
| Type checker | ✗ only diagnostic codes are defined; no checker |
|
|
10
10
|
| Full standard library | partial: Math / JSON / Date / Map / Set / RegExp / `Error` / `BigInt` / `Symbol` / `structuredClone` implemented; String.normalize missing |
|
|
11
11
|
| Multi-file module bundling | partial: relative-path `.ts` bundling, ESM `node_modules` packages, namespace imports and bare-specifier extension module imports implemented; CommonJS is handled only inside `node_modules`; circular dependencies / live bindings are not implemented |
|
|
12
|
-
| Real async runtime | ✓ `async`/`await` suspends on pending promises on the `select(2)` reactor: timers, TCP sockets and promise callbacks resume the coroutine. Still missing:
|
|
12
|
+
| Real async runtime | ✓ `async`/`await` suspends on pending promises on the `select(2)` reactor: timers, TCP sockets, offloaded file/HTTP work and promise callbacks resume the coroutine. Still missing: real OS-level file watching, non-blocking `net.connect`, TLS for `fetch`, and user-visible worker threads (`worker_threads` uses child processes) |
|
|
13
13
|
| Windows binary artifact verification | adapted at the build layer (`.exe` suffix, link flag branch), verified in CI |
|
|
14
14
|
| Precise ECMAScript number / string / comparison semantics | partial, see [Runtime deviations](./deviations.md) |
|
package/doc/zh-CN/gui/api.md
CHANGED
|
@@ -64,6 +64,7 @@ win.documentTree() // 序列化的 DOM(调试用)
|
|
|
64
64
|
win.layoutTree() // 序列化的布局盒(调试用)
|
|
65
65
|
win.paintCount() // 显示列表中图形的数量
|
|
66
66
|
win.paintList() // 序列化的显示列表(调试用)
|
|
67
|
+
win.inlineSvg(selector) // 序列化的内联 <svg>:{ markup, width, height, shapes }
|
|
67
68
|
win.measureText(text, fontSize?, family?) // 整形后的推进宽度(像素)
|
|
68
69
|
win.fontMetrics(fontSize?, family?) // { ascent, descent, lineHeight, ready }
|
|
69
70
|
win.hitTest(x, y) // 最深的元素描述符,或 ""
|
|
@@ -72,6 +73,12 @@ win.advance(ms) // 推进 CSS transition 时钟(测试
|
|
|
72
73
|
win.stats() // 引擎/运行时计数器(内存排查用)
|
|
73
74
|
```
|
|
74
75
|
|
|
76
|
+
`win.inlineSvg(selector)` 返回引擎为第一个匹配 `selector` 的 `<svg>` 元素构建的
|
|
77
|
+
独立 SVG 文档(`markup`),以及 NanoSVG 从它解析出的固有尺寸与图形数量;没有
|
|
78
|
+
匹配或元素不是 `<svg>` 时返回 `undefined`。它让序列化器的规范大小写
|
|
79
|
+
(`viewBox`、`linearGradient`、`gradientUnits` 等)无需 GPU 即可测试——HTML
|
|
80
|
+
解析器会把它们全部小写化。
|
|
81
|
+
|
|
75
82
|
`win.stats()` 返回 `{ heapBytes, heapAllocations, treeNodes, detachedRoots,`
|
|
76
83
|
`detachedNodes, handles, handleSlots, listeners }`:运行时存活堆、DOM 树规模、
|
|
77
84
|
分离节点池(detached pool)以及元素句柄表。稳定状态下它们都应保持常量——若
|
|
@@ -23,13 +23,14 @@
|
|
|
23
23
|
`tests/e2e/gui-example-browser.test.ts` 中。
|
|
24
24
|
- **`display: none -> flex` 的重排。** 通过类名切换让隐藏元素显示在 flex 容器上时,也曾观察
|
|
25
25
|
到同样的崩溃;`examples/gui/pelican-bike` 改用 `opacity` 显示游戏结束遮罩。
|
|
26
|
-
- **SVG
|
|
27
|
-
|
|
28
|
-
`
|
|
29
|
-
`<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
26
|
+
- **SVG 是 NanoSVG 的子集。** SVG *文件*(`<img src="logo.svg">`)与内联
|
|
27
|
+
`<svg>` 子树共用 vendored 的 NanoSVG 解析/光栅化器(`runtime/ext_gui/svg.cpp`、
|
|
28
|
+
`inline_svg.cpp`),它会渲染 `path`/`rect`/`circle`/`ellipse`/`line`/
|
|
29
|
+
`polyline`/`polygon`、组、`defs` 渐变以及基于 `class` 的 `<style>` 规则。
|
|
30
|
+
`<text>`、`<use>`、滤镜、遮罩与裁剪路径不会渲染,文档层叠的 CSS 也不会进入
|
|
31
|
+
图像内部(这里的 `fill`/`stroke` 是 SVG 表现属性,不是 CSS 属性)。需要这些
|
|
32
|
+
能力的矢量美术必须预先光栅化、用盒子绘制,或限制在受支持的语法内。参见
|
|
33
|
+
[媒体](./media.md#图像m6a)。
|
|
33
34
|
|
|
34
35
|
## 待决问题
|
|
35
36
|
|
package/doc/zh-CN/gui/media.md
CHANGED
|
@@ -12,7 +12,8 @@ PNG/JPEG/BMP/GIF/TGA 解码为 RGBA8,并带有解码缓存与仅头文件的
|
|
|
12
12
|
`runtime/ext_gui/svg.{h,cpp}` 在其上增加 SVG:它封装 vendored **NanoSVG**
|
|
13
13
|
库(解析 + 抗锯齿扫描线光栅化),按扩展名或内容识别 SVG,并产出与既有管线
|
|
14
14
|
相同的 RGBA8 `Image`。`stb_image` 无法解码 SVG,这正是
|
|
15
|
-
`<img src="logo.svg">`
|
|
15
|
+
`<img src="logo.svg">` 能工作的原因。内联 `<svg>` 子树会先被序列化成一个
|
|
16
|
+
独立文档(`inline_svg.{h,cpp}`),再交给同一个解析器。
|
|
16
17
|
|
|
17
18
|
- `<img>` 是一个替换元素(`display: inline-block`):设置了 CSS 尺寸时布局
|
|
18
19
|
采用该尺寸,否则采用固有像素尺寸;当只约束一个轴时保持宽高比。构建盒树时
|
|
@@ -23,11 +24,34 @@ PNG/JPEG/BMP/GIF/TGA 解码为 RGBA8,并带有解码缓存与仅头文件的
|
|
|
23
24
|
**位图**按固有分辨率解码并按路径缓存;**矢量图**(SVG)按设备像素下的绘制
|
|
24
25
|
尺寸(逻辑尺寸 × 窗口像素密度)光栅化并保持 viewBox 宽高比,再按该尺寸缓存,
|
|
25
26
|
因此缩放或 HiDPI 得到的是清晰渲染而非放大的位图。
|
|
27
|
+
- **内联** `<svg>` 元素与 `<img>` 一样是替换元素,但它的来源就是 DOM 子树
|
|
28
|
+
本身。`runtime/ext_gui/inline_svg.{h,cpp}` 把该子树序列化回独立 SVG 文档,
|
|
29
|
+
还原 HTML 解析器会小写掉的、NanoSVG 又按大小写精确匹配的拼写(`viewBox`、
|
|
30
|
+
`preserveAspectRatio`、`linearGradient`、`gradientUnits` 等)。布局先取
|
|
31
|
+
`width`/`height` 属性、其次 `viewBox`、最后 300x150 作为固有尺寸;绘制把
|
|
32
|
+
markup 挂在图像 op 上,渲染器按绘制设备像素尺寸,通过与 SVG 文件相同的
|
|
33
|
+
NanoSVG 缓存解析并光栅化。DOM 变更会在下一次布局时重新序列化(因此
|
|
34
|
+
`setAttribute` 与 `innerHTML` 都会重绘图像),markup 缓存有界
|
|
35
|
+
(最近最少使用),动画文档不会让它无限增长。
|
|
26
36
|
- 解析结果按路径缓存;解析与光栅化器状态在 `xt_svg_shutdown`
|
|
27
37
|
(`xt_image_shutdown`)中释放。
|
|
28
38
|
|
|
39
|
+
文档 CSS 只作用于 `<svg>` **盒子**——尺寸、外边距、背景、边框、`transform`、
|
|
40
|
+
opacity、`display`——与任何其他元素一样。盒子内部的艺术内容保持 SVG 语义:
|
|
41
|
+
表现属性与 SVG `<style>` 中基于 `class` 的规则由 NanoSVG 读取,而不是 HTML
|
|
42
|
+
层叠,所以这里的 `fill`/`stroke` 不是 CSS 属性。对布局、绘制、命中测试与事件
|
|
43
|
+
而言整个 `<svg>` 就是一个替换盒:其子元素没有 DOM 盒,因此点击的 `e.target`
|
|
44
|
+
是 `<svg>` 元素而不是某个 `<rect>`。渲染器按 markup 与尺寸缓存纹理,所以每帧
|
|
45
|
+
重写艺术内容的程序会为每个变体保留一张纹理;更好的做法是用 `transform`、
|
|
46
|
+
`opacity` 给盒子做动画,或在一小组文档之间切换。
|
|
47
|
+
|
|
29
48
|
图像仍需完成:CSS `background-image: url(...)`、`data:` URI、`object-fit`、
|
|
30
|
-
|
|
49
|
+
九宫格边框。
|
|
50
|
+
|
|
51
|
+
两种 SVG 都受限于 NanoSVG 的子集:`path`、`rect`、`circle`、`ellipse`、
|
|
52
|
+
`line`、`polyline`、`polygon`、组(`g`)、带线性/径向渐变的 `defs` 以及基于
|
|
53
|
+
`class` 的 `<style>` 规则会被光栅化;`<text>`、`<use>`、滤镜、遮罩与裁剪路径
|
|
54
|
+
不会渲染(见[已知问题](./known-issues.md))。
|
|
31
55
|
|
|
32
56
|
## 视频与音频(M13)
|
|
33
57
|
|
package/doc/zh-CN/gui.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> 语言 / Language:[English](../gui.md) | **简体中文**
|
|
4
4
|
|
|
5
|
-
状态:**
|
|
5
|
+
状态:**M16** —— 功能(M1–M15)已全部完成:HTML 解析、CSS 选择器匹配、层叠(cascade)、计算样式与布局(块级、行内、Flexbox 与 CSS 定位)均已就位,引擎还会**绘制**:它构建一个由矩形、图像与排版后的文本 run 组成的显示列表,并通过 SDL_GPU 渲染。输入事件会经过命中测试并投递给原生 TS 处理器,`:hover`/`:focus` 会被动态匹配,`<img>` 依据其固有尺寸确定大小并从纹理绘制——位图(PNG/JPEG/…)与 SVG 文件皆可,后者按绘制尺寸光栅化,因此矢量图保持清晰——CSS transition 会为绘制属性做动画。**M16** 让内联 `<svg>` 子树获得同样的处理:子树被序列化回 SVG 文档,并按绘制设备尺寸光栅化,因此图标不再需要单独的文件。**M8** 增加了交互式 DOM:具有稳定标识的元素句柄、变更操作(`appendChild`、`textContent`、`classList`、`style` 等)以及支持捕获/冒泡的元素级事件。**M9** 会提前编译 `<script>` 主体(内联与 `<script src>`)——参见 `gui-scripts.md`。**M10** 增加 `requestAnimationFrame` 以及若干 DOM 辅助方法。**M11** 增加 `position: relative`/`absolute`/`fixed` 及其偏移,`examples/gui/pelican-bike`(一个可玩的 2D 游戏)就构建在它之上。**M12** 明确了 DOM 节点生命周期(哪些变更释放、哪些保留),并让引擎内存有界:参见[节点生命周期](./gui/dom.md)与[内存与 GC](./gui/runtime.md)。**M13** 真正播放
|
|
6
6
|
`<video>`/`<audio>`——一个 vendored 的最小 FFmpeg 在主线程解码,视频帧走图像
|
|
7
7
|
纹理路径、音频进入 SDL 流,DOM 媒体 API 暴露 `play`/`pause`/`currentTime`/…
|
|
8
8
|
与媒体事件。**M14** 增加了 `<canvas>`,配一个自研的 2D 软件光栅器(抗锯齿
|
|
@@ -212,6 +212,16 @@ FFmpeg `7.1`(可用 `SDL3_TAG` / `FREETYPE_VERSION` / `HARFBUZZ_VERSION` /
|
|
|
212
212
|
[布局](./gui/layout.md#变换m15)与[动画](./gui/animation.md#css-transformm15);
|
|
213
213
|
e2e 见 `tests/e2e/gui-transform.test.ts` 与
|
|
214
214
|
`tests/e2e/gui-example-svg.test.ts`。
|
|
215
|
+
16. **M16 — 内联 `<svg>`** ✅
|
|
216
|
+
- `<svg>` 是替换元素(`layout.*`):固有尺寸先取 `width`/`height` 属性,
|
|
217
|
+
其次 `viewBox`,最后 300x150;常规盒树遍历不再进入其子元素。
|
|
218
|
+
- `inline_svg.{h,cpp}` 把子树序列化为独立 SVG 文档,并还原 HTML 解析器
|
|
219
|
+
小写掉的、区分大小写的名称(`viewBox`、`preserveAspectRatio`、
|
|
220
|
+
`linearGradient`、`gradientUnits` 等)。
|
|
221
|
+
- 绘制把 markup 挂在图像 op 上(`PaintImage::svg`),渲染器按绘制设备尺寸、
|
|
222
|
+
通过与 SVG 文件相同的 NanoSVG 缓存(`svg.{h,cpp}`)解析并光栅化;markup
|
|
223
|
+
缓存有界,DOM 变更会在下一次布局时重新序列化。e2e 见
|
|
224
|
+
`tests/e2e/gui-inline-svg.test.ts`。
|
|
215
225
|
|
|
216
226
|
## 进度日志
|
|
217
227
|
|
|
@@ -299,4 +309,11 @@ FFmpeg `7.1`(可用 `SDL3_TAG` / `FREETYPE_VERSION` / `HARFBUZZ_VERSION` /
|
|
|
299
309
|
`getBoundingClientRect` 返回变换后的包围盒。`examples/gui/pelican-svg` 用它
|
|
300
310
|
为自己的画做动画;e2e 见 `tests/e2e/gui-transform.test.ts` 与
|
|
301
311
|
`tests/e2e/gui-example-svg.test.ts`。
|
|
312
|
+
- **M16** ✅ 内联 `<svg>`。`buildBoxTree` 把 `<svg>` 元素当作替换盒(固有尺寸
|
|
313
|
+
依次取 `width`/`height`、`viewBox`、300x150)并停止下探,
|
|
314
|
+
`inline_svg.{h,cpp}` 以规范 SVG 大小写序列化子树,绘制把 markup 放进
|
|
315
|
+
`PaintImage::svg`,`renderer_image.cpp` 通过 NanoSVG 缓存(`svg.{h,cpp}`,
|
|
316
|
+
markup 采用有界 LRU)按绘制设备像素尺寸光栅化。`win.inlineSvg` 诊断钩子
|
|
317
|
+
暴露序列化文档,`tests/e2e/gui-inline-svg.test.ts` 固定了尺寸、命中测试、
|
|
318
|
+
渐变、CSS 盒样式与 DOM 变更。
|
|
302
319
|
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
> 属于[已实现语法与功能](../implemented.md) · [English](../../implemented/async.md)
|
|
4
4
|
|
|
5
5
|
实现位置:`runtime/xt_async.c`、`runtime/xt_coroutine.c`、`runtime/xt_promise.c`、
|
|
6
|
-
`runtime/xt_generator.c`、`runtime/xt_loop.c`、`runtime/
|
|
6
|
+
`runtime/xt_generator.c`、`runtime/xt_loop.c`、`runtime/xt_async_io.c`、
|
|
7
|
+
`runtime/xt_performance.c`。
|
|
7
8
|
|
|
8
9
|
## async / await
|
|
9
10
|
|
|
@@ -35,4 +36,14 @@
|
|
|
35
36
|
- `setTimeout` / `clearTimeout` / `setInterval` / `clearInterval` / `setImmediate` / `clearImmediate` / `queueMicrotask` 与 `performance.now`(单调递增的小数毫秒)。
|
|
36
37
|
- 定时器使用数字 id;未实现 `Timeout` / `Immediate` 对象。
|
|
37
38
|
- 定时器 settle 的 promise 可以被 await:async 函数体在 pending promise 上挂起,定时器触发时恢复。套接字与服务端(`net`、`http`、`dgram`)的回调在同一事件循环上投递。
|
|
38
|
-
- `fetch`
|
|
39
|
+
- `fetch` 与 `fs/promises` 由 reactor 驱动而不是阻塞 —— 见下一节。
|
|
40
|
+
|
|
41
|
+
## 异步 I/O offload
|
|
42
|
+
|
|
43
|
+
- `runtime/xt_async_io.c` 维护一个小型工作线程池(默认 4 个,惰性创建)。每个 job 分成两半:worker 上的 `run` 只能访问纯 C 内存;主线程上的 `complete` 才构造值并 settle promise。这个拆分让回收器与值模型保持单线程。
|
|
44
|
+
- job 完成后通过自管道(POSIX)或回环 UDP 套接字(Windows)唤醒 `select(2)`;reactor 也会轮询线程池,因此唤醒失败只会退化为短暂等待,而不会挂起。
|
|
45
|
+
- job 排队或运行期间,每个 job 最多四个值(promise;对 `fetch` 还有 headers 对象)保存在 job 的 root 槽中,由回收器扫描。
|
|
46
|
+
- `fetch` 把每一跳请求/重定向作为 job 执行;`fs/promises` 把每个文件与描述符操作作为 job 执行。两者都不会阻塞定时器、套接字或其他 `await`。
|
|
47
|
+
- 仍有 job 未完成时事件循环保持存活(`xt_loop_has_work`),线程池空闲后退出。
|
|
48
|
+
|
|
49
|
+
异步表面的已知限制(`fetch` 无 TLS/流式、`fs.watch` 不触发、线程池固定 4 个 worker)列在[运行时偏差](../unimplemented/deviations.md)与各 Node 页面。
|
|
@@ -2,11 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
> 属于[已实现语法与功能](../implemented.md) · [English](../../implemented/fetch.md)
|
|
4
4
|
|
|
5
|
-
实现位置:`runtime/xt_fetch.c`。
|
|
5
|
+
实现位置:`runtime/xt_fetch.c`、`runtime/xt_fetch/async.inc`、`runtime/xt_async_io.c`。
|
|
6
6
|
|
|
7
|
-
- 全局 `fetch(input, init)`
|
|
7
|
+
- 全局 `fetch(input, init)` 是 HTTP/1.1 客户端。阻塞的套接字交换(`getaddrinfo`、connect、send、receive)运行在异步 I/O 工作线程池上,因此进行中的请求**不会**卡住事件循环:定时器、套接字与其他 `await` 继续运行,promise 在 reactor 派发完成结果时 settle。
|
|
8
|
+
- 重定向在主线程上处理:每一跳是一次 offload 交换,最多 20 次;301/302/303 会把 POST 改成 GET。
|
|
8
9
|
- 只接受 `http://` URL —— 由于未链接 TLS 后端,`https://` 会以 `TypeError` 拒绝。
|
|
9
|
-
- 选项:`method`、`headers`(普通对象或 `Headers`)、`body` 与 `redirect`(`follow` / `manual` / `error
|
|
10
|
-
- 解析出的 `Response` 形状对象暴露 `ok` / `status` / `statusText` / `url` / `headers` 以及 `text()` / `json()` / `arrayBuffer()` / `bytes()` / `clone()
|
|
10
|
+
- 选项:`method`、`headers`(普通对象或 `Headers`)、`body` 与 `redirect`(`follow` / `manual` / `error`)。
|
|
11
|
+
- 解析出的 `Response` 形状对象暴露 `ok` / `status` / `statusText` / `url` / `headers` 以及 `text()` / `json()` / `arrayBuffer()` / `bytes()` / `clone()`。响应体在 promise settle 前已完整缓冲;不支持流式响应体。
|
|
11
12
|
- `Headers` 大小写不敏感,提供 `get` / `has` / `set` / `append` / `delete` / `keys` / `values` / `entries` / `forEach` / `getSetCookie`。
|
|
12
13
|
- 非法 URL 与网络失败会以 `TypeError` 拒绝。
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
async function main(): Promise<void> {
|
|
17
|
+
const response = await fetch("http://127.0.0.1:8080/status");
|
|
18
|
+
console.log(response.status, await response.text());
|
|
19
|
+
}
|
|
20
|
+
main();
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
在请求完成前安排的定时器会在交换仍在进行时触发:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
const pending = fetch("http://127.0.0.1:8080/slow");
|
|
27
|
+
setTimeout(() => console.log("timer"), 10); // 会在 150ms 的响应之前运行
|
|
28
|
+
await pending;
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
已知限制(仅 `http://`、无 TLS、响应体整体缓冲)列在[运行时偏差](../unimplemented/deviations.md)。
|
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
> 属于[Node 扩展:已实现](../node.md) · [English](../../../implemented/node/fs-promises.md)
|
|
4
4
|
|
|
5
|
-
实现位置:`src/extensions/node/fs-promises/index.ts`、`runtime/ext_node/fs/promises.c`
|
|
5
|
+
实现位置:`src/extensions/node/fs-promises/index.ts`、`runtime/ext_node/fs/async_*.c`、`runtime/ext_node/fs/promises.c`
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
每个函数都会向运行时的异步 I/O 线程池(`runtime/xt_async_io.c`)提交一个 job:阻塞的系统调用在 worker 线程上执行,promise 在事件循环上 settle。因此 `await` 在大文件读取、慢速网络文件系统或描述符操作进行期间会让出,`then` / `catch` 保持标准 Promise 语义。失败时会以与同步形式相同的 Node `Error`(含 `code` / `errno` / `syscall` / `path`)**reject**。
|
|
8
|
+
|
|
9
|
+
`fs.promises` 也可从 `fs` 模块访问(`import { promises as fsp } from "fs"`),两个命名空间都暴露 `constants` 对象。
|
|
8
10
|
|
|
9
11
|
Promise 导出:`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`。
|
|
10
12
|
|
|
11
|
-
`open(...)` 解析为 **`FileHandle`**,带有:`read`、`write`、`readFile`、`writeFile`、`appendFile`、`close`、`stat`、`truncate`、`chmod`、`chown`、`utimes`、`sync`、`datasync`。
|
|
13
|
+
`open(...)` 解析为 **`FileHandle`**,带有:`read`、`write`、`readFile`、`writeFile`、`appendFile`、`close`、`stat`、`truncate`、`chmod`、`chown`、`utimes`、`sync`、`datasync`。这些方法同样会 offload;`read(buffer, …)` 会在 worker 完成后填充调用方的 `Buffer`。
|
|
12
14
|
|
|
13
15
|
```ts
|
|
14
16
|
import { readFile, writeFile, open } from "fs/promises";
|
|
@@ -23,5 +25,6 @@ async function main(): Promise<void> {
|
|
|
23
25
|
main();
|
|
24
26
|
```
|
|
25
27
|
|
|
28
|
+
工作由固定的小型线程池(4 个 worker)执行,完成结果按每个 worker 的提交顺序派发;相互独立的操作可以重叠。任何 job 都不会阻塞其他 `await`、定时器或套接字回调。
|
|
26
29
|
|
|
27
30
|
已知偏差见[未实现:`fs/promises`](../../unimplemented/node/fs-promises.md)。
|
|
@@ -17,7 +17,7 @@ TypeScript 导出与 C 实现一一对应。新增模块不需要改动核心编
|
|
|
17
17
|
| 模块 | 页面 | 说明 |
|
|
18
18
|
| --- | --- | --- |
|
|
19
19
|
| `fs` | [fs](./node/fs.md) | 仅同步 API |
|
|
20
|
-
| `fs/promises` | [fs/promises](./node/fs-promises.md) |
|
|
20
|
+
| `fs/promises` | [fs/promises](./node/fs-promises.md) | 由 reactor 驱动、跑在异步 I/O 线程池上的文件与 `FileHandle` 操作 |
|
|
21
21
|
| `path` | [path](./node/path.md) | `path.<name>(...)` 命名空间调用 |
|
|
22
22
|
| `os` | [os](./node/os.md) | `os.<name>(...)` 命名空间调用 |
|
|
23
23
|
| `process` | [process](./node/process.md) | 对象:方法与属性 |
|
package/doc/zh-CN/implemented.md
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
- [集合](./implemented/collections.md) —— Map、Set、WeakMap、WeakSet、WeakRef、迭代
|
|
32
32
|
- [类型化数组与二进制数据](./implemented/typed-arrays.md) —— 类型化数组、ArrayBuffer、DataView
|
|
33
33
|
- [异步、Promise 与生成器](./implemented/async.md) —— async/await、异步生成器、Promise、定时器
|
|
34
|
-
- [fetch](./implemented/fetch.md) ——
|
|
34
|
+
- [fetch](./implemented/fetch.md) —— 由 reactor 驱动的 HTTP/1.1 客户端与 Headers
|
|
35
35
|
|
|
36
36
|
### 模块与工具
|
|
37
37
|
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
| 数组越界 / 稀疏 | 越界访问返回 `undefined`;对 `arr.length` 赋值会截断 / 扩展,但不区分稀疏空洞 |
|
|
15
15
|
| 内存管理 | 非移动标记-清扫回收器(在 `xt_alloc` 之后):显式根、子系统根提供者与保守 C 栈扫描。单线程、stop-the-world;无移动/压缩与分代 |
|
|
16
16
|
| 函数 `arity` / 调用参数个数 | 无参数个数校验;`fn.length` 报告声明的 arity,但调用不做校验 |
|
|
17
|
-
| `async` / `await` | 已在栈式协程上真实挂起;`await` 总会排入一次微任务(非 Promise 与已 settle 的 Promise 也一样),因此与 pending `.then` 回调的交错顺序符合规范。顶层 `await` 会阻塞事件循环等待,而不是让出模块主体。`fs/promises`
|
|
17
|
+
| `async` / `await` | 已在栈式协程上真实挂起;`await` 总会排入一次微任务(非 Promise 与已 settle 的 Promise 也一样),因此与 pending `.then` 回调的交错顺序符合规范。顶层 `await` 会阻塞事件循环等待,而不是让出模块主体。`fs/promises` 与 `fetch` 把阻塞工作 offload 到 4 线程池并在 reactor 上 settle。异步生成器可在 `await` 与 `yield` 处挂起,`for await...of` 每次迭代等待一步 |
|
|
18
18
|
| 异步生成器清理 | `for await...of` 提前退出时不会调用迭代器的 `return()`。异步生成器中的 `yield*` 只委托同步可迭代对象。在挂起的 `yield` 处调用 `.return()` 会直接完成而不执行 `finally`(与同步生成器相同的限制) |
|
|
19
19
|
| `super` | `super.x` / `super(...)` 取 `this` 原型的原型;单级继承正确,继承深度 > 1 时可能不准确 |
|
|
20
20
|
| `Error.stack` | 仅函数级帧:每帧为 `at 名称 (文件:行)`,行号取自函数声明(最内层帧会更新为错误构造处);没有列号,生成器 / `async` 函数体不产生帧(它们会切换栈) |
|
|
@@ -5,13 +5,16 @@
|
|
|
5
5
|
已实现部分:
|
|
6
6
|
|
|
7
7
|
- 核心事件循环 `runtime/xt_loop.c`(`select(2)` 反应堆),`net` / `dgram` / `http` 均构建于其上。
|
|
8
|
-
-
|
|
8
|
+
- 异步 I/O offload `runtime/xt_async_io.c`:阻塞的文件与 HTTP 客户端工作在 4 个工作线程上执行,并在 reactor 上完成,因此 `fs/promises` 与 `fetch` 不会卡住定时器或套接字。
|
|
9
|
+
- `Promise`、`async` / `await` 已可用(见核心文档),`fs/promises` 返回从 reactor settle 的 Promise。
|
|
9
10
|
- 定时器已作为全局函数提供:`setTimeout` / `clearTimeout` / `setInterval` / `clearInterval` 运行在核心反应堆上,并在仍有定时器时保持进程存活。
|
|
10
11
|
- 提供独立的 `EventEmitter`(`events` 模块,同时也是全局构造函数);流与套接字额外具备内部发射器方法(`on` / `addListener` / `once` / `off` / `removeListener` / `emit`)。
|
|
11
12
|
|
|
12
13
|
仍未实现:
|
|
13
14
|
|
|
14
15
|
- Node 的 `Timeout` 对象(`setTimeout` 返回数字 id;`setImmediate` 与 `queueMicrotask` 已作为全局函数提供)。
|
|
15
|
-
-
|
|
16
|
+
- 文件监听:`fs.watch` / `fs/promises.watch` 返回惰性对象;没有 inotify/kqueue/ReadDirectoryChangesW 后端。
|
|
17
|
+
- `Dir.read` / `Dir.close` 立即调用回调,回调式 `fs.readFile` / `fs.writeFile` / … 仍不支持(请用 `fs/promises` 或 `*Sync` 形式)。
|
|
16
18
|
- 流与套接字的内置 `once` 等同 `on`(不具「触发一次后移除」语义);`events` 模块的 `EventEmitter` 实现了真正的 `once`。
|
|
17
|
-
- `net` 的 `connect`
|
|
19
|
+
- `net` 的 `connect` 仍是在套接字加入 reactor 之前执行的阻塞 `connect(2)`;HTTP 响应要求 `Connection: close`,不做 keep-alive / 分块传输 / 流水线复用。`fetch` 没有 TLS,且在 resolve 前缓冲整个响应体。
|
|
20
|
+
- offload 线程池固定为 4 个 worker;没有线程池大小选项,也不支持对排队 job 的 `AbortSignal` 取消。
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
> 属于[Node 扩展:未实现](../node.md) · [English](../../../unimplemented/node/fs-promises.md)
|
|
4
4
|
|
|
5
|
-
`fs/promises`
|
|
6
|
-
[已实现:`fs/promises`](../../implemented/node/fs-promises.md))。
|
|
5
|
+
`fs/promises` 现在把阻塞 I/O offload 到异步 I/O 线程池(已实现表面见[已实现:`fs/promises`](../../implemented/node/fs-promises.md));剩余差异主要是行为层面的:
|
|
7
6
|
|
|
8
|
-
- I/O 是同步的:Promise 在 `await` 之前就已 settle,因此 await 它不会让出事件循环。
|
|
9
7
|
- `FileHandle.appendFile` 行为等同 `writeFile`(按当前文件位置写入,而不是追加)。
|
|
10
8
|
- `FileHandle.readFile()` 从当前描述符偏移读取。
|
|
11
|
-
- `Dir.read` / `Dir.close`(同步与 Promise
|
|
9
|
+
- `Dir.read` / `Dir.close`(同步与 Promise 形式)立即调用回调;`Dir.readSync` / `closeSync` 仍是同步的。
|
|
12
10
|
- `watch` resolve 为与 `fs.watch` 相同的、永不触发的 watcher;没有真正的文件监听后端。
|
|
11
|
+
- 读写是一次性整体操作;没有流式 `FileHandle` 变体,也不支持 `AbortSignal` 取消。
|
|
12
|
+
- 线程池固定为 4 个 worker;大量并发操作会排队(但仍不会阻塞事件循环)。
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> 属于[Node 扩展:未实现](../node.md) · [English](../../../unimplemented/node/fs.md)
|
|
4
4
|
|
|
5
|
-
`fs`
|
|
5
|
+
`fs` 实现了**同步** API 表面(文件、目录、描述符、元数据、链接、`cp`、`glob`、`Dir`、`constants`),`fs/promises` 则把每个文件/描述符操作跑在异步 I/O 线程池上(见[已实现:`fs`](../../implemented/node/fs.md)与[已实现:`fs/promises`](../../implemented/node/fs-promises.md))。仍缺少的主要是需要不同后端或回调管线的 API:
|
|
6
6
|
|
|
7
7
|
| 未实现 API | 类别 |
|
|
8
8
|
| --- | --- |
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
- `readFileSync` 支持编码选项(默认/`utf8`/`ascii`/`latin1`/`binary`/`hex`/`base64`/`base64url`),但默认**不返回 `Buffer`**:即使提供了 `Buffer`(以普通对象模拟),`readFileSync` 仍以字符串返回。要读取原始字节请显式指定。
|
|
18
18
|
- 未实现 `utf16le` / `ucs2` 解码(按文本返回字节)。
|
|
19
19
|
- `watch` / `watchFile` / `unwatchFile` 返回 API 形态的发射器对象,`.close()` / `.on()` 方法存在但**不会触发**事件。
|
|
20
|
-
- `Dir.read(cb)` / `Dir.close(cb)`
|
|
20
|
+
- `Dir.read(cb)` / `Dir.close(cb)` 会**同步**完成(回调立即被调用);`FileHandle` 方法现在返回真正的 Promise。
|
|
21
21
|
- `mkdtempSync` 总是向前缀追加 6 个随机字符(不要求以 `XXXXXX` 结尾)。
|
|
22
22
|
- `globSync` 支持 `*`、`?`、`[...]`、`**`,但不支持 `exclude` 回调与 `follow`;`**` 不跟随符号链接(与 Node 默认一致)。
|
|
23
23
|
- `cpSync` 的符号链接处理在常见场景下与 Node 一致,但不支持 `verbatimSymlinks`。
|
|
@@ -8,10 +8,10 @@ Node 扩展实现了 21 个模块以及事件循环集成;已实现表面按
|
|
|
8
8
|
## 目录
|
|
9
9
|
|
|
10
10
|
- [`fs`](./node/fs.md) —— 回调式异步操作、真正的文件监听、选项回调
|
|
11
|
-
- [`fs/promises`](./node/fs-promises.md) ——
|
|
11
|
+
- [`fs/promises`](./node/fs-promises.md) —— `FileHandle` 追加/读取偏移、`Dir` 回调立即完成、`watch` 不触发、无取消
|
|
12
12
|
- [完全未实现的模块](./node/modules.md) —— `https`、`readline`、`tls`、`cluster`、`vm` 等
|
|
13
13
|
- [全局对象与命名空间](./node/globals.md) —— `global`、`__dirname`、`node_modules` 之外的 `require`
|
|
14
|
-
- [异步与事件循环模型](./node/async.md) ——
|
|
14
|
+
- [异步与事件循环模型](./node/async.md) —— 文件监听缺失、阻塞式 `net.connect`、无 keep-alive、固定大小线程池
|
|
15
15
|
- [Bun 扩展](./node/bun.md) —— 仅为设计示例
|
|
16
16
|
|
|
17
17
|
模块的已实现页面会链接到对应限制页;限制解除后,把条目移到
|
|
@@ -9,6 +9,6 @@
|
|
|
9
9
|
| 类型检查器 | ✗ 仅定义诊断码,无 checker |
|
|
10
10
|
| 完整标准库 | 部分:Math / JSON / Date / Map / Set / RegExp / `Error` / `BigInt` / `Symbol` / `structuredClone` 已实现;String.normalize 缺失 |
|
|
11
11
|
| 多文件模块打包 | 部分:相对路径 `.ts` 打包、ESM `node_modules` 包、命名空间导入、裸说明符扩展模块导入已实现;CommonJS 仅在 `node_modules` 内处理;循环依赖 / 实时绑定未实现 |
|
|
12
|
-
| 异步运行时 | ✓ `async`/`await` 在 `select(2)` reactor 上对 pending promise 挂起:定时器、TCP
|
|
12
|
+
| 异步运行时 | ✓ `async`/`await` 在 `select(2)` reactor 上对 pending promise 挂起:定时器、TCP 套接字、offload 的文件/HTTP 工作与 promise 回调都能恢复协程。仍缺:真正的 OS 级文件监听、非阻塞 `net.connect`、`fetch` 的 TLS,以及用户可见的 worker 线程(`worker_threads` 仍用子进程) |
|
|
13
13
|
| Windows 二进制产物验证 | 构建层已适配(`.exe` 后缀、链接参数分支),并在 CI 中验证 |
|
|
14
14
|
| 精确的 ECMAScript 数值 / 字符串 / 比较语义 | 部分,见[运行时偏差](./deviations.md) |
|