The enum rewrite turns a package's numeric enum into one object holding
its names and its reverse mapping, so the object's fields have different
types. A reverse read with a runtime key, such as
DiagLogLevel[DiagLogLevel.WARN] in @opentelemetry/api, then failed with
SC1090 ("the declared fields have no one common type").
A keyed read of such a record already answers a checked-dynamic value in
JavaScript files. It now does the same where the checker types the read
'any'. The new npm case tsc-enum-reverse-reads matches Node, as does the
opentelemetry-api case again.
crypto.createECDH returns a native ECDH handle backed by mbedTLS for
prime192v1, secp224r1, prime256v1, secp384r1, secp521r1, secp192k1,
secp224k1, secp256k1, brainpoolP256r1, brainpoolP384r1 and
brainpoolP512r1. generateKeys, computeSecret, getPublicKey,
getPrivateKey, setPrivateKey, setPublicKey and ECDH.convertKey follow
Node 24: compressed, uncompressed and hybrid points, input and output
encodings, the private key range, key pair validation, and Node's error
codes and messages.
Curve names follow OpenSSL's short-name lookup: names of other curves
from crypto.getCurves() are refused at compile time when literal and
throw a coded SC2020 error when computed, other OpenSSL short names
throw ERR_CRYPTO_OPERATION_FAILED, and unknown names throw
ERR_CRYPTO_INVALID_CURVE. Calls whose arguments no @types/node overload
accepts, and computeSecret(view, encoding), are refused at compile time.
The runtime unit scr_ecdh.c links, with the mbedTLS archive, only into
programs that use ECDH. wasm32-wasi builds refuse it.
hot-shots, a StatsD client compiled from its JavaScript, failed when a
program constructed a client. Each gap on its UDP path is closed
generically:
- Sloppy-mode functions with named parameters may read `arguments`
where the aliasing of their parameters cannot show: only
`arguments.length`, or element reads without parameter or element
writes.
- An `any` slot admits any boxable function value, including functions
with optional parameters (`C.prototype.m = function (...)` through an
untyped receiver).
- In a JavaScript file TypeScript does not check, a prototype method
takes its documented parameters as checked-dynamic values, as
constructors already did.
- JavaScript dgram sends run completion callbacks, buffer lists,
connected sends and the six-argument offset/length form.
- A dgram socket crosses into the checked-dynamic tree as a handle
(SCR_DYNH_DGRAM_SOCKET) whose methods are function values, with
untyped listeners that survive 'close'. The handle lives in its own
runtime unit (scr_dgram_dyn.c, the dgramDyn feature), linked only
when a program converts a socket to or from an untyped value.
- `String.prototype.concat` on strings, and `parseInt` over a possibly
missing or untyped value in JavaScript.
Corpus programs 6590-6596 and the hot-shots-udp npm
case (hot-shots 8.5.0 vendored) match Node in both lanes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In JavaScript, `ReleaseEmitter = EventEmitter` over `const EventEmitter =
require("events")` was refused with SC1090 ("a runtime-provided class value
as an untyped value"), and `class Channel extends require("events")` failed
on the require call as a value. Bundled npm code does both, for example a
small semaphore that aliases EventEmitter and constructs its release channel
through the alias.
- The events module binding and the EventEmitter or stream class itself
turn untyped as the runtime's untyped constructor that constructor
functions already use (scr_dyn_builtin_class.c). `new` through it builds
an emitter object with Node's listener API, and `===` against the class
compares identity.
- `x instanceof EventEmitter` on an untyped value also recognizes a boxed
compiled emitter (an instance of a program class extending EventEmitter),
which the prototype test alone answered false for. The same holds through
an untyped binding narrowed to the class.
- `class X extends require("events")` extends the runtime emitter, as
through a require binding.
- A typed array of the class built from such values (`[EventEmitter]`) is
refused with SC1090 rather than failing its class check at run time.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The frontend calls tokenStartOfNode, getTextOfNode, getSourceFileOfNode and
forEachChild instead of AstNode's position and traversal methods. Node lists
answer hasTrailingComma(), and a declaration's modifiers are a modifier list
with their flags.
Symbol, Type, Signature, IndexInfo, TypePredicate, Program, TypeChecker and
Diagnostic have tsc-ts/api's members and types. Compiler code reads symbol
names with symbolName(symbol).
tsc-ts goes to 0.0.5. api-conformance.ts asserts that AstNode, AstNodeList,
SourceFile and each node interface are assignable to tsc-ts/api's interface of
the same name, and names the members where the wire format differs.
@types/node declares http_parser, v8, uv, zlib, ares and modules as plain
strings, but the runtime's versions object holds only node and openssl. The
dyn read was narrowed to the declared string with a checked extraction, so
comparisons with undefined folded to false and other uses threw. Such reads
now keep the undefined arm, like the optional stream properties, and
unannotated bindings initialized from them store the same union.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Merge origin/main (e9fb01603); the import lines at the top of
lowerer.ts conflicted and both are kept.
- Corpus 6385 gains a wrapper whose block-local `args` alias shadows an
outer one in the same function; each call forwards its own arguments.
A method call declared to return `this`, such as setEncoding, resolves to
its receiver's access path, so a 'data' listener on the stream that
`const out = child.stdout.setEncoding("utf8")` returns receives strings.
A setEncoding call that a preceding statement always evaluates (its
expression, a variable initializer, or the receiver of a method chain in
one of those) counts as preceding the listener. Only `new` and the
child_process factories (spawn, fork, exec, execFile) count as creating a
separate stream; any other call result may be a stream another binding
already holds.
A redirect fetch followed or rejected was marked to drain: its body was
read and dropped until the server ended it, and the abort listener was
already removed. A body that never ends kept the connection busy after
cancellation and stalled a pool of one connection. Following or
rejecting a redirect now aborts its request, so the connection closes.
undici 7 leaves that connection open with its body paused, which stalls
the same pool; the follow-up request here gets a new connection.
A redirect fetch followed or rejected was marked to drain: its body was
read and dropped until the server ended it, and the abort listener was
already removed. A body that never ends kept the connection busy after
cancellation and stalled a pool of one connection. Following or
rejecting a redirect now aborts its request, so the connection closes.
undici 7 leaves that connection open with its body paused, which stalls
the same pool; the follow-up request here gets a new connection.
6490 covers events.once with an AbortSignal: abort, an aborted signal, an
undefined signal, abort-listener order, 'removeListener' events, a
throwing 'newListener' listener and the settlement turns. 6491 covers
stream receivers (file streams, Readable.from, a destroyed PassThrough, a
Writable) and a NodeJS.ReadableStream part raced against its destination.
6492 covers races over events.once results with entries that only reject
and entries of different value types. 6493 covers stream subclasses whose
completion callbacks are typed `Function`. 6494 covers events.once over
checked-dynamic stream slots. The node-types fixture runs the race shapes
under @types/node, where events.once returns Promise<any[]>.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- matchInferSignature reads a fixed-tuple rest as its positions, so
(...args: [string, number]) needs two arguments, and a positional
any[] pattern parameter matches only when the function's parameter
there accepts an array, as TypeScript's assignability does
(corpus 6398).
- Merge origin/main (200fe8d22); node-v24-backlog.json regenerated.
- dns.lookup with options known only at run time (a checked-dynamic
value, or one cast to an overload's option type) may answer a string or,
with `all: true`, an address list, whatever the overload the checker
picked says: an inline callback now binds its parameters as
checked-dynamic values. Array.isArray tests a checker-narrowed dyn read's
dyn value instead of folding on the extracted type, so it never answers
false for an address list the declared type omits.
- net.connect({ lookup }) accepts a lookup of Node's own type
(net.LookupFunction: options plus a callback taking an address string
or list), called as Node's autoSelectFamily dial does ({ hints, all:
true }); the fallback declarations spell net.LookupFunction that way.
dns.lookup accepts Node's hints flags (ADDRCONFIG, V4MAPPED, ALL) and
passes them to getaddrinfo.
- A CommonJS export typed as the empty object literal (tsc's enum output
`exports.E || (exports.E = {})` after `exports.E = void 0`) rides
checked-dynamic storage, so the preamble's undefined no longer traps at
module load: @opentelemetry/api loads and its no-op metrics and trace
APIs run.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The export-alias rewrite skipped a whole function when a let or const
anywhere inside it declared the alias's name, so the function's other
references to the alias kept the alias name after its declaration was
removed. A function now shadows the alias only through its parameters,
its own name, its vars and the declarations directly in its body; a
block, case block, catch clause or for loop shadows it through its own
declarations, and the walk skips just that scope.
- Merge origin/main (e1c27176a).
- matchInferSignature answers false when a function needs more arguments
than a fixed-parameter pattern passes, as TypeScript's assignability
does (corpus 6398).
- Record corpus costs for the programs this change adds.
- Promise.race admits a Promise<never> entry (the deadline idiom) under
any result type: it can only reject, so its fulfillment adapter traps.
A Promise<never> executor's one-parameter resolve validates against the
void inner.
- Array(n).fill(v) and new Array(n).fill(v), which the checker types as
any[], take v's type.
- Object.entries/values over an index-signature record cast to a narrower
value type check each value into the element type instead of refusing.
- dns.LookupAllOptions and the lookup-function option union that holds it
(LookupOneOptions | LookupAllOptions | number | undefined) ride
checked-dynamic storage, and dns.lookup passes a cast of a
checked-dynamic options value through unchanged.
- npm packages: a CommonJS module that names its export object through a
variable (`var ip = exports; ip.isPrivate = ...`, the ip package) is
respelled through `exports`, and tsc output that adds a default-export
object (`exports.default = { metrics: metrics_api_1.metrics }`, the
@opentelemetry/api index) keeps its named exports linked.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Node answers a Unix-socket server's address() with its path. Programs
that call listen() with a string argument now get a Unix-aware
address(): typed `string | AddressInfo | null` (the @types/node
declaration), it answers the path; typed as the AddressInfo record alone,
which cannot hold the path, it throws for such a server, as does the
composed address().port read. Every other program keeps the record-only
lowering, so their output is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@types/node types the transform/flush completion callback's data as any
and a child stream 'data' chunk as any, and ChildProcess accepts
(code: number, signal: string) exit and close listeners through its
catch-all overload. None of these compiled: the any-typed completion
callback crashed the LLVM emitter, and the child listeners were refused.
The completion callback's data parameter is typed Buffer | string |
undefined while the option callback lowers. Child stream 'data' listeners
with an unknown or any chunk box it as a checked-dynamic value, taking
strings when a setEncoding statement on the same stream precedes the
listener and Buffers when the function never calls setEncoding on it;
other placements are refused. Exit and close listener parameters declared
number or string bind as checked-dynamic values, so the body sees the
null Node passes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A workspace package loaded on demand had its npm dependency selected, but
the selection never scanned that dependency's own JavaScript: it is
outside the startup module order, so a compiled CommonJS dist requiring a
sibling package was refused with "the module is not supported yet". The
scan of the import() graph now follows opted-in package JavaScript through
its literal require() and import edges.
The lowering appended those modules by their import declarations only, so
a CommonJS file's requires never joined the compiled graph and their
bindings stayed fenced. Preflight's resolved module edges, require edges
included, now reach the walks that append import(), fork() and Worker
modules, with lazy requires ordered after their module and inline require
cycles answered as at startup.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
http.request, https.request and get now accept options the compiler
cannot see as an object literal: a RequestOptions variable, a literal
that spreads one, or a literal that sets socketPath. The runtime reads
the record in the ClientRequest constructor's order with Node's errors;
documented options it does not implement throw the runtime fence when
they carry a value. https adds rejectUnauthorized, ca and servername.
socketPath dials a Unix domain socket in the net unit; the agent keys
its sockets by the path as Node's getName does, and the Host header
defaults to localhost. server.listen(path[, cb]) binds a Unix socket and
removes the socket file when the server closes; a numeric string is
still a port. Errors name the path ("connect ENOENT /path", "listen
EADDRINUSE: address already in use /path"). Windows reports ENOTSUP.
A TypeScript object literal with no contextual type that spreads a
checked-dynamic value maps to the checked dynamic, so
`const options = { ...location, path, timeout }` compiles.
A socket's 'lookup' event reaches its listeners with (err, address,
family, host) for each address a host name resolves to, or once with
the lookup error, before 'connect'. Only programs that listen for
'lookup' install the lookup records; elsewhere the hook sites are a NULL
check.
server.close((err) => ...) runs the callback with undefined at 'close',
or with ERR_SERVER_NOT_RUNNING when the server was not listening; a
server that never listened now emits 'close'. IncomingMessage 'data'
listeners may take string chunks after setEncoding, and res.end()
accepts a string-or-undefined chunk.
fetch's BodyInit and HeadersInit unions, as RequestInit-derived option
types spell them under @types/node, map to the checked dynamic, and a
URLSearchParams body is sent form-encoded, as by Node.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- writeFile and outputFile with byte data and a mode open the file with
that mode, and writeJsonSync and outputJsonSync pass the mode.
- copySync and moveSync compare source and destination inodes and walk
the destination's parents, as copy and move do.
- The resolver parity sweep skips the project-import comparison for
shimmed packages.
- The JSON reader writes the byte order mark as an escape.
Replaces the single-parent "Merge main" squash (6ab9a5423) with a two-parent merge of the same tree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>