Files
opencode/packages/codemode/interpreter-support.md
T

38 KiB

CodeMode Interpreter Support

This is the checkable support matrix for CodeMode's confined JavaScript interpreter. It tracks the language and standard-library surface that programs can use today, plus concrete gaps that may be implemented later.

  • [x] means the feature is implemented at the scope described here.
  • [ ] means a concrete compatibility gap remains.
  • Checked items do not promise complete ECMAScript edge-case parity; known differences are stated explicitly.
  • Intentional boundaries are not listed as compatibility work.

When behavior changes, update this file and the tests in the same change. The implementation and tests remain the ultimate source of truth. Upstream test262 files run verbatim from test/test262; a failing file is listed in test/test262/skipped.txt and its gap is an unchecked item here (see test/test262/README.md).

Source and execution model

  • JavaScript parsed with the latest syntax accepted by Acorn, then restricted by the interpreter allowlist.
  • Erasable TypeScript syntax, including type annotations, type declarations, assertions, and non-null assertions. TypeScript is transpiled first; the emitted JavaScript must still use the supported subset.
  • Top-level await and return through the program's implicit async-function scope.
  • Explicit return, final top-level expression as a REPL-style result, and null when no value is produced.
  • Program results use JSON-like boundaries, with undefined and non-finite numbers normalized to null. Tool arguments follow JSON serialization semantics before their schema applies (see the tools section). Own __proto__ keys are dropped wherever a host object crosses to the host, so merging tool inputs or results cannot replace a prototype; JSON.stringify still emits the key, like JS, since a string cannot pollute.
  • Values JSON.stringify would flatten to {} cross the host boundary in a useful form instead: a Set as an array, a RegExp as "/source/flags", a URLSearchParams as its query string. A Map still crosses as {}. Functions, generators, promises, and extension handles are rejected with a hint. In-program JSON.stringify keeps JS behavior for all of these.
  • Live Date, RegExp, Map, Set, URL, and URLSearchParams values inside CodeMode.
  • Tool calls through the host-provided tools tree only.
  • The global search(...) built-in: synchronous tool discovery that counts as an admitted tool call and is shadowable by program declarations like other globals.
  • Cooperative timeout, an optional total tool-call limit, output bounding, and unrestricted tool-call concurrency.
  • The timeout fires between interpreter steps, so one built-in is bounded in what it may build: strings up to 2^24 characters (repeat, pad*, concat, join, +, template literals, JSON.stringify), arrays up to 10,000,000 elements (Array(n), length =, Array.from, split, matchAll, concat, flat; below the JS maximum of 2^32 - 1), and 10,000 pending promises at once. Exceeding one throws a RangeError. A single regular expression match can still run long on a pathological pattern; the host regex engine has no interrupt hook.
  • Strict-mode early errors: duplicate parameter names, yield as an identifier, and a trailing comma after a rest parameter are accepted unless the program itself begins with "use strict".
  • Valid JavaScript rejected by TypeScript transpilation before interpretation, such as in inside a destructuring default in a for...of head and Unicode-escaped keywords.

Values and literals

  • null, undefined, booleans, finite and non-finite numbers, and strings.
  • Array literals, including holes and spread from arrays, strings, Maps, Sets, URLSearchParams, custom synchronous iterators, and synchronous generators.
  • Object literals with shorthand, computed string/number keys, and spread following ToObject: data objects and arrays copy own enumerable keys, strings copy index keys, and other values contribute nothing.
  • Template literals with interpolation.
  • Regular-expression literals.
  • NaN and Infinity globals.
  • BigInt literals and in-interpreter BigInt arithmetic; BigInt remains invalid at JSON-like host boundaries.
  • Arbitrary Symbol primitive values and symbol-keyed properties. The confined Symbol.iterator and Symbol.asyncIterator keys are available only for custom iterator protocols.
  • Tagged-template calls.
  • Getter and setter definitions in object literals.

Bindings and destructuring

  • const, let, and var declarations.
  • Object and array destructuring in declarations, parameters, assignment expressions, and for...of bindings.
  • Nested patterns, defaults, elisions, and rest elements.
  • Assignment to identifiers, plain-object fields, non-negative integer array indexes, and writable URL fields.
  • Direct function declarations are hoisted in program and block statement lists.
  • Parameter defaults observe a temporal dead zone for later parameters.
  • var is function-scoped and hoisted: names declared anywhere in a function or program body, including loop heads, blocks, switch cases, and try/catch, read as undefined before their statement runs; redeclaration assigns the one binding; a same-named parameter keeps its argument; closures in parameter defaults see outer names rather than body vars.
  • Predeclare let and const bindings in every lexical scope, including program/block bodies, switch bodies, and loop headers, so reads before initialization and self- or cross-referential initializers observe the JavaScript temporal dead zone.
  • Function declarations are hoisted across all cases of a switch, like any other statement list.
  • Computed object destructuring keys such as const { [field]: value } = record.
  • Object destructuring from arrays, such as const { length } = values.
  • Array binding and assignment destructuring from strings, Maps, Sets, URLSearchParams, custom synchronous iterators, and synchronous generators, including stepwise elisions/rest and IteratorClose on early completion or binding/default failure.
  • Object destructuring from primitives follows ToObject (const { length } = "abc", const {} = 1); non-object sources are rejected.
  • Destructuring reads through the prototype chain like member access: const { constructor } = error and const { slice } = values find the inherited built-in.
  • Member expressions as for...in targets (for (x.y in obj)).
  • IteratorClose during destructuring should throw a TypeError when return() yields a non-object.

Statements and control flow

  • Blocks and empty statements.
  • if/else and conditional expressions.
  • switch, including default clauses and fallthrough.
  • for, while, and do...while.
  • for...of over arrays, strings, Maps, Sets, URLSearchParams, custom synchronous iterators, and confined synchronous generators. Abrupt completion invokes the iterator's optional return().
  • for...in over own keys of plain objects, arrays, strings, and tool references; other values iterate nothing.
  • Unlabeled break and continue.
  • try, catch, optional catch bindings, and finally.
  • throw with arbitrary values.
  • Labeled statements, labeled break, and labeled continue.
  • for await...of over the supported synchronous collections and custom iterator objects using Symbol.asyncIterator or the Symbol.iterator fallback. Each iterator step is sequential, yielded promises and plain values from synchronous collections and sync iterators are awaited before binding, and abrupt loop completion invokes the iterator's optional return(). Custom async iterators control their yielded values, as in JavaScript; only their next() results are awaited. Confined sync and async generators are iterable here.

Functions and callbacks

  • Function declarations, function expressions, and arrow functions.
  • Synchronous and async functions.
  • Closures, recursion, default parameters, rest parameters, and destructured parameters.
  • A call depth limit of 10000: deeper nesting throws a catchable RangeError: Maximum call stack size exceeded at the overflowing call instead of running until the timeout. Callbacks invoked by built-ins count below the call that invoked the built-in, and a resumed await starts from depth 0 as in JS, so long async chains such as recursive pagination are unaffected.
  • Expression and block function bodies.
  • User callbacks for the supported Array, Map, Set, URLSearchParams, sort, string-replacement, and Array.from mapper APIs, with one shared acceptance rule everywhere including promise reactions.
  • Boolean, Number, String, parseInt, parseFloat, isFinite, isNaN, and URI helpers as callbacks.
  • Built-in method references as callbacks, such as values.map(Math.abs), records.map(JSON.stringify), items.forEach(console.log), and Promise.resolve(-1).then(Math.abs). Extra callback arguments a built-in does not consume are ignored, like JS; consumed arguments stay strictly validated (Math.floor still rejects a string). A detached method loses its receiver, as in JS: values.filter("abc".includes) is a TypeError because includes is called without a string this.
  • Constructors work as callbacks with JS call semantics: Error types construct (messages.map(Error)), and new-requiring constructors (Map, Set, URL, URLSearchParams, Promise) throw a TypeError, like JS.
  • Tool references and detached Promise statics are rejected as callbacks with a hint to wrap them in an arrow function.
  • Promise-returning string replacers are coerced synchronously to "[object Promise]", like JavaScript; they are not automatically awaited.
  • The optional thisArg of iteration methods is accepted and ignored: CodeMode functions have no this, so ignoring it matches JS arrow-function semantics exactly.
  • this in non-arrow CodeMode functions and callbacks.
  • User-defined constructor calls.
  • Function.prototype.call, apply, and bind for CodeMode functions.
  • Classes and private fields.
  • Functions are objects: they hold own properties (fn.count = 1), enumerate them, and expose read-only name and length. Names follow JavaScript's NamedEvaluation: declarations, named expressions, bindings, assignments, object literal keys, and destructuring or parameter defaults.
  • Built-in functions are objects too, with name and length (Math.max.length === 2, Array.prototype.push.name === "push").
  • A named function expression's name is not bound inside its own body.
  • Redeclaring a function in the same scope is rejected; in JavaScript the last declaration wins.
  • A line terminator between async function and the function name.
  • Generator and async generator functions evaluate parameter defaults and destructuring at the first next() rather than at the call, so their errors are not thrown synchronously.
  • Synchronous and async generator declarations/expressions, yield, and yield*, including lazy bodies, next(value), return(value), throw(value), exhaustion, promise adoption, async request ordering, try/catch/finally, and sync/async iterator symbols. Async yield* awaits values while adapting a sync iterator but preserves values supplied by a manually implemented async iterator. Generator values are opaque runtime references.
  • Synchronous generators and custom synchronous iterators are consumed stepwise by array/argument spread, array destructuring, Array.from, Map/Set/URLSearchParams construction, Object.fromEntries, Object/Map groupBy, Promise combinators, AggregateError, and Math.sumPrecise. Mapper/grouping callbacks interleave with iterator steps; synchronous consumers preserve yielded promise objects rather than awaiting them. Async generators are rejected by every synchronous consumer.
  • Synchronous iterator acquisition and result validation follow IteratorClose boundaries: consumer errors and intentional early stops invoke return(), acquisition/next() failures do not, and an original consumer error wins over a cleanup failure. Async iterator consumption remains limited to for await...of and async yield*.
  • Portable generator protocol coverage is adapted from pinned Test262 cases for suspended-start, suspended-yield, and completed states; sync and async next/return/throw; finally yields and completion overrides; rejected yielded promises; mixed async request queues; sync and async yield* forwarding; malformed methods/results; and declaration, expression, and object-method forms with closure and parameter behavior. The adapted suite deliberately skips Test262 variants whose observation mechanism requires unsupported getter definitions, proxies, prototype inspection or mutation, non-arrow this, classes, or arbitrary symbols. It also skips tests asserting exact promise reaction-turn counts beyond the observable ordering guarantee documented below. These are interpreter-surface boundaries, not claims that the corresponding full Test262 families pass unchanged.

Expressions and operators

  • Property access with dot or computed bracket syntax.
  • Optional property access and optional calls.
  • Function/tool calls and spread arguments.
  • Sequence expressions (the comma operator).
  • await for CodeMode promises and callable thenables; a plain value passes through unchanged, though every await still defers its continuation one reaction turn.
  • new for Array, Object, Error types, Date, RegExp, Map, Set, URL, URLSearchParams, and Promise. new on any other value throws a catchable TypeError naming the callee: other built-in functions such as Number say new is unsupported and point at the plain call, user-defined functions report the constructor gap below, and non-callable values are not constructors.
  • Arithmetic operators: +, -, *, /, %, and **.
  • Equality and ordering: ==, !=, ===, !==, <, <=, >, and >=.
  • Bitwise operators: &, |, ^, ~, <<, >>, and >>>.
  • Logical operators: &&, ||, ??, and !, with short-circuiting.
  • Unary +, unary -, void, typeof, instanceof (through the constructor's prototype, so [] instanceof Object holds), and in across the prototype chain.
  • Prefix and postfix ++ and --.
  • Plain, arithmetic, bitwise, and logical assignment operators.
  • Property deletion on plain data objects and arrays, including computed and optional forms; deleting an array index creates a hole without changing its length. Deleting a non-configurable property (length, lastIndex) or assigning a read-only one (Math.PI, fn.name) throws a TypeError, as in strict mode.
  • Operators, switch discriminants, template interpolation, and coercion helpers such as String and isNaN applied to functions and namespaces; JavaScript coerces them, the interpreter rejects non-data operands.
  • ToPrimitive on object operands: operators, Error(message), Date arguments, and parseInt radix should call valueOf/toString in spec order and surface their throws.
  • Property keys follow ToPropertyKey: x[null], x[true], and objects (via toString) become string keys; only strings and numbers are accepted.

Promises and tools

  • Tool calls start eagerly and return supervised, run-once CodeMode promises.
  • Direct await, repeated awaits, and recursive thenable assimilation when a promise or thenable is returned from a function/program.
  • Promise.resolve and Promise.reject.
  • Promise.all, Promise.allSettled, Promise.race, and Promise.any over finite collections, custom synchronous iterators, and synchronous generators containing promises and plain values.
  • Promise.all preserves result order and rejects on the first observed failure without cancelling siblings.
  • Promise.allSettled returns plain fulfilled/rejected outcome records.
  • Promise.race settles from the first result without cancelling losers at settlement time.
  • Real promise values from Promise.all, Promise.allSettled, and Promise.race; separately constructed combinator batches overlap as in normal JavaScript.
  • Promise chaining with .then, .catch, and .finally: handlers run deferred in attach order, returned promises are adopted, handler throws reject the derived promise, .finally preserves the original settlement unless its cleanup fails, and direct self-resolution rejects with a TypeError.
  • Every await (including of plain values and already-settled promises) defers its continuation one reaction turn, so concurrent async functions interleave at await points as in JavaScript.
  • Combinators settle one reaction turn after their deciding member (V8-observable ordering): reactions already attached to members run first, and an aggregate cannot beat a plain value settling in the same turn into a Promise.race. Exact microtask-count parity beyond this observable ordering is not a documented guarantee.
  • All still-pending work (race losers, fail-fast Promise.all stragglers, and un-awaited calls alike) is interrupted when the program returns; rejections that settled un-awaited become Success.warnings diagnostics. A combinator abandoned inside its final settlement turn counts as pending and is interrupted without a warning.
  • try/catch can handle awaited tool and promise failures.
  • Promise.any: first fulfillment wins; all-rejected rejects with an AggregateError whose errors array holds the catch-normalized reasons in input order, and empty input rejects with an empty AggregateError.
  • new Promise((resolve, reject) => ...): the executor runs synchronously and receives first-class resolve/reject callables that settle the promise exactly once (they may escape the executor and settle later); an executor throw rejects unless the promise already settled, resolving with a promise or callable thenable adopts it, and resolving with the promise itself rejects with a TypeError. Resolver callables work anywhere callbacks are accepted, including .then/.catch handlers and collection callbacks, but remain opaque references that cannot cross the data boundary.
  • Recursive assimilation of objects with an own callable then field across Promise.resolve, combinators, constructors, reactions, finally, await, and async returns. Thenable methods run deferred, receive first-call-wins resolve/reject functions, and ignore throws after settlement. Inherited/accessor then fields and a JavaScript this receiver remain outside the supported object/function model.
  • Dotted tool names are canonicalized into namespace paths; a path can be both callable and a namespace, and the last tool supplied for a canonical path wins.
  • Tool path segments may be named constructor, prototype, or __proto__ because paths use inert Map keys.
  • Outbound tool arguments follow JSON serialization semantics, like JSON.stringify: object properties with undefined values are dropped, undefined array elements and non-finite numbers become null, and sparse arrays densify. Tools never receive undefined inside their input object, though a bare tools.t(undefined) argument still reaches schema decoding as undefined. Program results keep the stricter normalization where every undefined becomes null.
  • Tokenize and case-fold non-ASCII tool paths, descriptions, and queries for tool search.

Objects and properties

  • Own-field reads and writes on plain data objects.
  • new dispatches on the evaluated constructor value, so aliases (const D = Date; new D()), constructors held in objects, and constructors passed as arguments work, while a shadowed name (const Date = 5; new Date()) does not construct.
  • Object() and new Object() return {} for nullish arguments and pass objects through unchanged; primitive wrapper objects (Object(1)) are rejected explicitly.
  • Computed property names and object spread.
  • Object.keys, Object.values, Object.entries, Object.hasOwn, Object.assign, and Object.fromEntries, with synchronous iterator support for fromEntries. Sources follow ToObject: strings enumerate by index, other primitives and wrappers contribute nothing, and null/undefined throw. Object.assign accepts array targets for index keys only; a primitive target is a TypeError rather than a boxed object.
  • Object.keys over arrays and tool references.
  • Object identity is preserved by in-CodeMode Object helpers.
  • Every value has a real prototype chain built fresh for each run: Object.prototype, Array.prototype, String.prototype, Error.prototype → TypeError.prototype, and so on hold the built-in methods as non-enumerable properties, and each constructor's prototype points at it ([].constructor === Array, Object.getPrototypeOf is not exposed). Programs may read and even overwrite these prototypes; the change is confined to that run. __proto__ is an ordinary own data key, so o.__proto__ = x never changes the chain, and Object.groupBy results have no prototype at all, as in JS.
  • Circular references are rejected when created (o.self = o, array.push(array)), not at serialization as in JS.
  • Object.is for supported data values.
  • Object.groupBy over finite collections and custom synchronous iterators/generators, with string-key coercion and plain-object results.
  • Object.prototype methods on values: toString ("[object Array]"), toLocaleString, valueOf, hasOwnProperty, isPrototypeOf, and propertyIsEnumerable.

Arrays

  • The Array constructor with or without new: Array(a, b) collects arguments and Array(n) creates a sparse array of that length; invalid lengths throw RangeError. Iteration, spread, join, and JSON handle holes like JavaScript, and host results normalize holes to null.
  • Static methods: Array.isArray, Array.of, and Array.from, including the Array.from mapper form with (value, index) arguments and stepwise synchronous iterator consumption.
  • Iteration/transformation: map, filter, flatMap, and forEach.
  • Searching/tests: find, findIndex, findLast, findLastIndex, some, every, includes, indexOf, and lastIndexOf.
  • Aggregation: reduce and reduceRight.
  • Ordering: sort, toSorted, reverse, and toReversed.
  • Access/copying: at, slice, concat, flat, with, and join.
  • Mutation: push, pop, shift, unshift, splice, fill, and copyWithin.
  • Materialized iteration helpers: keys, values, and entries return arrays rather than iterators.
  • length, numeric indexing, index assignment, spread, and for...of.
  • The thisArg argument of Array.from is accepted and ignored, like JS arrows.
  • Array.prototype.toSpliced.
  • Canonical array/string index parsing: keys such as "01" are ordinary properties rather than aliases of index 1.
  • Array.prototype.sort preserves trailing holes, while toSorted densifies holes into undefined elements, like JavaScript.
  • Assigning length to truncate or extend an array; invalid lengths throw RangeError.
  • Non-index own properties on arrays (arr.foo = 1, arr.constructor = null). They are excluded from the JSON form, like JSON.stringify.
  • Argument coercion for indexOf, lastIndexOf, includes, fill, flat, copyWithin, and the join separator: JavaScript applies ToIntegerOrInfinity/ToString (including valueOf, strings, and undefined), the interpreter requires numbers and strings; includes()/indexOf() with no argument should search for undefined.
  • Iterator objects from keys, values, and entries with a live next().

Strings

  • Case/normalization: toLowerCase, toUpperCase, normalize.
  • Trimming: trim, trimStart, and trimEnd, plus the Annex B trimLeft and trimRight aliases.
  • Searching/tests: includes, startsWith, endsWith, indexOf, lastIndexOf, and search.
  • Slicing/access: slice, substring, Annex B substr, at, charAt, charCodeAt, and codePointAt.
  • Construction/transformation: split, concat, repeat, padStart, padEnd, replace, and replaceAll.
  • Regular-expression integration: match, materialized matchAll, replace, replaceAll, split, and search.
  • localeCompare; locale and options arguments are currently ignored.
  • isWellFormed and toWellFormed.
  • toString, length, numeric indexing, spread, and for...of by Unicode code point.
  • Static String.fromCharCode and String.fromCodePoint.
  • Native argument coercion for supported String methods; for example, includes(1) and slice("1") coerce like native JS, split(undefined) returns the whole string, and includes/startsWith/endsWith reject regular expressions with a native-style TypeError. Opaque runtime references still reject as data errors, and repeat still requires a finite non-negative count.
  • Native no-argument parity for match(), matchAll(), and search(); all behave as an empty pattern. Present arguments must still be a regular expression or string pattern.
  • String.raw.
  • match, search, and split accept any value and coerce it (objects via toString), like JavaScript.

Numbers and Math

  • Coercion functions: Number, parseInt, and parseFloat.
  • Number predicates/parsers: Number.isInteger, Number.isFinite, Number.isNaN, Number.isSafeInteger, Number.parseInt, and Number.parseFloat.
  • Number formatting: toFixed, toPrecision, toExponential, toString, and valueOf.
  • Number constants: MAX_SAFE_INTEGER, MIN_SAFE_INTEGER, MAX_VALUE, MIN_VALUE, EPSILON, NaN, POSITIVE_INFINITY, and NEGATIVE_INFINITY.
  • Math constants: PI, E, LN2, LN10, LOG2E, LOG10E, SQRT2, and SQRT1_2.
  • Math methods: random, max, min, abs, acos, acosh, asin, asinh, atan, atan2, atanh, floor, ceil, round, trunc, sign, sqrt, cbrt, pow, hypot, cos, cosh, sin, sinh, tan, tanh, log, log2, log10, log1p, exp, expm1, f16round, fround, clz32, and imul.
  • Native zero-argument behavior for Number() and String(): they produce 0 and "", while Number(undefined) stays NaN and String(undefined) stays "undefined".
  • ++ and -- use CodeMode numeric coercion (numeric strings increment, plain data objects become NaN, Dates use their epoch time) and reject opaque runtime references as data errors.
  • Unknown static members on global namespaces and on Number/String/the coercion functions read as undefined for feature detection. Calling any undefined value reports a native-style TypeError naming the callee, for example Math.sum is not a function. Unknown Promise statics keep their descriptive error.
  • Math.sumPrecise over finite collections and custom synchronous iterators/generators, rejecting non-number elements without coercion.
  • Global coercing isFinite and isNaN; opaque runtime references reject as data errors, like Number(...).

JSON and console

  • JSON.parse and JSON.stringify for supported data objects.
  • Numeric/string indentation for JSON.stringify.
  • JSON.parse reviver callbacks, including postorder traversal, deletion through undefined, and root replacement. Revivers receive (key, value) but no this holder because CodeMode functions intentionally have no this.
  • JSON.stringify function and array replacers. Function replacers receive (key, value) in preorder, including the root, but no this holder. Array replacers preserve requested property order, deduplicate names, coerce number primitives, and ignore non-string/non-number entries. Primitive wrapper entries remain unsupported.
  • Captured console.log, console.info, console.debug, console.warn, and console.error.
  • Captured console.dir and console.table.

Date

  • Date.now, Date.parse, and Date.UTC.
  • new Date() from the current time, epoch milliseconds, a date string, another Date, or local components.
  • Date() without new returns the current time as a string, like JS, but in deterministic ISO format rather than the host's locale/timezone string.
  • getTime, valueOf, toISOString, toJSON, and deterministic ISO toString.
  • Local getters: getFullYear, getMonth, getDate, getDay, getHours, getMinutes, getSeconds, and getMilliseconds.
  • UTC getters: getUTCFullYear, getUTCMonth, getUTCDate, getUTCDay, getUTCHours, getUTCMinutes, getUTCSeconds, and getUTCMilliseconds.
  • getTimezoneOffset, arithmetic, relational comparison, and instanceof Date.
  • Date values serialize to ISO strings; invalid dates serialize to null.
  • Local and UTC Date setters, including native argument coercion, mutation, rollover, invalid-Date recovery, and TimeClip behavior.
  • Date.prototype.toUTCString and its toGMTString alias.
  • toDateString and toTimeString in the host's local timezone.
  • Native one-argument Date coercion for supported values, including booleans, null, arrays, and plain objects.
  • Date setters and multi-argument construction coerce object arguments through valueOf/toString and surface their throws.
  • Native Date loose-equality and default primitive-coercion semantics, using CodeMode's deterministic ISO string representation for the string primitive.
  • Native RangeError branding for invalid toISOString() calls.

Regular expressions

  • Literal and RegExp(pattern, flags) construction, with or without new.
  • test, exec, and toString.
  • Readable source, flags, lastIndex, hasIndices, global, ignoreCase, multiline, sticky, unicode, unicodeSets, and dotAll.
  • Captures, named groups, match .index and .input, and stateful global matching.
  • Integration with supported String methods, including function replacers.
  • Writable lastIndex.
  • Match indices metadata for the d flag, including named groups on exec, match, and matchAll results.
  • RegExp.escape.

Map and Set

  • Static Map.groupBy over finite collections and custom synchronous iterators/generators, preserving key identity.
  • new Map() from synchronous iterables of entries.
  • Map get, set, has, delete, clear, size, and forEach.
  • new Set() from synchronous iterables.
  • Set add, has, delete, clear, size, and forEach.
  • Materialized keys, values, and entries arrays for Map and Set.
  • Spread, for...of, Array.from, and Object.fromEntries integration.
  • Map and Set values serialize to {} at host/JSON boundaries.
  • Set composition and relation methods: union, intersection, difference, symmetricDifference, isSubsetOf, isSupersetOf, and isDisjointFrom, including supported Set-like operands.

URL and URI helpers

  • encodeURI, encodeURIComponent, decodeURI, and decodeURIComponent.
  • new URL(input, base), URL.canParse, and URL.parse.
  • URL toString, toJSON, and linked searchParams.
  • Readable URL fields: href, origin, protocol, username, password, host, hostname, port, pathname, search, and hash.
  • Writable URL fields except origin.
  • new URLSearchParams() from query strings, data objects, synchronous iterables of pairs, and URLSearchParams.
  • URLSearchParams append, delete, get, getAll, has, set, sort, forEach, keys, values, entries, toString, and size.
  • URL values serialize to their href; URLSearchParams serialize to {}.

Web platform helpers

  • atob and btoa with forgiving-base64 decoding and WebIDL string conversion; invalid input throws a TypeError, since there is no DOMException.
  • crypto.randomUUID().
  • crypto.getRandomValues and crypto.subtle, TextEncoder/TextDecoder, and Blob: these need a binary value type, which the JSON-like data model does not have yet.

Extensions

Host classes and functions a host opts in through Extension.make({ name, globals }) and CodeMode.make({ extensions }). Nothing is exposed unless a host provides it; extension calls are not tool calls.

  • Each global is a class or a function, exposed as-is: constructors with new, prototype methods, accessors, and statics (including through an exposed subclass, so new this() works), plus inheritance up to the nearest exposed ancestor. A global that shadows a built-in or another extension throws at make.
  • Instances of exposed classes stay on the host; the program holds a handle whose only members are the class's. The same host instance is always the same handle within a run, so identity and instanceof hold. Handles cannot cross the data boundary: returning, stringifying, throwing, or passing one to a tool fails.
  • Every value crossing in either direction is converted, never shared: plain objects and arrays are copied, Date, RegExp, URL, URLSearchParams, Map, and Set become fresh copies with their contents converted, errors cross as errors with their name and message, and a __proto__ key is dropped. Functions, generators, un-awaited promises, and symbols cannot be passed in; an instance of an unexposed class, a symbol, or a BigInt cannot come out.
  • A host Promise becomes a program promise. Whatever host code returns, resolves, throws, or rejects with crosses the same way, so catch (e) receives a copy of the thrown value (an Error of the matching type, or plain data). A getter must be synchronous.
  • A prototype member runs only with a handle of its own class as this; a detached call, a plain object, or a handle of another class throws TypeError: Illegal invocation. Program edits to an exposed prototype affect that run only. Data properties on a class or prototype are not exposed, since a program write would change the host class itself; expose one through an accessor.
  • Program functions as arguments to extension code (callbacks such as forEach).
  • Binary values (Uint8Array, ArrayBuffer) at the extension boundary; needs the binary value type above.

Errors and diagnostics

  • Error, TypeError, RangeError, SyntaxError, ReferenceError, EvalError, and URIError, callable with or without new.
  • AggregateError with the (errors, message?) signature and an own errors array, constructed directly or by an all-rejected Promise.any; direct construction accepts custom synchronous iterators and generators.
  • Error name/message, error inheritance through instanceof, and plain-data serialization. message is an own non-enumerable property and name is inherited, as in JS, so Object.keys(err) is [] while the host still receives { name, message }. Errors have no stack; the diagnostic carries the source location instead.
  • instanceof against any constructor with a prototype, including every built-in and Function.
  • Catchable user throws, runtime failures raised during interpreted evaluation, awaited tool failures, and awaited tool-call-limit failures; parse/compile failures, cooperative timeout, and output bounding remain outside program catch.
  • Source locations on unsupported-syntax diagnostics for JavaScript-shaped input; TypeScript transpilation may shift them. The diagnostic names the rejected node type and attaches a short orientation to the supported subset; this matrix is the full reference.
  • Model-visible host failure messages and underlying causes, including output-validation errors.
  • Caught errors do not distinguish user throws, interpreter failures, and tool failures; a program sees one Error-shaped value with name and message in catch, rejection handlers, and Promise.allSettled reasons. This is deliberate: the program should handle a failure the same way regardless of where it originated.
  • Failures raised by the interpreter are TypeErrors unless JavaScript names them otherwise (RangeError, ReferenceError, SyntaxError, URIError), so e instanceof TypeError and e.constructor === TypeError hold. Unsupported syntax reached at runtime is a SyntaxError; awaited tool failures stay plain Error. Host errors escaping a built-in ((1).toFixed(200)) become the same-named program error at the call. A failure raised inside a promise a built-in created (Promise.all(1), Promise.race([]), a resolution cycle) is located at the call that created the promise.
  • One failure is one error object: every catch, rejection handler, and allSettled reason for the same failure sees the identical value, so a === b holds after awaiting the same rejected promise twice.
  • Rethrowing an interpreter failure keeps its diagnostic: catch (e) { throw e } still reports the original kind and source location. Uncaught errors report as name: message whoever raised them, as Error.prototype.toString would (TypeError: Cannot read properties of null (reading 'foo')., TypeError: bad input); other thrown values report as Uncaught: <value>.