Preserve native class state and handle terminal process events (#571)

- Preserve fields, accessors, added properties, and cyclic references across untyped class boundaries.
- Support platform signal names and native exception handlers that resume queued work.
This commit is contained in:
Chris Tate
2026-09-29 09:09:34 -05:00
committed by GitHub
parent f8906d0b75
commit 13718c7ac1
42 changed files with 1121 additions and 289 deletions
+7
View File
@@ -13,6 +13,7 @@ These are rejected at compile time with an `SC` code, a code frame, and usually
**Language edges**
- `Error`, `TypeError`, `RangeError`, and `SyntaxError` accept `{ cause }` options, including through inherited constructors. Reading, assigning, deleting, and testing `"cause" in error` preserve the distinction between an absent cause and an explicitly undefined cause. Constructor causes are non-enumerable; assignment creates an enumerable property when the cause is absent. Property descriptors and checked-value aliases share the same cause, including getters and setters installed after construction. Accessor constructor options and explicit subclass redeclarations of `cause` remain unsupported.
- Native class fields, inherited accessors, and added properties retain their identity across untyped values. Reflection such as `JSON.stringify` and `Object.keys` still requires every declared field to have a supported checked-value representation; classes containing opaque fields such as native Maps retain a checked error for those operations.
- Native class methods can be stored and passed as unbound function values. A field call supplies the containing instance as `this`; `call`, `apply`, and `bind` work when the function signature can cross the checked-value boundary. Extracted overrides keep the selected method even when called with another receiver. Receiver validation accepts the declaring class and its subclasses; borrowing a method onto an unrelated object remains unsupported. Detached methods that use `this`, builtin method values, abstract method declarations, unspecialized generic methods, and incompatible override signatures retain checked errors or compile-time refusals.
- Loose `==`/`!=` comparisons compile across statically represented primitive and primitive-union operands, including number/string/boolean/BigInt coercions and the `x == null`/`x != null` nullish idiom. Object-to-primitive comparisons remain fenced because custom `valueOf`/`toString` methods can execute arbitrary code; convert the object explicitly first.
- Block- and function-scoped `using` and `await using` compile for statically represented classes with zero-parameter disposal methods and for the supported FileHandle, timer, immediate, child-process, and readline handles. Array `for (using ... of ...)` loops compile. Top-level and switch-clause declarations, disposal through an engine-held package value, and the `DisposableStack` constructors remain fenced; a caught `SuppressedError` exposes its Node-compatible `name` and `message`, while its `error` and `suppressed` payload properties remain outside the static catch surface.
@@ -120,6 +121,12 @@ A static-tier program otherwise produces byte-identical stdout and the same exit
- **Top-level `await` in embedded ESM packages** is not supported yet. It does compile in your program's own ESM graph and in npm packages compiled through `--npm-static`; the remaining limit is package code running inside the `--dynamic` island.
- **`--npm-static` and `--provenance-sources` are experimental** — see [npm Dependencies](/dependencies) for the maturity notes.
## Process events
Static signal listeners resolve names on the target platform, including `SIGWINCH` for terminal resize on POSIX. `on`, `once`, `off`, and `removeListener` accept computed signal names and deliver the signal name and number. Computed names for other process-event families and chained registrations remain unsupported. Windows signal registration remains limited to the CRT signal set; WASI has no OS signals.
Literal `uncaughtException` and `uncaughtExceptionMonitor` registrations compile without a JavaScript engine. Handled exceptions resume queued native work; monitors alone do not suppress failure. Error objects and primitive exception values cross the listener boundary, while arbitrary native objects retain the existing exception-value restrictions. Exception capture callbacks and dynamic-island exception handling remain unsupported.
## Native addons
Node-API (N-API) and V8 `.node` addons require Node's addon runtime, which scriptc does not embed in either static or `--dynamic` builds. Direct `createRequire` calls to local addons are rejected at compile time. Embedded npm packages receive a catchable `ERR_DLOPEN_FAILED` when they attempt to load an addon, allowing packages with JavaScript fallbacks to select them.
@@ -2,6 +2,6 @@
"schemaVersion": 3,
"nodeVersion": "24.15.0",
"nodeCommit": "848430679556aed0bd073f2bc263331ad84fa119",
"artifactVersion": "a063593865cc30056a9c",
"artifactVersion": "e6aa3e9df87eb18c506b",
"rowCount": 3662
}
+11 -11
View File
@@ -842,9 +842,9 @@
"apiEntries": 119,
"static": {
"supported": 0,
"partial": 30,
"partial": 33,
"refused": 0,
"not-implemented": 89,
"not-implemented": 86,
"by-design": 0,
"unreviewed": 0,
"not-applicable": 0
@@ -65109,9 +65109,9 @@
"anchor": "event-uncaughtexception",
"nodeStability": null,
"static": {
"status": "not-implemented",
"detail": "No static compiler lowering is registered for this API yet.",
"verification": "registry-gap"
"status": "partial",
"detail": "Implemented for the documented scriptc module-loader subset.",
"verification": "test-backed"
},
"dynamic": {
"status": "not-implemented",
@@ -65155,9 +65155,9 @@
"anchor": "event-uncaughtexceptionmonitor",
"nodeStability": null,
"static": {
"status": "not-implemented",
"detail": "No static compiler lowering is registered for this API yet.",
"verification": "registry-gap"
"status": "partial",
"detail": "Implemented for the documented scriptc module-loader subset.",
"verification": "test-backed"
},
"dynamic": {
"status": "not-implemented",
@@ -65247,9 +65247,9 @@
"anchor": "signal-events",
"nodeStability": null,
"static": {
"status": "not-implemented",
"detail": "No static compiler lowering is registered for this API yet.",
"verification": "registry-gap"
"status": "partial",
"detail": "Implemented for the documented scriptc module-loader subset.",
"verification": "test-backed"
},
"dynamic": {
"status": "not-implemented",