Main now compiles minified npm packages (#1989), so ni-minified no
longer refuses and the island report lost its packaging class. The
fixture is now ni-bundled, whose build-transform markers still refuse it
as shipped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main now reports fenced sites in module top-level code under "runs at
startup"; the use of 'legacy' on line 22 is one of them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A for-in or for-of loop stores its var binding only when it iterates. The
early-read analysis counted the loop as an unconditional store for every
later statement, so after a loop that ran zero times a closure read the
binding as initialized (typeof answered "string" where Node answers
"undefined"). The loop now settles the reads in its body; later reads
settle at the next unconditional store.
Records are width-tolerant, and a union's arms were tried in canonical
order, which sorts record arms by shape id. When a `{}` arm, or an arm
whose fields are all optional, came first, it took every object, so a
value converted to the union lost the fields only a wider arm has:
const pairs = [["a", { publicKeyEncoding: 5 }], ["b", {}]];
for (const [, v] of pairs) console.log(Object.keys(v));
printed [] twice, where Node prints [ 'publicKeyEncoding' ] and [].
A checked cast to `{ p: number; q: string } | { p?: number }` dropped
`q` the same way.
The checked conversion now tries record arms with more required fields
first, then those with more fields, and keeps the canonical order
otherwise. The union's tags are unchanged.
The test refused unchecked-dependency only because its one-line index.js
looked minified. A dependency another package's JavaScript imports needs
no declarations of its own (npmStaticIneligibleReason's untypedDependency),
so with the minified refusal gone it compiles; the test now builds it and
checks the library's result.
Refs #1777
An identifier-minified esbuild bundle renames the __commonJS helper
(var j=(u,t)=>()=>(t||u((t={exports:{}}).exports,t),t.exports)). The
recognizer already compared the helper's shape independently of its
parameter names, but only used a renamed match to refuse the package.
A stable top-level declaration with the helper's shape now splits the
bundle's chunks like the named helper, so lru-cache's CommonJS build is
no longer refused.
The EventTarget method values are cached for the program, and exit
released them only when an EventTarget, an event or a listener had
registered the unit's teardown. A program that read an AbortSignal's
addEventListener and never added a listener or made a target left the
cached functions live, and RC-audit builds exited with 99. Caching a
method value now registers the teardown too.
Refs #1777
npm packages are no longer refused up front for minified JavaScript. A
bundle whose interop helpers lost their names is still refused by the
bundle recognizers, and a package whose attempt fails is still refused on
its own.
A `var` read in a later declarator of the statement that stores it
(`var a = {...}, b = {...a}`) runs after the store. A read in a function
body is now located at the body's own statement instead of the body, so
JavaScript `var` bindings read after their store in a function keep their
type instead of gaining undefined.
`replace` and `replaceAll` with an untyped search value and a callback
call the regex callback replacement for a RegExp and the string-search
helper otherwise. That helper now accepts untyped callback parameters,
passes undefined to parameters after the subject, and converts number,
boolean and untyped results with ToString.
In JavaScript, `||` and `&&` over primitives of different types whose
result tsc types `any` evaluate in the checked domain.
An AbortSignal answered addEventListener, removeEventListener and
dispatchEvent read as values with functions of its own, which only ran on
AbortSignal handles: calling one on a plain EventTarget threw
ERR_INVALID_THIS. In Node they are EventTarget.prototype's methods,
shared with every target. The signal's property read now answers the
EventTarget method values (scr_event_target_method_value), which run on
any EventTarget receiver, AbortSignal included, so
signal.addEventListener === new EventTarget().addEventListener holds.
The signal's own method table keeps throwIfAborted.
The declaration boundary projected a user-declared interface as plain
data even when it extends a package interface. effect's Request.tagged
constructors create such values (interface Double extends
Request.Request<number>) with a prototype, so the boundary cast threw
"expected a plain object (this value has a prototype)". A user
interface now projects only when every interface it extends is
user-declared too; other values keep their JavaScript-world typing, so
the package finds its prototype members when the value goes back to it.
A child spawned from a listener that runs during a poll pass, such as a
'close' listener, can exit before the next pass fires its 'spawn'
listeners. The same pass's waitpid loop then settled it with 'spawn' never
emitted. Settling an exited child now fires its pending 'spawn' listeners
first, before its stream data and 'exit', as Node emits them.
`other.#x ??= value` (and `||=`, `&&=`) on a receiver JavaScript leaves
untyped read and wrote an ordinary property named "#x" instead of the
brand-checked private field, so the field kept its old value. Hono's
RegExpRouter numbers its parameter nodes with `next.#varIndex ??=
context.varIndex++`; without the stored index its regular expression lost
every parameter capture, and `c.req.param("id")` answered undefined.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
generateKeyPair tested its callback, and a function in the options
position, by the checked-dynamic kind, so a Proxy whose target is a
function threw ERR_INVALID_ARG_TYPE. Node checks typeof, which answers
"function" for such a Proxy. Both tests now ask whether the value is
callable.
Untyped code calling a method on an instance of a compiled JavaScript class
whose own properties live in a property bag materialized the instance's
whole checked view on every call (copying the bag, boxing each field and
attaching the prototype) only to read one member. Hono's Context declares
its methods as arrow-function fields, so every c.header() or c.json() from
middleware rebuilt an 18-property view.
The materializer of such a class gives the view exactly the bag's
string-keyed properties, the declared fields among them with their native
slot values, and the class's prototype. The compiler now emits those parts
as ScrDynTypedBagClassOps (bag, prototype, declared field names, field
getter) and binds them to the class's capsules, and scr_dyn_invoke resolves
a member that is an ordinary data property, own or inherited, from them,
calling it with the capsule as this. Accessors, read-only fields, capsule
prototype links and everything else still build the view.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A class binding may hold a subclass of the class it was declared with.
When the declared class has subclasses, a caught payload of that class is
now tested against the class the binding holds, as for other operands, so
a base-class instance no longer passes a test against a subclass.
Methods of Web objects held in untyped code (Request, Response, Headers,
ReadableStream, its reader, AbortSignal) answered member calls only by
static name, so a property read such as hono's `raw[key]()` or
`typeof req.json` saw undefined. A handle class now lists the methods its
invoke answers; a read returns one shared function per method that calls
invoke on its `this` and raises Node's ERR_INVALID_THIS TypeError (or a
rejected promise for the async operations) on another receiver. The in
operator sees the methods and the modeled properties.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The reflection gate turned on only for an untyped or Error-shaped
defineProperty target, so a helper taking `target: object` (or `{}`,
`Object`, a weak type, or a type parameter) installed a message or name
accessor that typed Error reads then skipped, returning the old slot
value. The gate now turns on for any target an Error may flow into: an
untyped or generic type, a type Error is assignable to, or an
Error-shaped type, alone or in a union or intersection.
e instanceof E where e is a catch binding and E a binding holding a class expression (var E = class extends Error {}) refused with "'instanceof' right-hand sides other than classes declared in the program". The binding holds exactly that class, so the test is the class's caught test (hono's SmartRouter fallback on UnsupportedPathError).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
entries(), keys() and values() on a checked-dynamic Headers value threw 'is not a function'. They now return live native iterators over the sorted header list, re-read on every step with set-cookie values one by one, as Node's Headers iterator does (hono's Context copies response headers this way).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Worklist passes that transform every function (the class-construction dispatch rewriting dyn.classBasePrototype) rebuild statement objects, so a recorded lazy bag store could be a detached copy. When the class gained prototype data later, only the copy was upgraded and the live store kept creating a bare {} bag: inherited methods read as undefined through the property bag (hono's SmartRouter.match once zod was in the program). Upgrades now also reach the stores as they stand in the generated bodies.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An implicit-any package function specialized for a string argument lowered base?.[0] to the element-access refusal: the checker types the receiver any, so only the lowered string reached the string-index path. Hono's mergePath failed at startup.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
s.match(p) and s.search(p) with an untyped pattern now choose at run time, as Node does: a RegExp is used as is (with its lastIndex state), any other value builds new RegExp(value). The checked-dynamic receiver form previously threw 'method calls like path.match on a string are not supported yet' (hono's RegExpRouter matcher).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Materializing the checked view of a JavaScript class instance copies its
property bag through scr_dyn_copy_property_descriptors, which built a key
string and a descriptor object per property and defined each through
scr_dyn_define_property (about 2k instructions per property). Plain objects
on both sides now copy each entry directly with the attributes, value or
accessor pair and own-key order the definition gives; properties the target
already has, non-extensible targets and other receivers keep the general
path.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A package function declared to return its own type parameter, which also
types one of its parameters (<T extends object>(obj: T) => T), hands back
the argument or something standing in for it, and the package may track
that object's identity. Effect's Equal.byReference returns a proxy it
keeps in a WeakSet. The declaration-typed boundary cast such a result to
the argument's type and built a separate native record, so
Equal.equals(a, b) on two by-reference objects compared them by value and
printed true where Node prints false. The result's type comes from the
caller's argument, not from data the package declares, so the projection
no longer casts these calls.
The package re-export coverage test now expects three dynamic statements:
since the boundary, readRows's declared number result keeps its type, so
count - 1 in 7004-package-declared-type-reexports is native arithmetic.