Something went wrong. Try again.
opencode v2 mirror
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047/* * Portions adapted from Test262 at revision 250f204f23a9249ff204be2baec29600faae7b75: * - test/built-ins/Date/value-to-primitive-result-non-string-prim.js * - test/built-ins/Date/value-to-primitive-result-string.js * - test/built-ins/Date/prototype/toUTCString/format.js * - test/built-ins/Date/prototype/toUTCString/invalid-date.js * - test/built-ins/RegExp/prototype/exec/S15.10.6.2_A4_T8.js * * CodeMode does not support Symbol.toPrimitive, so the Date-constructor cases exercise the same primitive-result * handling through supported own valueOf and toString functions. * * Copyright (C) 2016 the V8 project authors. All rights reserved. * Copyright (C) 2017 the V8 project authors. All rights reserved. * Copyright 2009 the Sputnik authors. All rights reserved. * Test262 portions are governed by the BSD license in LICENSE.test262. */import { describe, expect, test } from "bun:test"import { Effect, Schema } from "effect"import { CodeMode, Tool } from "../src/index.js"
// Standard-library value types: Date, RegExp, Map, Set. Programs use them as ordinary JS;// intra-CodeMode checkpoints (Object.* helpers, spread, coercion inputs) preserve the live// values, while at the host boundary (final result, tool arguments, JSON.stringify) they// serialize exactly as JSON.stringify would: Date -> ISO string (invalid -> null),// URL -> href, and RegExp/Map/Set/URLSearchParams -> {}.const run = (code: string) => Effect.runPromise(CodeMode.execute({ code, tools: {} }))const value = async (code: string) => { const result = await run(code) if (!result.ok) throw new Error(`expected success, got ${result.error.kind}: ${result.error.message}`) return result.value}const error = async (code: string) => { const result = await run(code) if (result.ok) throw new Error(`expected failure, got value ${JSON.stringify(result.value)}`) return result.error}
describe("Number and Math", () => { test("Math.random returns a number in [0, 1)", async () => { expect(await value(`const n = Math.random(); return typeof n === "number" && n >= 0 && n < 1`)).toBe(true) })
test("Number exposes native non-finite constants", async () => { expect( await value( `return [Number.isNaN(Number.NaN), Number.POSITIVE_INFINITY === Infinity, Number.NEGATIVE_INFINITY === -Infinity]`, ), ).toEqual([true, true, true]) })
test("Number valueOf returns its primitive receiver", async () => { expect(await value(`return (42).valueOf()`)).toBe(42) })
test("Number valueOf does not enable boxed numbers", async () => { expect((await error(`return new Number(42)`)).kind).toBe("UnsupportedSyntax") })})
describe("Date", () => { test("Date.now() returns a number", async () => { expect(await value(`return typeof Date.now()`)).toBe("number") })
test("epoch construction and ISO rendering", async () => { expect(await value(`return new Date(0).toISOString()`)).toBe("1970-01-01T00:00:00.000Z") })
test("string parsing round-trips", async () => { expect(await value(`return new Date("2024-01-02T03:04:05.000Z").getTime()`)).toBe(1704164645000) expect(await value(`return Date.parse("2024-01-02T03:04:05.000Z")`)).toBe(1704164645000) })
test("one-argument construction coerces supported values like JavaScript", async () => { expect( await value(`return [new Date(true).getTime(), new Date(false).getTime(), new Date(null).getTime()]`), ).toEqual([1, 0, 0]) expect(await value(`return Number.isNaN(new Date(undefined).getTime())`)).toBe(true) expect(await value(`return Number.isNaN(new Date([]).getTime())`)).toBe(true) expect(await value(`return new Date(["1970-01-01T00:00:00.000Z"]).getTime()`)).toBe(0) expect(await value(`return Number.isNaN(new Date({}).getTime())`)).toBe(true) })
test("one-argument construction uses valueOf then toString for objects", async () => { expect( await value(` const calls = [] const number = { valueOf: () => 8 } const text = { valueOf: () => { calls.push("valueOf"); return {} }, toString: () => { calls.push("toString"); return "2016-06-05T18:40:00.000Z" }, } return [new Date(number).getTime(), new Date(text).getTime(), calls] `), ).toEqual([8, 1465152000000, ["valueOf", "toString"]])
expect( await value(` const values = [ { valueOf: () => undefined }, { valueOf: () => true }, { valueOf: () => false }, { valueOf: () => null }, ] return values.map((item) => new Date(item).getTime()) `), ).toEqual([null, 1, 0, 0])
expect( await value(` try { new Date({ valueOf: () => ({}), toString: () => ({}) }) } catch (error) { return error.name } `), ).toBe("TypeError") })
test("date arithmetic and comparison use the time value", async () => { expect(await value(`const a = new Date(1000); const b = new Date(3000); return b - a`)).toBe(2000) expect(await value(`const a = new Date(1000); const b = new Date(3000); return a < b`)).toBe(true) expect(await value(`return +new Date(42)`)).toBe(42) })
test("UTC getters read calendar components", async () => { expect( await value( `const d = new Date("2024-03-05T06:07:08.009Z"); return [d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()]`, ), ).toEqual([2024, 2, 5, 6, 7, 8, 9]) })
test("invalid dates yield NaN times, guardable in-CodeMode", async () => { expect(await value(`return Number.isNaN(new Date("garbage").getTime())`)).toBe(true) expect(await value(`return new Date("garbage").toJSON()`)).toBeNull() })
test("toISOString on an invalid date throws RangeError", async () => { expect(await value(`try { new Date("garbage").toISOString() } catch (error) { return error.name }`)).toBe( "RangeError", ) })
test("template interpolation renders the ISO form", async () => { expect(await value("return `at ${new Date(0)}`")).toBe("at 1970-01-01T00:00:00.000Z") })
test("dates serialize to ISO strings at the boundary, direct and nested", async () => { expect(await value(`return new Date(0)`)).toBe("1970-01-01T00:00:00.000Z") expect(await value(`return { when: new Date(0), tags: [new Date(1000)] }`)).toEqual({ when: "1970-01-01T00:00:00.000Z", tags: ["1970-01-01T00:00:01.000Z"], }) expect(await value(`return JSON.stringify({ d: new Date(0) })`)).toBe('{"d":"1970-01-01T00:00:00.000Z"}') })
test("coercions: Number is the time, String is ISO, Boolean is true", async () => { expect(await value(`return Number(new Date(5))`)).toBe(5) expect(await value(`return String(new Date(0))`)).toBe("1970-01-01T00:00:00.000Z") expect(await value(`return Boolean(new Date(0))`)).toBe(true) })
test("sorting dates with a numeric comparator", async () => { expect( await value(` const dates = [new Date(3000), new Date(1000), new Date(2000)] return dates.sort((a, b) => a - b).map((d) => d.getTime()) `), ).toEqual([1000, 2000, 3000]) })
test("new Date(year, month, day) accepts component form", async () => { expect(await value(`const d = new Date(2024, 0, 2); return [d.getFullYear(), d.getMonth(), d.getDate()]`)).toEqual([ 2024, 0, 2, ]) })
test("typeof and unknown properties are forgiving", async () => { expect(await value(`return typeof new Date(0)`)).toBe("object") expect(await value(`return new Date(0).nope === undefined`)).toBe(true) })
test("toUTCString and toGMTString use the native UTC format", async () => { expect( await value(` const date = new Date(0) return [ date.toUTCString(), date.toGMTString(), new Date(NaN).toUTCString(), new Date("0020-01-01T00:00:00Z").toUTCString(), ] `), ).toEqual([ "Thu, 01 Jan 1970 00:00:00 GMT", "Thu, 01 Jan 1970 00:00:00 GMT", "Invalid Date", "Wed, 01 Jan 0020 00:00:00 GMT", ]) })})
describe("RegExp", () => { test("literal test", async () => { expect(await value(`return /ab+c/.test("xabbbc")`)).toBe(true) expect(await value(`return /ab+c/.test("nope")`)).toBe(false) })
test("exec exposes captures and index", async () => { expect(await value(`const m = /a(b+)/.exec("xxabbc"); return { full: m[0], group: m[1], index: m.index }`)).toEqual( { full: "abb", group: "bb", index: 2, }, ) expect(await value(`return /a/.exec("zzz")`)).toBeNull() })
test("named groups read through", async () => { expect( await value(`const m = /(?<word>[a-z]+)-(?<num>\\d+)/.exec("id ab-42"); return m.groups.word + m.groups.num`), ).toBe("ab42") })
test("global exec advances lastIndex across calls", async () => { expect( await value(` const r = /\\d+/g const first = r.exec("a1b22c") const second = r.exec("a1b22c") return [first[0], second[0]] `), ).toEqual(["1", "22"]) })
test("lastIndex is writable and exec coerces its stored value", async () => { expect( await value(` const pattern = /(?:ab|cd)\\d?/g pattern.lastIndex = "12" const stored = [pattern.lastIndex, typeof pattern.lastIndex] const match = pattern.exec("aacd2233ab12nm444ab42") pattern.lastIndex = 0 return [stored, match[0], match.index, pattern.lastIndex, delete pattern.lastIndex] `), ).toEqual([["12", "string"], "ab4", 17, 0, false]) })
test("exec coerces CodeMode data objects assigned to lastIndex", async () => { expect( await value(` const pattern = /a/g pattern.lastIndex = {} const stored = pattern.lastIndex const match = pattern.exec("ba") pattern.lastIndex = 10 const missed = pattern.exec("a") return [stored, match.index, pattern.lastIndex, missed] `), ).toEqual([{}, 1, 0, null]) })
test("non-global exec and test coerce and preserve lastIndex", async () => { expect( await value(` const execPattern = /a/ const execIndex = {} execPattern.lastIndex = execIndex const match = execPattern.exec("ba")
const testPattern = /a/ const testIndex = {} testPattern.lastIndex = testIndex const matched = testPattern.test("ba")
return [match.index, execPattern.lastIndex === execIndex, matched, testPattern.lastIndex === testIndex] `), ).toEqual([1, true, true, true]) })
test("an unmatched string pattern returns null", async () => { expect(await value(`return "abc".match(/\\d/)`)).toBeNull() })
test("matchAll materializes match arrays with captures", async () => { expect(await value(`return "a1b22".matchAll(/(\\d+)/g).map((m) => m[1])`)).toEqual(["1", "22"]) })
test("function replacers receive captures, offsets, input, and named groups", async () => { expect( await value(` const seen = [] const output = "a1b22".replace(/(\\d)(\\d)?/g, (match, first, second, offset, input) => { seen.push([match, first, second === undefined, offset, input]) return Number(match) * 2 }) return { output, seen } `), ).toEqual({ output: "a2b44", seen: [ ["1", "1", true, 1, "a1b22"], ["22", "2", false, 3, "a1b22"], ], }) expect( await value(` return "red-blue".replace( /(?<left>[a-z]+)-(?<right>[a-z]+)/, (match, left, right, offset, input, groups) => groups.right + ":" + groups.left, ) `), ).toBe("blue:red") })
test("function replacers support string searches, zero-length matches, and result coercion", async () => { expect(await value(`return "banana".replace("na", (match, offset, input) => "[" + offset + "]")`)).toBe("ba[2]na") expect(await value(`return "ab".replaceAll("", (match, offset) => offset)`)).toBe("0a1b2") expect(await value(`return "😀".replaceAll(/(?:)/gu, (match, offset) => "[" + offset + "]")`)).toBe("[0]😀[2]") expect( await value(`return "123".replace(/\\d/g, (match) => match === "1" ? 7 : match === "2" ? null : { n: 3 })`), ).toBe("7null[object Object]") })
test("promise-returning string replacers are coerced synchronously", async () => { const decorate = Tool.make({ description: "Decorate a string", input: Schema.String, output: Schema.String, execute: (input) => Effect.succeed(`[${input}]`), }) const result = await Effect.runPromise( CodeMode.execute({ tools: { host: { decorate } }, code: `return "a1b22".replace(/\\d+/g, async (match) => await tools.host.decorate(match))`, }), ) expect(result.ok && result.value).toBe("a[object Promise]b[object Promise]")
const missingAwait = await Effect.runPromise( CodeMode.execute({ tools: { host: { decorate } }, code: `return "a1".replace(/\\d/, (match) => tools.host.decorate(match))`, }), ) expect(missingAwait.ok && missingAwait.value).toBe("a[object Promise]") })
test("replaceAll without the g flag is a catchable error", async () => { expect(await value(`try { "a".replaceAll(/a/, "b"); return "no" } catch { return "caught" }`)).toBe("caught") })
test("new RegExp constructs from strings; invalid patterns are catchable", async () => { expect(await value(`return new RegExp("a+", "i").test("AAA")`)).toBe(true) expect(await value(`try { new RegExp("("); return "no" } catch { return "caught" }`)).toBe("caught") expect(await value(`return [/a/ instanceof RegExp, /a/.source]`)).toEqual([true, "a"]) })
test("invalid patterns fail with actionable messages", async () => { const fromString = await error(`return "abc".match("(")`) expect(fromString.message).toContain('String.match received the string "("') expect(fromString.message).toContain("escape them with a backslash")
const fromConstructor = await error(`return new RegExp("(")`) expect(fromConstructor.message).toContain('new RegExp(...) received "("') expect(fromConstructor.message).toContain("escape them with a backslash")
const fromFlags = await error(`return new RegExp("a", "xz")`) expect(fromFlags.message).toContain('invalid flags "xz"') expect(fromFlags.message).toContain("Valid flags are") })
test("missing g-flag errors say how to fix the call", async () => { expect((await error(`return "aa".replaceAll(/a/, "b")`)).message).toContain("write /a/g, or use String.replace") expect((await error(`return "aa".matchAll(/a/)`)).message).toContain("write /a/g, or use String.match") })
test("a non-pattern argument names the expected shapes", async () => { const err = await error(`return "abc".match(42)`) expect(err.message).toContain("expects a regular expression") expect(err.message).toContain("not number") })
test("source and flags properties read through", async () => { expect(await value(`const r = /ab/gi; return { source: r.source, flags: r.flags, global: r.global }`)).toEqual({ source: "ab", flags: "gi", global: true, }) })
test("regexes serialize to {} at the boundary, like JSON", async () => { expect(await value(`return /a/`)).toEqual({}) expect(await value(`return JSON.stringify({ r: /a/g })`)).toBe('{"r":{}}') })
test("template interpolation renders the literal form", async () => { expect(await value("return `${/ab/g}`")).toBe("/ab/g") })})
describe("URL and URI helpers", () => { test("encodes and decodes complete URIs and URI components", async () => { expect( await value(` return [ encodeURI("https://example.test/a b?q=a/b"), encodeURIComponent("a b/c?"), decodeURI("https://example.test/a%20b?q=a/b"), decodeURIComponent("a%20b%2Fc%3F"), ["a b", "c/d"].map(encodeURIComponent), ] `), ).toEqual([ "https://example.test/a%20b?q=a/b", "a%20b%2Fc%3F", "https://example.test/a b?q=a/b", "a b/c?", ["a%20b", "c%2Fd"], ]) expect( await value(`try { decodeURIComponent("%zz"); return false } catch (error) { return error instanceof URIError }`), ).toBe(true) })
test("resolves and mutates URLs with linked search parameters", async () => { expect( await value(` const url = new URL("../users?id=old#top", "https://user:pass@example.com:8443/api/v1/") url.pathname = "/items/a b" url.searchParams.set("id", "a b") url.searchParams.append("tag", "x/y") url.hash = "part 1" return { href: url.href, origin: url.origin, host: url.host, pathname: url.pathname, search: url.search, id: url.searchParams.get("id"), string: String(url), json: url.toJSON(), instances: [ url instanceof URL, url.searchParams instanceof URLSearchParams, url.searchParams === url.searchParams, ], } `), ).toEqual({ href: "https://user:pass@example.com:8443/items/a%20b?id=a+b&tag=x%2Fy#part%201", origin: "https://example.com:8443", host: "example.com:8443", pathname: "/items/a%20b", search: "?id=a+b&tag=x%2Fy", id: "a b", string: "https://user:pass@example.com:8443/items/a%20b?id=a+b&tag=x%2Fy#part%201", json: "https://user:pass@example.com:8443/items/a%20b?id=a+b&tag=x%2Fy#part%201", instances: [true, true, true], }) })
test("URLSearchParams supports records, pairs, mutation, callbacks, and materialization", async () => { expect( await value(` const params = new URLSearchParams([["tag", "b"], ["tag", "a"], ["q", "a b"]]) const seen = [] params.forEach((value, key) => seen.push(key + "=" + value)) params.delete("tag", "b") params.append("tag", "c") params.sort() return { text: params.toString(), size: params.size, tags: params.getAll("tag"), has: params.has("tag", "c"), entries: Array.from(params), object: Object.fromEntries(params), record: new URLSearchParams({ page: 2, filter: "open" }).toString(), seen, } `), ).toEqual({ text: "q=a+b&tag=a&tag=c", size: 3, tags: ["a", "c"], has: true, entries: [ ["q", "a b"], ["tag", "a"], ["tag", "c"], ], object: { q: "a b", tag: "c" }, record: "page=2&filter=open", seen: ["tag=b", "tag=a", "q=a b"], }) })
test("URL parsing failures are catchable and values use native JSON forms", async () => { expect( await value(` const parsed = URL.parse("/users", "https://example.test/api/") let invalidIsTypeError = false try { new URL("not relative without a base") } catch (error) { invalidIsTypeError = error instanceof TypeError } return { canParse: URL.canParse("/users", "https://example.test/api/"), cannotParse: URL.canParse("not relative without a base"), parsed: parsed.href, invalidIsTypeError, boundary: [new URL("https://example.test/a"), new URLSearchParams("q=one")], json: JSON.stringify({ url: new URL("https://example.test/a"), params: new URLSearchParams("q=one") }), } `), ).toEqual({ canParse: true, cannotParse: false, parsed: "https://example.test/users", invalidIsTypeError: true, boundary: ["https://example.test/a", {}], json: '{"url":"https://example.test/a","params":{}}', }) })
test("distinguishes omitted URL arguments from explicit undefined", async () => { expect( await value(` function throwsTypeError(run) { try { run(); return false } catch (error) { return error instanceof TypeError } } const params = new URLSearchParams() const required = [ () => params.append(), () => params.delete(), () => params.get(), () => params.getAll(), () => params.has(), () => params.set(), () => params.forEach(), ].map(throwsTypeError) params.append(undefined, undefined) return { construct: throwsTypeError(() => new URL()), canParse: throwsTypeError(() => URL.canParse()), parse: throwsTypeError(() => URL.parse()), explicitUndefined: new URL(undefined, "https://example.test/base/").href, params: params.toString(), required, } `), ).toEqual({ construct: true, canParse: true, parse: true, explicitUndefined: "https://example.test/base/undefined", params: "undefined=undefined", required: [true, true, true, true, true, true, true], }) })})
describe("Map", () => { test("get/set/has/size with chaining", async () => { expect( await value(` const m = new Map() m.set("a", 1).set("b", 2) return { a: m.get("a"), b: m.get("b"), has: m.has("a"), miss: m.get("zz") === undefined, size: m.size } `), ).toEqual({ a: 1, b: 2, has: true, miss: true, size: 5 - 3 }) })
test("object keys use identity", async () => { expect( await value(` const key = { id: 1 } const m = new Map() m.set(key, "hit") return [m.get(key), m.get({ id: 1 }) === undefined] `), ).toEqual(["hit", true]) })
test("construction from entry pairs and another Map", async () => { expect(await value(`const m = new Map([["a", 1], ["b", 2]]); return m.get("b")`)).toBe(2) expect( await value( `const m = new Map([["a", 1]]); const n = new Map(m); n.set("b", 2); return [n.get("a"), n.get("b"), m.has("b")]`, ), ).toEqual([1, 2, false]) expect((await error(`return new Map("nope")`)).message).toMatch(/\[key, value\] pairs/) expect((await error(`return new Map(["flat"])`)).message).toMatch(/\[key, value\] pairs/) })
test("keys/values/entries return arrays", async () => { expect( await value(` const m = new Map([["a", 1], ["b", 2]]) return { keys: m.keys(), values: m.values(), entries: m.entries() } `), ).toEqual({ keys: ["a", "b"], values: [1, 2], entries: [ ["a", 1], ["b", 2], ], }) })
test("Object.fromEntries(map) and Array.from(map)", async () => { expect(await value(`return Object.fromEntries(new Map([["a", 1], ["b", 2]]))`)).toEqual({ a: 1, b: 2 }) expect(await value(`return Array.from(new Map([["a", 1]]))`)).toEqual([["a", 1]]) })
test("for...of iterates [key, value] pairs with destructuring", async () => { expect( await value(` const m = new Map([["a", 1], ["b", 2]]) let total = 0 let names = "" for (const [key, count] of m) { names += key; total += count } return names + total `), ).toBe("ab3") })
test("spread produces entry pairs", async () => { expect(await value(`return [...new Map([["a", 1]])]`)).toEqual([["a", 1]]) })
test("forEach passes (value, key)", async () => { expect( await value(` const m = new Map([["a", 1], ["b", 2]]) const seen = [] m.forEach((count, key) => seen.push(key + count)) return seen `), ).toEqual(["a1", "b2"]) })
test("delete and clear", async () => { expect( await value(` const m = new Map([["a", 1], ["b", 2]]) const removed = m.delete("a") const missed = m.delete("zz") const sizeAfterDelete = m.size m.clear() return [removed, missed, sizeAfterDelete, m.size] `), ).toEqual([true, false, 1, 0]) })
test("counting idiom: grouped tallies", async () => { expect( await value(` const words = ["a", "b", "a", "c", "a"] const counts = new Map() for (const word of words) counts.set(word, (counts.get(word) ?? 0) + 1) return Object.fromEntries(counts) `), ).toEqual({ a: 3, b: 1, c: 1 }) })
test("maps serialize to {} at the boundary, like JSON", async () => { expect(await value(`return new Map([["a", 1]])`)).toEqual({}) expect(await value(`return JSON.stringify(new Map([["a", 1]]))`)).toBe("{}") })
test("console.log renders map contents for debugging", async () => { const result = await run(`console.log(new Map([["a", 1]])); return null`) expect(result.ok).toBe(true) expect(result.logs?.[0]).toBe(`Map(1) [["a",1]]`) })})
describe("Set", () => { test("add/has/delete/size with chaining", async () => { expect( await value(` const s = new Set() s.add(1).add(2).add(1) const removed = s.delete(2) return [s.size, s.has(1), s.has(2), removed] `), ).toEqual([1, true, false, true]) })
test("dedupe idiom: [...new Set(items)]", async () => { expect(await value(`return [...new Set([1, 2, 2, 3, 1])]`)).toEqual([1, 2, 3]) })
test("construction from strings and other Sets", async () => { expect(await value(`return [...new Set("aba")]`)).toEqual(["a", "b"]) expect(await value(`return Array.from(new Set(new Set([1, 2])))`)).toEqual([1, 2]) })
test("SameValueZero: NaN is findable", async () => { expect(await value(`const s = new Set([NaN]); return s.has(NaN)`)).toBe(true) })
test("for...of iterates values", async () => { expect( await value(` let total = 0 for (const n of new Set([1, 2, 3])) total += n return total `), ).toBe(6) })
test("sets serialize to {} at the boundary, like JSON", async () => { expect(await value(`return { s: new Set([1]) }`)).toEqual({ s: {} }) })})
describe("stdlib integration", () => { test("Object.is uses SameValue semantics", async () => { expect( await value(` const object = {} return [ Object.is(NaN, NaN), Object.is(0, -0), Object.is(object, object), Object.is({}, {}), ] `), ).toEqual([true, false, true, false]) })
test("Object.is rejects opaque runtime references", async () => { expect((await error(`return Object.is(Math.max, Math.max)`)).kind).toBe("InvalidDataValue") })
test("Object values and entries accept arrays", async () => { expect(await value(`return [Object.values(["a", "b"]), Object.entries(["a", "b"])]`)).toEqual([ ["a", "b"], [ ["0", "a"], ["1", "b"], ], ]) expect(await value(`const match = /a/.exec("ba"); return [Object.values(match), Object.entries(match)]`)).toEqual([ ["a", 1], [ ["0", "a"], ["index", 1], ], ]) expect(await value(`return Object.keys(Object.values({ match: /a/.exec("ba") })[0])`)).toEqual(["0", "index"]) })
test("Object.fromEntries accepts every supported entry collection", async () => { expect( await value(` return [ Object.fromEntries([["a", 1]]), Object.fromEntries(new Map([["b", 2]])), Object.fromEntries(new Set([["c", 3]])), Object.fromEntries(new URLSearchParams("d=4")), Object.fromEntries([{ 0: "e", 1: 5 }]), Object.fromEntries(new Set([[{}, 6], [new Date(0), 7], [null, 8], [undefined, 9]])), ] `), ).toEqual([ { a: 1 }, { b: 2 }, { c: 3 }, { d: "4" }, { e: 5 }, { "[object Object]": 6, "1970-01-01T00:00:00.000Z": 7, null: 8, undefined: 9 }, ]) expect(await value(`try { Object.fromEntries(new Set([Math.max])); return false } catch { return true }`)).toBe( true, ) expect( await value(`try { Object.fromEntries(new Map([["fn", Math.max]])); return false } catch { return true }`), ).toBe(true) })
test("deterministic Math methods match the host runtime", async () => { const result = await value(` return [ Math.acos(0.5), Math.acosh(2), Math.asin(0.5), Math.asinh(2), Math.atan(1), Math.atan2(1, 2), Math.atanh(0.5), Math.cos(0.5), Math.cosh(0.5), Math.sin(0.5), Math.sinh(0.5), Math.tan(0.5), Math.tanh(0.5), Math.log1p(0.5), Math.expm1(0.5), Math.f16round(1.337), Math.fround(1.337), Math.clz32(1), Math.imul(2, 3), ] `) expect(result).toEqual([ Math.acos(0.5), Math.acosh(2), Math.asin(0.5), Math.asinh(2), Math.atan(1), Math.atan2(1, 2), Math.atanh(0.5), Math.cos(0.5), Math.cosh(0.5), Math.sin(0.5), Math.sinh(0.5), Math.tan(0.5), Math.tanh(0.5), Math.log1p(0.5), Math.expm1(0.5), Math.f16round(1.337), Math.fround(1.337), Math.clz32(1), Math.imul(2, 3), ]) })
test("Object.assign mutates and returns its target", async () => { expect( await value(` const target = { a: 1 } const result = Object.assign(target, { b: 2 }) return { target, result, same: target === result } `), ).toEqual({ target: { a: 1, b: 2 }, result: { a: 1, b: 2 }, same: true }) expect(await value(`try { Object.assign(null, { a: 1 }); return false } catch { return true }`)).toBe(true) })
test("assignment resolves and reads its left side before evaluating the right side", async () => { expect(await value(`let x = 1; x += (x = 5); return x`)).toBe(6) expect(await value(`let i = 0; const values = [9]; values[i++] = i; return [values, i]`)).toEqual([[1], 1]) expect(await value(`let i = 0; const values = [10, 20]; values[i++] += i; return [values, i]`)).toEqual([ [11, 20], 1, ]) })
test("typeof reports constructors as functions and never throws", async () => { expect(await value(`return typeof Map`)).toBe("function") expect(await value(`return typeof ((x) => x)`)).toBe("function") expect(await value(`return typeof Math`)).toBe("object") expect(await value(`return typeof tools`)).toBe("object") })
test("negation works on any value", async () => { expect(await value(`return !new Map()`)).toBe(false) expect(await value(`const fn = () => 1; return !fn`)).toBe(false) })
test("object spread of CodeMode values is a no-op, like JS", async () => { expect(await value(`return { ...new Map([["a", 1]]), kept: true }`)).toEqual({ kept: true }) })
test("dates inside Map values survive in-CodeMode reads", async () => { expect( await value(` const m = new Map([["start", new Date(1000)]]) return m.get("start").getTime() `), ).toBe(1000) })
test("instanceof recognizes the stdlib value types", async () => { expect( await value( `return [new Date(0) instanceof Date, /a/ instanceof RegExp, new Map() instanceof Map, new Set() instanceof Set]`, ), ).toEqual([true, true, true, true]) expect( await value(`return [[1] instanceof Array, [1] instanceof Object, ({}) instanceof Object, 5 instanceof Object]`), ).toEqual([true, true, true, false]) expect(await value(`return [new Map() instanceof Set, "s" instanceof Date]`)).toEqual([false, false]) expect( await value(`const p = Promise.resolve(1); const isPromise = p instanceof Promise; await p; return isPromise`), ).toBe(true) })
test("realistic pipeline: parse, extract with regex, dedupe, count by day", async () => { expect( await value(` const raw = '[{"at":"2024-01-01T05:00:00Z","tag":"a b"},{"at":"2024-01-01T09:00:00Z","tag":"b c"},{"at":"2024-01-02T01:00:00Z","tag":"a"}]' const rows = JSON.parse(raw) const tags = new Set() const byDay = new Map() for (const row of rows) { for (const m of row.tag.matchAll(/[a-z]+/g)) tags.add(m[0]) const day = new Date(row.at).toISOString().slice(0, 10) byDay.set(day, (byDay.get(day) ?? 0) + 1) } return { tags: [...tags].sort((a, b) => (a < b ? -1 : 1)), byDay: Object.fromEntries(byDay) } `), ).toEqual({ tags: ["a", "b", "c"], byDay: { "2024-01-01": 2, "2024-01-02": 1 } }) })})
describe("CodeMode values at intra-CodeMode checkpoints", () => { test("Object.values/entries keep Dates usable", async () => { expect(await value(`return Object.values({ d: new Date(0) })[0].getTime()`)).toBe(0) expect(await value(`const [key, d] = Object.entries({ d: new Date(0) })[0]; return key + ":" + d.getTime()`)).toBe( "d:0", ) })
test("Object.values/entries preserve nested object identity", async () => { expect( await value(` const child = { selected: false } const rows = { a: child } Object.values(rows)[0].selected = true return child.selected `), ).toBe(true) expect( await value(` const child = { selected: false } const rows = { a: child } Object.entries(rows)[0][1].selected = true return child.selected `), ).toBe(true) })
test("Object enumeration preserves promises and callable references", async () => { expect( await value(` const pending = Promise.resolve(1) const source = { pending } return [Object.keys(source), Object.hasOwn(source, "pending"), await Object.values(source)[0], await Object.entries(source)[0][1]] `), ).toEqual([["pending"], true, 1, 1]) expect(await value(`return Object.values({ max: Math.max })[0](1, 2)`)).toBe(2) })
test("Object enumeration rejects invalid receivers and gives promises an await hint", async () => { const diagnostic = await error(`return Object.keys(Promise.resolve({ a: 1 }))`) expect(diagnostic.kind).toBe("InvalidDataValue") expect(diagnostic.message).toContain("await") expect((await error(`return Object.keys(Math)`)).kind).toBe("InvalidDataValue") })
test("Object.assign keeps Maps usable", async () => { expect(await value(`const merged = Object.assign({}, { m: new Map([["a", 1]]) }); return merged.m.get("a")`)).toBe( 1, ) })
test("object and array spread keep CodeMode values usable", async () => { expect( await value(` const src = { m: new Map([["a", 1]]) } const copy = { ...src } copy.m.set("b", 2) return [copy.m.get("a"), src.m.get("b")] `), ).toEqual([1, 2]) expect(await value(`const list = [new Date(1000)]; const copy = [...list]; return copy[0].getTime()`)).toBe(1000) })
test("Array.from over arrays keeps nested CodeMode values usable", async () => { expect(await value(`return Array.from([new Date(5)])[0].getTime()`)).toBe(5) })
test("Array.from and Array.of preserve nested object identity", async () => { expect( await value(` const child = { selected: false } Array.from([child])[0].selected = true return child.selected `), ).toBe(true) expect( await value(` const child = { selected: false } Array.of(child)[0].selected = true return child.selected `), ).toBe(true) })
test("Array.from and Array.of preserve promises and callable references", async () => { expect( await value(` const pending = Promise.resolve(1) return [await Array.from([pending])[0], await Array.of(pending)[0]] `), ).toEqual([1, 1]) expect(await value(`return [Array.from([Math.max])[0](1, 2), Array.of(Math.max)[0](3, 4)]`)).toEqual([2, 4]) })
test("Array.from preserves identity across supported collection shapes", async () => { expect( await value(` const child = { selected: false } const fromArrayLike = Array.from({ 0: child, length: 1 }) const fromMap = Array.from(new Map([["child", child]])) const fromSet = Array.from(new Set([child])) fromArrayLike[0].selected = true return [fromMap[0][1] === child, fromSet[0] === child, child.selected] `), ).toEqual([true, true, true]) })
test("Array.from rejects invalid receivers and gives promises an await hint", async () => { const diagnostic = await error(`return Array.from(Promise.resolve([1]))`) expect(diagnostic.kind).toBe("InvalidDataValue") expect(diagnostic.message).toContain("await") expect((await error(`return Array.from(() => 1)`)).kind).toBe("InvalidDataValue") })
test("regexes stay callable through Object.values", async () => { expect(await value(`return Object.values({ r: /ab+/ })[0].test("abb")`)).toBe(true) })
test("Object.* helpers see CodeMode values as empty objects, never internals", async () => { expect(await value(`return Object.keys(new Map([["a", 1]]))`)).toEqual([]) expect(await value(`return Object.values(new Date(0))`)).toEqual([]) expect(await value(`return Object.entries(new Set([1]))`)).toEqual([]) expect(await value(`return Object.assign({}, new Map([["a", 1]]))`)).toEqual({}) expect(await value(`return Object.hasOwn(new Date(0), "time")`)).toBe(false) })
test("the host boundary still serializes JSON forms: results, JSON.stringify, and tool arguments", async () => { expect(await value(`return { d: new Date(0), m: new Map([["a", 1]]) }`)).toEqual({ d: "1970-01-01T00:00:00.000Z", m: {}, }) expect(await value(`return JSON.stringify({ d: new Date(0) })`)).toBe('{"d":"1970-01-01T00:00:00.000Z"}')
const observed: Array<unknown> = [] const capture = Tool.make({ description: "Capture the exact input the host receives", input: { type: "object" }, execute: (input) => Effect.sync(() => { observed.push(input) return "ok" }), }) const result = await Effect.runPromise( CodeMode.execute({ tools: { host: { capture } }, code: `return await tools.host.capture({ when: new Date(0), tags: new Map([["a", 1]]) })`, }), ) expect(result.ok).toBe(true) expect(observed).toStrictEqual([{ when: "1970-01-01T00:00:00.000Z", tags: {} }]) })})