Something went wrong. Try again.
opencode v2 mirror
Something went wrong. Try again.
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213import { describe, expect, test } from "bun:test"import { Effect } from "effect"import { CodeMode } from "../src/index.js"
// One failure is one program error object, and rethrowing it keeps the diagnostic it started with.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("source syntax", () => { test("rejects TypeScript-only syntax", async () => { expect((await error(`const value: number = 1; return value`)).kind).toBe("ParseError") })})
describe("error identity", () => { test("Error.isError is true for every Error value and nothing else", async () => { expect( await value(` const caught = (() => { try { null.foo } catch (error) { return error } })() return [Error.isError(new Error("x")), Error.isError(new RangeError("x")), Error.isError(caught), Error.isError({ name: "Error", message: "x" }), Error.isError("Error"), Error.isError(null)] `), ).toEqual([true, true, true, false, false, false]) })
test("awaiting the same rejected promise twice yields the same error object", async () => { expect( await value(` const fail = async () => { null.foo } const p = fail() const a = await p.catch((e) => e) try { await p } catch (b) { return a === b } `), ).toBe(true) })
test("allSettled reasons for the same failure are identical", async () => { expect( await value(` const fail = async () => { null.foo } const p = fail() const [a, b] = await Promise.allSettled([p, p]) return [a.reason === b.reason, a.reason.name, a.reason.message] `), ).toEqual([true, "TypeError", "Cannot read properties of null (reading 'foo')."]) })
test("Promise.any collects the same object a direct catch would", async () => { expect( await value(` const fail = async () => { null.foo } const p = fail() const direct = await p.catch((e) => e) try { await Promise.any([p]) } catch (aggregate) { return aggregate.errors[0] === direct } `), ).toBe(true) })})
describe("rethrown interpreter failures", () => { test("keep their diagnostic kind and source location", async () => { const failure = await error(`try { switch (Symbol) {} } catch (e) { throw e }`) expect(failure.kind).toBe("InvalidDataValue") expect(failure.message).toStartWith("TypeError: Switch discriminants must be data values. (line ") expect(failure.location).toBeDefined() })
test("keep their location through a rejection handler", async () => { const direct = await error(` const fail = async () => { null.foo } await fail() `) const rethrown = await error(` const fail = async () => { null.foo } await fail().catch((e) => { throw e }) `) expect(direct.location).toBeDefined() expect(rethrown).toEqual(direct) })})
describe("uncaught program throws", () => { test("an Error reports as name: message", async () => { const failure = await error(`throw new TypeError("bad input")`) expect(failure).toEqual({ kind: "ExecutionFailure", message: "TypeError: bad input" }) })
test("a custom name is honored", async () => { const failure = await error(`const e = new Error("x"); e.name = "ValidationError"; throw e`) expect(failure.message).toBe("ValidationError: x") })
test("non-Error values keep the Uncaught prefix", async () => { expect((await error(`throw "boom"`)).message).toBe("Uncaught: boom") expect((await error(`throw { code: 7 }`)).message).toBe('Uncaught: {"code":7}') })})
describe("source locations", () => { test("uses the submitted line and 1-based column", async () => { const failure = await error("const value = 1\nreturn value()") expect(failure.location).toEqual({ line: 2, column: 8 }) expect(failure.message).toBe("TypeError: value is not a function. (line 2, col 8)") })
test("names a missing method on a call instead of the previous line", async () => { const failure = await error(`// Try search with different namespacesfor (const ns of ["github", "tools.github", "tools", ""]) { const s = await search({query: "star", namespace: ns, limit: 100}).catch(e=>({items:[],error:String(e)})); return s}`) expect(failure.location).toEqual({ line: 3, column: 19 }) expect(failure.message).toBe("TypeError: search(...).catch is not a function. (line 3, col 19)") })})
describe("host errors escaping built-ins", () => { test("become the same-named program error", async () => { expect( await value(` try { (1).toFixed(200) } catch (e) { return [e.name, e instanceof RangeError, e.message] } `), ).toEqual(["RangeError", true, "toFixed() argument must be between 0 and 100"]) })
test("report the location of the call that raised them", async () => { const failure = await error(`return [1].map((n) => n.toFixed(200))`) expect(failure.kind).toBe("ExecutionFailure") expect(failure.message).toBe("RangeError: toFixed() argument must be between 0 and 100 (line 1, col 23)") })
test("a built-in that rejects its arguments before doing any work is located at the call", async () => { expect((await error(`new Promise(Symbol)`)).message).toEndWith("(line 1, col 1)") })
test("a rejection born inside a promise the built-in created is located at the creating call", async () => { expect((await error(`return await Promise.all(1)`)).message).toEndWith("(line 1, col 14)") expect((await error(`return await Promise.race([])`)).message).toEndWith("(line 1, col 14)") expect((await error(`return await Promise.all({ [Symbol.iterator]: () => ({ next: 1 }) })`)).message).toEndWith( "(line 1, col 14)", ) expect((await error(`let p; p = Promise.resolve().then(() => p); return await p`)).message).toEndWith( "(line 1, col 12)", ) })
test("an un-awaited rejection born inside promise machinery keeps its location in the warning", async () => { const result = await run(`Promise.all(1); return 1`) expect(result.ok && result.warnings?.[0]?.message).toEndWith( "TypeError: Promise.all expects a synchronous iterable, received a number. (line 1, col 1)", ) })
test("a failure inside a built-in called by another built-in is located at the outer call", async () => { const failure = await error(`return Array.from({ [Symbol.iterator]: () => ({ next: 1 }) })`) expect(failure.message).toBe("TypeError: Iterator next must be a function. (line 1, col 8)") })})
describe("call depth", () => { test("runaway recursion fails fast with a catchable RangeError", async () => { const started = Date.now() expect( await value(` const f = (n) => f(n + 1) try { f(0) } catch (e) { return [e.name, e instanceof RangeError, e.message] } `), ).toEqual(["RangeError", true, "Maximum call stack size exceeded"]) expect(Date.now() - started).toBeLessThan(2000) })
test("uncaught overflow reports the call that overflowed", async () => { const failure = await error(`const f = (n) => f(n + 1); return f(0)`) expect(failure.kind).toBe("ExecutionFailure") expect(failure.message).toBe("RangeError: Maximum call stack size exceeded (line 1, col 18)") })
test("the limit is 10000 nested calls", async () => { expect(await value(`let depth = 0; const f = () => { depth++; f() }; try { f() } catch { return depth }`)).toBe( 10000, ) expect(await value(`const f = (n) => (n === 0 ? 0 : 1 + f(n - 1)); return f(9000)`)).toBe(9000) })
test("recursion through a built-in callback counts", async () => { const failure = await error(`const f = (n) => [n].map((x) => f(x + 1)); return f(0)`) expect(failure.message).toStartWith("RangeError: Maximum call stack size exceeded") })
test("an await resets the depth, so long async chains are fine", async () => { expect( await value(` const page = async (n) => { await null; return n === 0 ? "done" : page(n - 1) } return await page(3000) `), ).toBe("done") })
test("an async function that recurses before its first await overflows like JS", async () => { const failure = await error(`const f = async (n) => f(n + 1); return await f(0)`) expect(failure.message).toStartWith("RangeError: Maximum call stack size exceeded") })})