mirror of
https://github.com/anomalyco/opencode.git
synced 2026-09-04 11:34:39 +00:00
Replace record-keyed tools and the separate namespace-description map with an OpenAI-style array of named tools and namespaces. Namespace descriptions are optional, namespaces may nest, and duplicate or dotted names are rejected.
463 lines
17 KiB
TypeScript
463 lines
17 KiB
TypeScript
/*
|
|
* Portions adapted from Test262 at revision 250f204f23a9249ff204be2baec29600faae7b75:
|
|
* - test/built-ins/Set/prototype/union/combines-sets.js
|
|
* - test/built-ins/Set/prototype/union/combines-empty-sets.js
|
|
* - test/built-ins/Set/prototype/union/combines-itself.js
|
|
* - test/built-ins/Set/prototype/union/combines-same-sets.js
|
|
* - test/built-ins/Set/prototype/union/combines-Map.js
|
|
* - test/built-ins/Set/prototype/union/result-order.js
|
|
* - test/built-ins/Set/prototype/union/appends-new-values.js
|
|
* - test/built-ins/Set/prototype/union/allows-set-like-object.js
|
|
* - test/built-ins/Set/prototype/union/size-is-a-number.js
|
|
* - test/built-ins/Set/prototype/union/has-is-callable.js
|
|
* - test/built-ins/Set/prototype/union/keys-is-callable.js
|
|
* - test/built-ins/Set/prototype/union/array-throws.js
|
|
* - test/built-ins/Set/prototype/union/converts-negative-zero.js
|
|
* - test/built-ins/Set/prototype/union/set-like-class-mutation.js
|
|
* - test/built-ins/Set/prototype/intersection/combines-sets.js
|
|
* - test/built-ins/Set/prototype/intersection/combines-itself.js
|
|
* - test/built-ins/Set/prototype/intersection/result-order.js
|
|
* - test/built-ins/Set/prototype/intersection/size-is-a-number.js
|
|
* - test/built-ins/Set/prototype/intersection/converts-negative-zero.js
|
|
* - test/built-ins/Set/prototype/intersection/combines-Map.js
|
|
* - test/built-ins/Set/prototype/intersection/allows-set-like-object.js
|
|
* - test/built-ins/Set/prototype/intersection/set-like-class-mutation.js
|
|
* - test/built-ins/Set/prototype/difference/combines-sets.js
|
|
* - test/built-ins/Set/prototype/difference/combines-itself.js
|
|
* - test/built-ins/Set/prototype/difference/result-order.js
|
|
* - test/built-ins/Set/prototype/difference/size-is-a-number.js
|
|
* - test/built-ins/Set/prototype/difference/converts-negative-zero.js
|
|
* - test/built-ins/Set/prototype/difference/combines-Map.js
|
|
* - test/built-ins/Set/prototype/difference/allows-set-like-object.js
|
|
* - test/built-ins/Set/prototype/difference/set-like-class-mutation.js
|
|
* - test/built-ins/Set/prototype/symmetricDifference/combines-sets.js
|
|
* - test/built-ins/Set/prototype/symmetricDifference/combines-itself.js
|
|
* - test/built-ins/Set/prototype/symmetricDifference/result-order.js
|
|
* - test/built-ins/Set/prototype/symmetricDifference/size-is-a-number.js
|
|
* - test/built-ins/Set/prototype/symmetricDifference/converts-negative-zero.js
|
|
* - test/built-ins/Set/prototype/symmetricDifference/set-like-class-mutation.js
|
|
* - test/built-ins/Set/prototype/symmetricDifference/combines-Map.js
|
|
* - test/built-ins/Set/prototype/symmetricDifference/allows-set-like-object.js
|
|
* - test/built-ins/Set/prototype/isSubsetOf/compares-sets.js
|
|
* - test/built-ins/Set/prototype/isSubsetOf/size-is-a-number.js
|
|
* - test/built-ins/Set/prototype/isSubsetOf/compares-Map.js
|
|
* - test/built-ins/Set/prototype/isSubsetOf/allows-set-like-object.js
|
|
* - test/built-ins/Set/prototype/isSubsetOf/compares-itself.js
|
|
* - test/built-ins/Set/prototype/isSubsetOf/compares-same-sets.js
|
|
* - test/built-ins/Set/prototype/isSubsetOf/set-like-class-mutation.js
|
|
* - test/built-ins/Set/prototype/isSupersetOf/compares-sets.js
|
|
* - test/built-ins/Set/prototype/isSupersetOf/size-is-a-number.js
|
|
* - test/built-ins/Set/prototype/isSupersetOf/compares-Map.js
|
|
* - test/built-ins/Set/prototype/isSupersetOf/allows-set-like-object.js
|
|
* - test/built-ins/Set/prototype/isSupersetOf/compares-itself.js
|
|
* - test/built-ins/Set/prototype/isSupersetOf/compares-same-sets.js
|
|
* - test/built-ins/Set/prototype/isSupersetOf/converts-negative-zero.js
|
|
* - test/built-ins/Set/prototype/isDisjointFrom/compares-sets.js
|
|
* - test/built-ins/Set/prototype/isDisjointFrom/size-is-a-number.js
|
|
* - test/built-ins/Set/prototype/isDisjointFrom/compares-Map.js
|
|
* - test/built-ins/Set/prototype/isDisjointFrom/allows-set-like-object.js
|
|
* - test/built-ins/Set/prototype/isDisjointFrom/compares-itself.js
|
|
* - test/built-ins/Set/prototype/isDisjointFrom/compares-same-sets.js
|
|
* - test/built-ins/Set/prototype/isDisjointFrom/converts-negative-zero.js
|
|
* - test/built-ins/Set/prototype/isDisjointFrom/set-like-class-mutation.js
|
|
*
|
|
* Copyright (C) 2023 Anthony Frehner. All rights reserved.
|
|
* Copyright (C) 2023 Anthony Frehner and Kevin Gibbons. All rights reserved.
|
|
* Copyright (C) 2023 Kevin Gibbons. All rights reserved.
|
|
* Copyright (C) 2023 Kevin Gibbons, Anthony Frehner. All rights reserved.
|
|
* Test262 portions are governed by the BSD license in LICENSE.test262.
|
|
* Set-like `keys` methods return arrays instead of iterator objects because
|
|
* CodeMode materializes supported iterators and does not support generators.
|
|
*/
|
|
import { describe, expect, test } from "bun:test"
|
|
import { Effect } from "effect"
|
|
import { CodeMode } from "../src/index.js"
|
|
|
|
const value = async (code: string) => {
|
|
const result = await Effect.runPromise(CodeMode.execute({ code }))
|
|
if (!result.ok) throw new Error(`expected success, got ${result.error.kind}: ${result.error.message}`)
|
|
return result.value
|
|
}
|
|
|
|
describe("Set composition Test262 parity", () => {
|
|
test("combines Sets without mutating either operand", async () => {
|
|
expect(
|
|
await value(`
|
|
const left = new Set([1, 2])
|
|
const right = new Set([2, 3])
|
|
const union = left.union(right)
|
|
const intersection = left.intersection(right)
|
|
const difference = left.difference(right)
|
|
const symmetric = left.symmetricDifference(right)
|
|
return [
|
|
[...union], union instanceof Set,
|
|
[...intersection], intersection instanceof Set,
|
|
[...difference], difference instanceof Set,
|
|
[...symmetric], symmetric instanceof Set,
|
|
[...left], [...right],
|
|
[...left.union(left)], left.union(left) !== left,
|
|
[...left.intersection(left)], left.intersection(left) !== left,
|
|
[...left.difference(left)], left.difference(left) !== left,
|
|
[...left.symmetricDifference(left)], left.symmetricDifference(left) !== left,
|
|
[...left.union(new Set())], [...new Set().union(left)],
|
|
]
|
|
`),
|
|
).toEqual([
|
|
[1, 2, 3],
|
|
true,
|
|
[2],
|
|
true,
|
|
[1],
|
|
true,
|
|
[1, 3],
|
|
true,
|
|
[1, 2],
|
|
[2, 3],
|
|
[1, 2],
|
|
true,
|
|
[1, 2],
|
|
true,
|
|
[],
|
|
true,
|
|
[],
|
|
true,
|
|
[1, 2],
|
|
[1, 2],
|
|
])
|
|
})
|
|
|
|
test("preserves the specified result order", async () => {
|
|
expect(
|
|
await value(`
|
|
return [
|
|
[...new Set([1, 3, 5]).intersection(new Set([3, 2, 1]))],
|
|
[...new Set([3, 2, 1, 0]).intersection(new Set([1, 3, 5]))],
|
|
[...new Set([1, 2, 3, 4]).difference(new Set([6, 5, 3, 2]))],
|
|
[...new Set([6, 5, 3, 2]).difference(new Set([1, 2, 3, 4]))],
|
|
[...new Set([1, 2, 3, 4]).symmetricDifference(new Set([6, 5, 4, 3]))],
|
|
[...new Set([2, 3]).union(new Set([1, 2]))],
|
|
[...new Set([1, 2, -3]).union(new Set([-1, 0]))],
|
|
]
|
|
`),
|
|
).toEqual([
|
|
[1, 3],
|
|
[1, 3],
|
|
[1, 4],
|
|
[6, 5],
|
|
[1, 2, 6, 5],
|
|
[2, 3, 1],
|
|
[1, 2, -3, -1, 0],
|
|
])
|
|
})
|
|
|
|
test("accepts Maps as Set-like operands", async () => {
|
|
expect(
|
|
await value(`
|
|
const set = new Set([1, 2])
|
|
const map = new Map([[2, "two"], [3, "three"]])
|
|
return [
|
|
[...set.union(map)],
|
|
[...set.intersection(map)],
|
|
[...set.difference(map)],
|
|
[...set.symmetricDifference(map)],
|
|
]
|
|
`),
|
|
).toEqual([[1, 2, 3], [2], [1], [1, 3]])
|
|
})
|
|
|
|
test("accepts supported Set-like objects and uses the size-selected method", async () => {
|
|
expect(
|
|
await value(`
|
|
const keysOnly = {
|
|
size: 1,
|
|
has: () => { throw new Error("has should not be called") },
|
|
keys: () => [2, 3],
|
|
}
|
|
const hasOnly = {
|
|
size: 2,
|
|
has: (value) => value === 2,
|
|
keys: () => { throw new Error("keys should not be called") },
|
|
}
|
|
const set = new Set([1, 2])
|
|
return [
|
|
[...set.union(keysOnly)],
|
|
[...set.intersection(hasOnly)],
|
|
[...set.difference(hasOnly)],
|
|
[...set.symmetricDifference(keysOnly)],
|
|
]
|
|
`),
|
|
).toEqual([[1, 2, 3], [2], [1], [1, 3]])
|
|
})
|
|
|
|
test("normalizes negative zero", async () => {
|
|
expect(
|
|
await value(`
|
|
const setlike = {
|
|
size: 1,
|
|
has: () => { throw new Error("has should not be called") },
|
|
keys: () => [-0],
|
|
}
|
|
return [
|
|
1 / new Set([1]).union(setlike).values()[1] === Infinity,
|
|
1 / new Set([0, 1, 2]).intersection(setlike).values()[0] === Infinity,
|
|
[...new Set([0, 1]).difference(setlike)],
|
|
1 / new Set([1, 2]).symmetricDifference(setlike).values()[2] === Infinity,
|
|
]
|
|
`),
|
|
).toEqual([true, true, [1], true])
|
|
})
|
|
|
|
test("handles duplicate Set-like keys using receiver membership", async () => {
|
|
expect(
|
|
await value(`
|
|
const other = {
|
|
size: 4,
|
|
has: () => { throw new Error("has should not be called") },
|
|
keys: () => [2, 2, 3, 3],
|
|
}
|
|
return [...new Set([1, 2]).symmetricDifference(other)]
|
|
`),
|
|
).toEqual([1, 3])
|
|
})
|
|
|
|
test("copies receiver data before Set-like key iteration mutates it", async () => {
|
|
expect(
|
|
await value(`
|
|
const unionBase = new Set(["a", "b", "c", "d", "e"])
|
|
const unionOther = {
|
|
size: 2,
|
|
has: () => { throw new Error("has should not be called") },
|
|
keys: () => {
|
|
unionBase.delete("b")
|
|
unionBase.delete("c")
|
|
unionBase.add("b")
|
|
return ["x", "y"]
|
|
},
|
|
}
|
|
const union = unionBase.union(unionOther)
|
|
|
|
const intersectionBase = new Set(["a", "b", "c", "d", "e"])
|
|
const intersectionOther = {
|
|
size: 3,
|
|
has: () => { throw new Error("has should not be called") },
|
|
keys: () => {
|
|
intersectionBase.delete("b")
|
|
intersectionBase.delete("c")
|
|
intersectionBase.add("b")
|
|
return ["x", "b", "b"]
|
|
},
|
|
}
|
|
const intersection = intersectionBase.intersection(intersectionOther)
|
|
|
|
const differenceBase = new Set(["a", "b", "c", "d", "e"])
|
|
const differenceOther = {
|
|
size: 3,
|
|
has: () => { throw new Error("has should not be called") },
|
|
keys: () => {
|
|
differenceBase.delete("b")
|
|
differenceBase.delete("c")
|
|
differenceBase.add("b")
|
|
return ["x", "b", "b"]
|
|
},
|
|
}
|
|
const difference = differenceBase.difference(differenceOther)
|
|
|
|
const symmetricBase = new Set(["a", "b", "c", "d", "e"])
|
|
const symmetricOther = {
|
|
size: 4,
|
|
has: () => { throw new Error("has should not be called") },
|
|
keys: () => {
|
|
symmetricBase.delete("b")
|
|
symmetricBase.delete("c")
|
|
symmetricBase.add("b")
|
|
return ["x", "b", "c", "c"]
|
|
},
|
|
}
|
|
const symmetric = symmetricBase.symmetricDifference(symmetricOther)
|
|
|
|
return [
|
|
[...union], [...unionBase],
|
|
[...intersection], [...intersectionBase],
|
|
[...difference], [...differenceBase],
|
|
[...symmetric], [...symmetricBase],
|
|
]
|
|
`),
|
|
).toEqual([
|
|
["a", "b", "c", "d", "e", "x", "y"],
|
|
["a", "d", "e", "b"],
|
|
["b"],
|
|
["a", "d", "e", "b"],
|
|
["a", "c", "d", "e"],
|
|
["a", "d", "e", "b"],
|
|
["a", "c", "d", "e", "x"],
|
|
["a", "d", "e", "b"],
|
|
])
|
|
})
|
|
})
|
|
|
|
describe("Set relation Test262 parity", () => {
|
|
test("compares Sets", async () => {
|
|
expect(
|
|
await value(`
|
|
const set = new Set([1, 2])
|
|
return [
|
|
set.isSubsetOf(new Set([2, 3])), set.isSubsetOf(new Set([1, 2, 3])),
|
|
set.isSupersetOf(new Set([2, 3])), set.isSupersetOf(new Set([1])),
|
|
set.isDisjointFrom(new Set([2, 3])), set.isDisjointFrom(new Set([3])),
|
|
new Set().isSubsetOf(set), set.isSupersetOf(new Set()), new Set().isDisjointFrom(new Set()),
|
|
set.isSubsetOf(set), set.isSupersetOf(set), set.isDisjointFrom(set),
|
|
set.isSubsetOf(new Set([1, 2])), set.isSupersetOf(new Set([1, 2])),
|
|
]
|
|
`),
|
|
).toEqual([false, true, false, true, false, true, true, true, true, true, true, false, true, true])
|
|
})
|
|
|
|
test("compares Maps and supported Set-like objects", async () => {
|
|
expect(
|
|
await value(`
|
|
const set = new Set([1, 2])
|
|
const map = new Map([[1, "one"], [2, "two"], [3, "three"]])
|
|
const hasOnly = {
|
|
size: 2,
|
|
has: (value) => value === 1 || value === 2,
|
|
keys: () => { throw new Error("keys should not be called") },
|
|
}
|
|
const keysOnly = {
|
|
size: 1,
|
|
has: () => { throw new Error("has should not be called") },
|
|
keys: () => [1],
|
|
}
|
|
return [
|
|
set.isSubsetOf(map), set.isSupersetOf(map), set.isDisjointFrom(map),
|
|
set.isSubsetOf(hasOnly), set.isSupersetOf(keysOnly), set.isDisjointFrom(hasOnly),
|
|
]
|
|
`),
|
|
).toEqual([true, false, false, true, true, false])
|
|
})
|
|
|
|
test("normalizes negative zero from Set-like keys", async () => {
|
|
expect(
|
|
await value(`
|
|
const setlike = {
|
|
size: 1,
|
|
has: () => { throw new Error("has should not be called") },
|
|
keys: () => [-0],
|
|
}
|
|
return [
|
|
new Set([0, 1]).isSupersetOf(setlike),
|
|
new Set([0, 1]).isDisjointFrom(setlike),
|
|
]
|
|
`),
|
|
).toEqual([true, false])
|
|
})
|
|
|
|
test("observes live receiver mutation while calling Set-like has", async () => {
|
|
expect(
|
|
await value(`
|
|
const subset = new Set(["a", "b", "c"])
|
|
const subsetOther = {
|
|
size: 3,
|
|
has: (item) => {
|
|
if (item === "a") subset.delete("c")
|
|
return ["x", "a", "b"].includes(item)
|
|
},
|
|
keys: () => { throw new Error("keys should not be called") },
|
|
}
|
|
const disjoint = new Set(["a", "b", "c"])
|
|
const disjointOther = {
|
|
size: 3,
|
|
has: (item) => {
|
|
if (item === "a") {
|
|
disjoint.delete("b")
|
|
disjoint.delete("c")
|
|
disjoint.add("b")
|
|
}
|
|
if (item === "c") throw new Error("deleted value should not be visited")
|
|
return false
|
|
},
|
|
keys: () => { throw new Error("keys should not be called") },
|
|
}
|
|
return [
|
|
subset.isSubsetOf(subsetOther), [...subset],
|
|
disjoint.isDisjointFrom(disjointOther), [...disjoint],
|
|
]
|
|
`),
|
|
).toEqual([true, ["a", "b"], true, ["a", "b"]])
|
|
})
|
|
})
|
|
|
|
describe("Set-like validation Test262 parity", () => {
|
|
test("rejects arrays, invalid sizes, and non-callable methods with TypeError", async () => {
|
|
expect(
|
|
await value(`
|
|
const set = new Set([1])
|
|
const names = []
|
|
let coercionCalls = 0
|
|
const invalid = [
|
|
[],
|
|
{ size: undefined, has: () => false, keys: () => [] },
|
|
{ size: NaN, has: () => false, keys: () => [] },
|
|
{ size: { valueOf: () => { coercionCalls += 1; return NaN } }, has: () => false, keys: () => [] },
|
|
{ size: "string", has: () => false, keys: () => [] },
|
|
{ size: 0, has: undefined, keys: () => [] },
|
|
{ size: 0, has: {}, keys: () => [] },
|
|
{ size: 0, has: () => false, keys: undefined },
|
|
{ size: 0, has: () => false, keys: {} },
|
|
]
|
|
for (const other of invalid) {
|
|
try { set.union(other) } catch (error) { names.push(error.name) }
|
|
}
|
|
return [names, coercionCalls]
|
|
`),
|
|
).toEqual([
|
|
[
|
|
"TypeError",
|
|
"TypeError",
|
|
"TypeError",
|
|
"TypeError",
|
|
"TypeError",
|
|
"TypeError",
|
|
"TypeError",
|
|
"TypeError",
|
|
"TypeError",
|
|
],
|
|
1,
|
|
])
|
|
})
|
|
|
|
test("validates Set-like records for every method", async () => {
|
|
expect(
|
|
await value(`
|
|
const set = new Set([1])
|
|
const invalid = { size: NaN, has: () => false, keys: () => [] }
|
|
const names = []
|
|
const operations = [
|
|
() => set.union(invalid),
|
|
() => set.intersection(invalid),
|
|
() => set.difference(invalid),
|
|
() => set.symmetricDifference(invalid),
|
|
() => set.isSubsetOf(invalid),
|
|
() => set.isSupersetOf(invalid),
|
|
() => set.isDisjointFrom(invalid),
|
|
]
|
|
for (const operation of operations) {
|
|
try { operation() } catch (error) { names.push(error.name) }
|
|
}
|
|
return names
|
|
`),
|
|
).toEqual(["TypeError", "TypeError", "TypeError", "TypeError", "TypeError", "TypeError", "TypeError"])
|
|
})
|
|
|
|
test("requires Set-like keys to return CodeMode's materialized iterator representation", async () => {
|
|
expect(
|
|
await value(`
|
|
const set = new Set([1])
|
|
const names = []
|
|
for (const keys of [() => "ab", () => new Set([2]), () => new Map([[2, true]])]) {
|
|
try { set.union({ size: 1, has: () => false, keys }) } catch (error) { names.push(error.name) }
|
|
}
|
|
return names
|
|
`),
|
|
).toEqual(["TypeError", "TypeError", "TypeError"])
|
|
})
|
|
})
|