mirror of
https://github.com/anomalyco/opencode.git
synced 2026-09-11 11:26:24 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
97a47cc022 |
@@ -18,6 +18,7 @@ const WebSocketResponseCreate = Schema.StructWithRest(Schema.Struct({ type: Sche
|
||||
])
|
||||
const decodeMessage = ProviderShared.validateWith(Schema.decodeUnknownEffect(WebSocketResponseCreate))
|
||||
const encodeMessage = Schema.encodeSync(Schema.fromJsonString(WebSocketResponseCreate))
|
||||
const decodeEvent = Schema.decodeUnknownEffect(OpenResponses.protocol.stream.event)
|
||||
|
||||
export interface Options {
|
||||
readonly id: string
|
||||
@@ -26,7 +27,6 @@ export interface Options {
|
||||
readonly enabled?: (url: string) => boolean
|
||||
readonly url?: (url: string) => string
|
||||
readonly headers?: (headers: Headers.Headers) => Headers.Headers
|
||||
readonly continuation?: OpenResponsesContinuation.Shape
|
||||
}
|
||||
|
||||
export interface Prepared {
|
||||
@@ -60,7 +60,7 @@ const driver = (options: Options, body: string): WebSocketChannelDriver => {
|
||||
}),
|
||||
observe: (_create, frame) =>
|
||||
Effect.gen(function* () {
|
||||
const event = yield* OpenResponses.decodeChannelEvent(frame).pipe(
|
||||
const event = yield* decodeEvent(frame).pipe(
|
||||
Effect.mapError((cause) =>
|
||||
ProviderShared.eventError(options.id, `Invalid ${options.name} WebSocket event`, frame, cause),
|
||||
),
|
||||
@@ -163,7 +163,6 @@ export const transport = <Body>(options: Options): Transport<Body, Prepared, str
|
||||
request: create.request,
|
||||
message: create.message,
|
||||
base,
|
||||
continuation: options.continuation,
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
@@ -6,6 +6,7 @@ import { OpenResponses } from "./open-responses.js"
|
||||
|
||||
const PROTOCOL = "open-responses.websocket.v1"
|
||||
const VERSION = 1
|
||||
const decodeEvent = Schema.decodeUnknownEffect(OpenResponses.protocol.stream.event)
|
||||
|
||||
interface CheckpointValue {
|
||||
readonly version: typeof VERSION
|
||||
@@ -14,19 +15,12 @@ interface CheckpointValue {
|
||||
readonly output: ReadonlyArray<unknown>
|
||||
}
|
||||
|
||||
/**
|
||||
* Fields to send next to `previous_response_id` on an incremental step, or undefined to send the step in full.
|
||||
* Whether omitted fields carry over from the continued response is provider behavior the route must know.
|
||||
*/
|
||||
export type Shape = (request: Readonly<Record<string, unknown>>) => Readonly<Record<string, unknown>> | undefined
|
||||
|
||||
export interface DriverInput {
|
||||
readonly id: string
|
||||
readonly name: string
|
||||
readonly request: Readonly<Record<string, unknown>>
|
||||
readonly message: string
|
||||
readonly base: WebSocketChannelDriver
|
||||
readonly continuation?: Shape
|
||||
}
|
||||
|
||||
const checkpointValue = (checkpoint: ChannelCheckpoint | undefined): CheckpointValue | undefined => {
|
||||
@@ -133,26 +127,22 @@ const rejected = (
|
||||
|
||||
export const driver = (input: DriverInput): WebSocketChannelDriver => {
|
||||
const { previous_response_id: _previousResponseID, ...request } = input.request
|
||||
const shape = input.continuation ?? ((fields: Readonly<Record<string, unknown>>) => fields)
|
||||
let output: OpenResponses.StreamItem[] = []
|
||||
return {
|
||||
create: (checkpoint) =>
|
||||
Effect.sync(() => {
|
||||
output = []
|
||||
const previous = checkpointValue(checkpoint)
|
||||
// Ask the route first: diffing the whole history is wasted when it declines the continuation.
|
||||
const fields = previous ? shape(request) : undefined
|
||||
const delta = previous && fields ? incremental(request, previous) : undefined
|
||||
if (!previous || !fields || !delta)
|
||||
return { message: ProviderShared.encodeJson(request), mode: "full" as const }
|
||||
const delta = previous ? incremental(request, previous) : undefined
|
||||
if (!previous || !delta) return { message: ProviderShared.encodeJson(request), mode: "full" as const }
|
||||
return {
|
||||
message: ProviderShared.encodeJson({ ...fields, input: delta, previous_response_id: previous.responseID }),
|
||||
message: ProviderShared.encodeJson({ ...request, input: delta, previous_response_id: previous.responseID }),
|
||||
mode: "incremental" as const,
|
||||
}
|
||||
}),
|
||||
observe: (create, frame) =>
|
||||
Effect.gen(function* () {
|
||||
const event = yield* OpenResponses.decodeChannelEvent(frame).pipe(
|
||||
const event = yield* decodeEvent(frame).pipe(
|
||||
Effect.mapError((cause) =>
|
||||
ProviderShared.eventError(input.id, `Invalid ${input.name} WebSocket event`, frame, cause),
|
||||
),
|
||||
@@ -205,4 +195,4 @@ export const driver = (input: DriverInput): WebSocketChannelDriver => {
|
||||
}
|
||||
}
|
||||
|
||||
export * as OpenResponsesContinuation from "./open-responses-continuation.js"
|
||||
export const OpenResponsesContinuation = { driver } as const
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Effect, Option, Schema, SchemaGetter } from "effect"
|
||||
import { Effect, Option, Schema } from "effect"
|
||||
import type { Content } from "@opencode/schema/tool"
|
||||
import { HttpTransport } from "../route/transport/index.js"
|
||||
import { Protocol } from "../route/protocol.js"
|
||||
@@ -325,8 +325,9 @@ export const StreamItem = Schema.StructWithRest(
|
||||
export type StreamItem = Schema.Schema.Type<typeof StreamItem>
|
||||
export type OutputItem = StreamItem & { readonly id: string }
|
||||
|
||||
// Responses-compatible providers put streaming error details at the top level or
|
||||
// under `error`, and response failures under `response.error`. Accept all three shapes.
|
||||
// The Responses schema puts streaming error details at the top level and
|
||||
// response failures under `response.error`. WebSocket failures use an
|
||||
// event-level `error` envelope, so accept all three shapes here.
|
||||
// https://www.openresponses.org/specification
|
||||
const OpenResponsesErrorPayload = Schema.Struct({
|
||||
type: optionalNull(Schema.String),
|
||||
@@ -400,39 +401,10 @@ export const Event = Schema.StructWithRest(
|
||||
headers: Schema.optional(Schema.Unknown),
|
||||
}),
|
||||
[Schema.Record(Schema.String, Schema.Unknown)],
|
||||
).pipe(
|
||||
Schema.decode({
|
||||
decode: SchemaGetter.transform((event) => {
|
||||
if (event.type !== "error" || event.error != null) return event
|
||||
const { code, message, param, ...rest } = event
|
||||
if (code === undefined && message === undefined && param === undefined) return event
|
||||
// Flat errors (for example, Meta's) can also arrive through generic Responses endpoints.
|
||||
return { ...rest, error: { code, message, param } }
|
||||
}),
|
||||
encode: SchemaGetter.passthrough(),
|
||||
}),
|
||||
)
|
||||
export type Event = Schema.Schema.Type<typeof Event>
|
||||
export type NormalizedEvent = Event & { readonly item?: OutputItem | null }
|
||||
|
||||
const decodeEventValue = Schema.decodeUnknownEffect(Event)
|
||||
const decodeFrame = Schema.decodeUnknownEffect(ProviderShared.Json)
|
||||
|
||||
/**
|
||||
* Decodes one WebSocket frame. xAI answers a rejected `response.create` with `{ "error": { "message", "type" } }` and no
|
||||
* event type; that envelope reads as an error event so the failure classifies instead of failing decoding.
|
||||
*/
|
||||
export const decodeChannelEvent = (frame: string) =>
|
||||
decodeFrame(frame).pipe(
|
||||
Effect.flatMap((value) =>
|
||||
decodeEventValue(
|
||||
ProviderShared.isRecord(value) && value.type === undefined && ProviderShared.isRecord(value.error)
|
||||
? { ...value, type: "error" }
|
||||
: value,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
export interface ProviderAdapter {
|
||||
readonly id: string
|
||||
readonly name: string
|
||||
|
||||
@@ -41,10 +41,6 @@ const responsesRoute = Route.make({
|
||||
id: "openai-responses",
|
||||
name: "xAI Responses",
|
||||
rotateAfterMs: RESPONSES_WEBSOCKET_ROTATE_AFTER_MS,
|
||||
// xAI continues a chain only from stored responses: with `store: false` (the route default) `previous_response_id`
|
||||
// fails with "Response with id=… not found", so those steps are sent in full over the reused connection. It also
|
||||
// rejects `instructions` next to `previous_response_id` and keeps the instructions of the response it continues.
|
||||
continuation: ({ instructions: _instructions, ...request }) => (request.store === false ? undefined : request),
|
||||
}),
|
||||
defaults: { providerOptions: { store: false, include: ["reasoning.encrypted_content"] } },
|
||||
})
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
import { expect } from "bun:test"
|
||||
import { Effect, Schema } from "effect"
|
||||
import { LLM, LLMClient } from "../../src/index.js"
|
||||
import { OpenResponses } from "../../src/protocols/open-responses.js"
|
||||
import { Meta } from "../../src/providers/index.js"
|
||||
import { configure } from "../../src/providers/openai-compatible-responses.js"
|
||||
import { it } from "../lib/effect.js"
|
||||
import { fixedResponse } from "../lib/http.js"
|
||||
import { sseEvents } from "../lib/sse.js"
|
||||
|
||||
const decodeEvent = Schema.decodeUnknownEffect(OpenResponses.protocol.stream.event)
|
||||
|
||||
it.effect("normalizes flat errors in shared SSE and WebSocket decoding", () =>
|
||||
Effect.gen(function* () {
|
||||
const frame = {
|
||||
type: "error",
|
||||
sequence_number: 4,
|
||||
code: "server_shutting_down",
|
||||
message: "Server is shutting down. Please retry your request.",
|
||||
param: null,
|
||||
}
|
||||
for (const decode of [decodeEvent, OpenResponses.decodeChannelEvent]) {
|
||||
const event = yield* decode(JSON.stringify(frame))
|
||||
expect(event).toEqual({
|
||||
type: "error",
|
||||
sequence_number: 4,
|
||||
error: { code: frame.code, message: frame.message, param: null },
|
||||
})
|
||||
|
||||
for (const unchanged of [
|
||||
event,
|
||||
{ type: "error" },
|
||||
{
|
||||
type: "response.failed",
|
||||
response: { id: "resp_failed", error: { code: "server_error", message: "Internal server error" } },
|
||||
},
|
||||
{ type: "response.output_text.delta", item_id: "msg_text", delta: "Hello" },
|
||||
]) {
|
||||
expect(yield* decode(JSON.stringify(unchanged))).toEqual(unchanged)
|
||||
}
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("continues to normalize untyped xAI WebSocket errors", () =>
|
||||
Effect.gen(function* () {
|
||||
const frame = { error: { type: "api_error", message: "gRPC error: Response with id=resp_missing not found" } }
|
||||
expect(yield* OpenResponses.decodeChannelEvent(JSON.stringify(frame))).toEqual({ ...frame, type: "error" })
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("retains classification and original error bodies through Meta and generic Responses routes", () =>
|
||||
Effect.gen(function* () {
|
||||
const raw = `{
|
||||
"type": "error",
|
||||
"sequence_number": 4,
|
||||
"code": "server_shutting_down",
|
||||
"message": "Server is shutting down. Please retry your request.",
|
||||
"param": null,
|
||||
"diagnostic": "retain-original-frame"
|
||||
}`
|
||||
for (const model of [
|
||||
Meta.configure({ apiKey: "fixture" }).responses("muse-spark-1.3"),
|
||||
configure({ apiKey: "fixture", provider: "gateway", baseURL: "https://responses.example.test/v1" }).model(
|
||||
"example-model",
|
||||
),
|
||||
]) {
|
||||
const error = yield* LLMClient.generate(LLM.request({ model, prompt: "Hello" })).pipe(
|
||||
Effect.provide(fixedResponse(sseEvents(raw.replaceAll("\n", "\ndata: ")))),
|
||||
Effect.flip,
|
||||
)
|
||||
expect(error.reason._tag).toBe("ProviderInternal")
|
||||
expect(error.message).toBe("server_shutting_down: Server is shutting down. Please retry your request.")
|
||||
expect(error.reason.body).toBe(raw)
|
||||
expect(error.reason.http?.status).toBe(200)
|
||||
}
|
||||
}),
|
||||
)
|
||||
@@ -90,11 +90,7 @@ const classifyingChannelDriver = (message: string): WebSocketChannelDriver => {
|
||||
}
|
||||
}
|
||||
|
||||
const continuationDriver = (
|
||||
request: Readonly<Record<string, unknown>>,
|
||||
base = baseChannelDriver,
|
||||
continuation?: OpenResponsesContinuation.Shape,
|
||||
) => {
|
||||
const continuationDriver = (request: Readonly<Record<string, unknown>>, base = baseChannelDriver) => {
|
||||
const message = ProviderShared.encodeJson(request)
|
||||
return OpenResponsesContinuation.driver({
|
||||
id: "openai-responses",
|
||||
@@ -102,7 +98,6 @@ const continuationDriver = (
|
||||
request,
|
||||
message,
|
||||
base: base(message),
|
||||
continuation,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -926,58 +921,6 @@ describe("OpenAI Responses route", () => {
|
||||
type: "provider-failure",
|
||||
error: { reason: { _tag: "InvalidRequest", classification: "context-overflow" } },
|
||||
})
|
||||
|
||||
// A retryable failure stays one: the runner retries it, and the transport has already dropped the
|
||||
// checkpoint, so that retry is a full send. xAI reports every rejection this way.
|
||||
const internal = ProviderShared.encodeJson({
|
||||
type: "error",
|
||||
error: { type: "api_error", message: "gRPC error: Response with id=resp_1 not found" },
|
||||
})
|
||||
expect(yield* second.observe(yield* second.create(saved), internal)).toMatchObject({
|
||||
type: "provider-failure",
|
||||
error: { reason: { _tag: "ProviderInternal" } },
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("shapes the incremental send with the route continuation", () =>
|
||||
Effect.gen(function* () {
|
||||
const firstRequest = {
|
||||
type: "response.create",
|
||||
model: "grok-4.6",
|
||||
store: true,
|
||||
instructions: "You are terse.",
|
||||
input: [{ role: "user", content: [{ type: "input_text", text: "First" }] }],
|
||||
}
|
||||
const secondRequest = {
|
||||
...firstRequest,
|
||||
input: [...firstRequest.input, { role: "user", content: [{ type: "input_text", text: "Second" }] }],
|
||||
}
|
||||
const saved = checkpoint(
|
||||
yield* continuationDriver(firstRequest).observe(
|
||||
yield* continuationDriver(firstRequest).create(undefined),
|
||||
ProviderShared.encodeJson({ type: "response.completed", response: { id: "resp_1" } }),
|
||||
),
|
||||
)
|
||||
|
||||
const trimmed = yield* continuationDriver(
|
||||
secondRequest,
|
||||
baseChannelDriver,
|
||||
({ instructions: _, ...rest }) => rest,
|
||||
).create(saved)
|
||||
expect(trimmed.mode).toBe("incremental")
|
||||
expect(JSON.parse(trimmed.message)).toEqual({
|
||||
type: "response.create",
|
||||
model: "grok-4.6",
|
||||
store: true,
|
||||
previous_response_id: "resp_1",
|
||||
input: [{ role: "user", content: [{ type: "input_text", text: "Second" }] }],
|
||||
})
|
||||
|
||||
// Declining the continuation sends the step in full and never sends a previous_response_id.
|
||||
const declined = yield* continuationDriver(secondRequest, baseChannelDriver, () => undefined).create(saved)
|
||||
expect(declined.mode).toBe("full")
|
||||
expect(JSON.parse(declined.message)).toEqual(secondRequest)
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
@@ -1,18 +1,11 @@
|
||||
import { describe, expect } from "bun:test"
|
||||
import { Effect, Layer, Stream } from "effect"
|
||||
import { Effect } from "effect"
|
||||
import { LLM, LLMEvent, Message } from "../../src/index.js"
|
||||
import { XAI } from "../../src/providers.js"
|
||||
import { OpenResponses } from "../../src/protocols/open-responses.js"
|
||||
import { OpenAIResponses } from "../../src/protocols/openai-responses.js"
|
||||
import * as ProviderShared from "../../src/protocols/shared.js"
|
||||
import { XAIResponses } from "../../src/protocols/xai-responses.js"
|
||||
import {
|
||||
LLMClient,
|
||||
RequestExecutor,
|
||||
WebSocketTransport,
|
||||
type ChannelCheckpoint,
|
||||
type WebSocketChannelDriver,
|
||||
} from "../../src/route.js"
|
||||
import { LLMClient } from "../../src/route.js"
|
||||
import { compileRequest } from "../../src/route/client.js"
|
||||
import { it } from "../lib/effect.js"
|
||||
import { fixedResponse } from "../lib/http.js"
|
||||
@@ -20,35 +13,6 @@ import { sseEvents } from "../lib/sse.js"
|
||||
|
||||
const model = XAI.configure({ apiKey: "test", baseURL: "https://api.x.ai/v1" }).responses("grok-4.6")
|
||||
|
||||
/** Runs a request through the WebSocket transport and hands back its channel driver; the HTTP fallback answers. */
|
||||
const channelDriver = (request: ReturnType<typeof LLM.request>) =>
|
||||
Effect.gen(function* () {
|
||||
let driver: WebSocketChannelDriver | undefined
|
||||
yield* LLMClient.generate(request, {
|
||||
webSocket: {
|
||||
execute: (exchange) =>
|
||||
Effect.sync(() => {
|
||||
driver = exchange.driver
|
||||
return { frames: exchange.fallback(), complete: Effect.void }
|
||||
}),
|
||||
},
|
||||
}).pipe(Effect.provide(fixedResponse(sseEvents({ type: "response.completed", response: { id: "http" } }))))
|
||||
if (!driver) throw new Error("Expected a WebSocket channel driver")
|
||||
return driver
|
||||
})
|
||||
|
||||
const completed = (driver: WebSocketChannelDriver, id: string) =>
|
||||
Effect.gen(function* () {
|
||||
const create = yield* driver.create(undefined)
|
||||
yield* driver.observe(create, ProviderShared.encodeJson({ type: "response.created", response: { id } }))
|
||||
const observation = yield* driver.observe(
|
||||
create,
|
||||
ProviderShared.encodeJson({ type: "response.completed", response: { id } }),
|
||||
)
|
||||
if (observation.type !== "completed" || !observation.checkpoint) throw new Error("Expected a checkpoint")
|
||||
return observation.checkpoint
|
||||
})
|
||||
|
||||
describe("xAI Responses route", () => {
|
||||
it.effect("composes the Open Responses baseline with xAI extensions", () =>
|
||||
Effect.gen(function* () {
|
||||
@@ -198,78 +162,6 @@ describe("xAI Responses route", () => {
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("classifies xAI's untyped WebSocket error envelope", () =>
|
||||
Effect.gen(function* () {
|
||||
// xAI answers a rejected response.create with an error envelope that carries no event type.
|
||||
const envelope = ProviderShared.encodeJson({
|
||||
error: {
|
||||
message:
|
||||
'Request validation error: {"code":"400","error":"Argument not supported: instructions and previous_response_id together"}',
|
||||
type: "api_error",
|
||||
},
|
||||
})
|
||||
const webSocket = WebSocketTransport.makeDirect({
|
||||
open: () =>
|
||||
Effect.succeed({ sendText: () => Effect.void, messages: Stream.make(envelope), close: Effect.void }),
|
||||
})
|
||||
const error = yield* LLMClient.generate(LLM.request({ model, prompt: "Hello" }), { webSocket }).pipe(
|
||||
Effect.provide(
|
||||
LLMClient.layer.pipe(
|
||||
Layer.provide(
|
||||
Layer.succeed(
|
||||
RequestExecutor.Service,
|
||||
RequestExecutor.Service.of({ execute: () => Effect.die("unexpected HTTP request") }),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Effect.flip,
|
||||
)
|
||||
|
||||
expect(error.reason._tag).toBe("ProviderInternal")
|
||||
expect(error.message).toContain("Argument not supported: instructions and previous_response_id together")
|
||||
expect(error.reason.body).toBe(envelope)
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("continues stored responses without instructions and sends unstored steps in full", () =>
|
||||
Effect.gen(function* () {
|
||||
const step = (store: boolean, ...prompts: string[]) =>
|
||||
LLM.request({
|
||||
model,
|
||||
system: "You are terse.",
|
||||
messages: prompts.map((prompt) => Message.user(prompt)),
|
||||
providerOptions: { store },
|
||||
})
|
||||
const send = (store: boolean, checkpoint: ChannelCheckpoint) =>
|
||||
channelDriver(step(store, "First", "Second")).pipe(Effect.flatMap((driver) => driver.create(checkpoint)))
|
||||
|
||||
const stored = yield* send(true, yield* completed(yield* channelDriver(step(true, "First")), "resp_1"))
|
||||
expect(stored.mode).toBe("incremental")
|
||||
expect(JSON.parse(stored.message)).toEqual({
|
||||
type: "response.create",
|
||||
model: "grok-4.6",
|
||||
store: true,
|
||||
include: ["reasoning.encrypted_content"],
|
||||
previous_response_id: "resp_1",
|
||||
input: [{ role: "user", content: [{ type: "input_text", text: "Second" }] }],
|
||||
})
|
||||
|
||||
// The connection cache only serves stored responses, so the default store: false never chains.
|
||||
const unstored = yield* send(false, yield* completed(yield* channelDriver(step(false, "First")), "resp_1"))
|
||||
expect(unstored.mode).toBe("full")
|
||||
expect(JSON.parse(unstored.message)).toMatchObject({
|
||||
instructions: "You are terse.",
|
||||
store: false,
|
||||
input: [
|
||||
{ role: "user", content: [{ type: "input_text", text: "First" }] },
|
||||
{ role: "user", content: [{ type: "input_text", text: "Second" }] },
|
||||
],
|
||||
})
|
||||
expect(JSON.parse(unstored.message).previous_response_id).toBeUndefined()
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("parses xAI hosted tool items", () =>
|
||||
Effect.gen(function* () {
|
||||
const item = { type: "x_search_call", id: "x_search_1", status: "completed", action: { query: "news" } }
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
import { expect, test } from "@playwright/test"
|
||||
import { sessionID, setupTimeline, userMessage } from "../performance/timeline-stability/fixture"
|
||||
|
||||
test("keeps a submitted prompt in place while its optimistic rows are measured", async ({ page }) => {
|
||||
await setupTimeline(page, { messages: [userMessage()], seedHistory: true })
|
||||
const release = Promise.withResolvers<void>()
|
||||
await page.route(`**/api/session/${sessionID}/prompt`, async (route) => {
|
||||
if (route.request().method() !== "POST") return route.fallback()
|
||||
await release.promise
|
||||
return route.fallback()
|
||||
})
|
||||
|
||||
const editor = page.locator('[data-component="composer"]').getByRole("textbox")
|
||||
await expect(editor).toBeEditable()
|
||||
await editor.fill("Observe optimistic prompt spacing.")
|
||||
await expect
|
||||
.poll(() =>
|
||||
page.locator("[data-timeline-virtual-content]").evaluate((element) => {
|
||||
const root = element.parentElement!
|
||||
return root.scrollHeight - root.clientHeight - root.scrollTop
|
||||
}),
|
||||
)
|
||||
.toBe(0)
|
||||
|
||||
const observation = await page.evaluateHandle(() => {
|
||||
const frames: { prompt?: number; working: boolean }[] = []
|
||||
let frame = 0
|
||||
const sample = () => {
|
||||
const prompt = [...document.querySelectorAll<HTMLElement>('[data-timeline-row="UserMessage"]')].find((row) =>
|
||||
row.textContent?.includes("Observe optimistic prompt spacing."),
|
||||
)
|
||||
frames.push({
|
||||
...(prompt ? { prompt: prompt.getBoundingClientRect().y } : {}),
|
||||
working: !!document.querySelector('[data-component="session-working"]'),
|
||||
})
|
||||
frame = requestAnimationFrame(sample)
|
||||
}
|
||||
frame = requestAnimationFrame(sample)
|
||||
return {
|
||||
stop: () => {
|
||||
cancelAnimationFrame(frame)
|
||||
return frames
|
||||
},
|
||||
}
|
||||
})
|
||||
const requested = page.waitForRequest(
|
||||
(request) => request.method() === "POST" && new URL(request.url()).pathname === `/api/session/${sessionID}/prompt`,
|
||||
)
|
||||
try {
|
||||
await editor.press("Enter")
|
||||
await requested
|
||||
const prompt = page
|
||||
.locator('[data-timeline-row="UserMessage"]')
|
||||
.filter({ hasText: "Observe optimistic prompt spacing." })
|
||||
await expect(prompt).toBeInViewport()
|
||||
await expect(page.locator('[data-component="session-working"]')).toBeVisible()
|
||||
await expect
|
||||
.poll(() =>
|
||||
page.locator("[data-timeline-virtual-content]").evaluate((element) => {
|
||||
const root = element.parentElement!
|
||||
return root.scrollHeight - root.clientHeight - root.scrollTop
|
||||
}),
|
||||
)
|
||||
.toBe(0)
|
||||
const frames = await observation.evaluate((value) => value.stop())
|
||||
expect(frames.some((frame) => frame.working && frame.prompt === undefined)).toBe(false)
|
||||
const positions = frames.flatMap((frame) => (frame.prompt === undefined ? [] : [frame.prompt]))
|
||||
expect(positions.length).toBeGreaterThan(0)
|
||||
expect(new Set(positions).size).toBe(1)
|
||||
} finally {
|
||||
release.resolve()
|
||||
await observation.dispose()
|
||||
}
|
||||
})
|
||||
@@ -122,15 +122,7 @@ test("renders compaction progress, summary, and outcome in order", async ({ page
|
||||
)
|
||||
await expect(compaction.getByRole("heading", { name: "Checkpoint" })).toBeVisible()
|
||||
await expect(compaction).toContainText("Streamed implementation details.")
|
||||
const running = compaction.getByRole("status").getByLabel("Compacting", { exact: true })
|
||||
await expect(running).toBeVisible()
|
||||
await expect
|
||||
.poll(async () => {
|
||||
const summary = await compaction.locator('[data-component="text-part"]').boundingBox()
|
||||
const status = await running.boundingBox()
|
||||
return !!summary && !!status && status.y >= summary.y + summary.height
|
||||
})
|
||||
.toBe(true)
|
||||
await expect(compaction.getByRole("status").getByLabel("Compacting", { exact: true })).toBeVisible()
|
||||
await expect(compaction.getByText("Session compacted", { exact: true })).toHaveCount(0)
|
||||
|
||||
await timeline.send(
|
||||
|
||||
@@ -88,12 +88,8 @@ export function createComposerSubmit(input: ComposerSubmitInput) {
|
||||
if (value.mode === "normal" && !command) {
|
||||
session.handoff?.set(handoffMessage(value))
|
||||
const optimisticBusy = !input.adapter.working()
|
||||
if (optimisticBusy && input.adapter.kind === "new-session")
|
||||
session.data.session.setStatus(session.id, "running")
|
||||
const sending = sendPrompt(session, value, input.adapter.controls().model.selection.trackSessionCommit, () => {
|
||||
if (optimisticBusy && input.adapter.kind === "active-session")
|
||||
session.data.session.setStatus(session.id, "running")
|
||||
}).then(
|
||||
if (optimisticBusy) session.data.session.setStatus(session.id, "running")
|
||||
const sending = sendPrompt(session, value, input.adapter.controls().model.selection.trackSessionCommit).then(
|
||||
() => ({ ok: true as const }),
|
||||
(error) => ({ ok: false as const, error }),
|
||||
)
|
||||
@@ -126,9 +122,15 @@ export function createComposerSubmit(input: ComposerSubmitInput) {
|
||||
|
||||
if (command) {
|
||||
clearSubmission(input, submission)
|
||||
void sendCommand(session, value, command, input.adapter.controls().model.selection.trackSessionCommit).catch(
|
||||
(error) => failSubmission(input, session, "command", error, restore, value.id),
|
||||
)
|
||||
// Commands always steer: the server applies a command's configured
|
||||
// agent and model immediately at admission, so queueing one would
|
||||
// reconfigure the turn it is supposed to wait behind.
|
||||
void sendCommand(
|
||||
session,
|
||||
{ ...value, delivery: "steer" },
|
||||
command,
|
||||
input.adapter.controls().model.selection.trackSessionCommit,
|
||||
).catch((error) => failSubmission(input, session, "command", error, restore, value.id))
|
||||
return
|
||||
}
|
||||
} finally {
|
||||
@@ -320,8 +322,7 @@ async function sendCommand(
|
||||
track?: ModelSelection["trackSessionCommit"],
|
||||
) {
|
||||
const request = await buildSubmissionRequest(session, value)
|
||||
// Like queued prompts, queued commands must not apply the composer's selection to active work.
|
||||
if (value.delivery === "steer") await applySelection(session, value.selection, track)
|
||||
await applySelection(session, value.selection, track)
|
||||
await session.api.command({
|
||||
sessionID: session.id,
|
||||
command: command.command,
|
||||
@@ -358,8 +359,7 @@ async function applySelection(
|
||||
async function sendPrompt(
|
||||
session: ComposerSession,
|
||||
value: ComposerSubmission,
|
||||
track: ModelSelection["trackSessionCommit"] | undefined,
|
||||
onAdmit: () => void,
|
||||
track?: ModelSelection["trackSessionCommit"],
|
||||
) {
|
||||
const request = await buildSubmissionRequest(session, value)
|
||||
// Switching agent or model reconfigures the session immediately, and with it
|
||||
@@ -389,9 +389,7 @@ async function sendPrompt(
|
||||
},
|
||||
},
|
||||
}
|
||||
const sending = session.data.session.prompt(admission).catch(() => session.data.session.prompt(admission))
|
||||
onAdmit()
|
||||
await sending
|
||||
await session.data.session.prompt(admission).catch(() => session.data.session.prompt(admission))
|
||||
}
|
||||
|
||||
async function buildSubmissionRequest(session: ComposerSession, value: ComposerSubmission) {
|
||||
|
||||
@@ -515,19 +515,6 @@ export function createTimelineVirtualizer(input: Input) {
|
||||
<div
|
||||
ref={(value) => {
|
||||
element = value
|
||||
if (row()._tag !== "UserMessage" || !addedKeys.has(rowProps.rowKey) || !input.pinned() || coldPending)
|
||||
return
|
||||
// The optimistic row can paint before ResizeObserver corrects the tail estimates.
|
||||
// Measure the mounted tail and pin it in this render's microtask instead.
|
||||
queueMicrotask(() => {
|
||||
if (!input.pinned() || !virtualContent?.isConnected) return
|
||||
virtualizer.elementsCache.forEach((item) => {
|
||||
if (item.isConnected) virtualizer.resizeItem(virtualizer.indexFromElement(item), item.offsetHeight)
|
||||
})
|
||||
virtualizer.resizeItem(item().index, element.offsetHeight)
|
||||
virtualContent.style.height = `${virtualizer.getTotalSize()}px`
|
||||
virtualizer.scrollToEnd()
|
||||
})
|
||||
}}
|
||||
data-index={item().index}
|
||||
style={{ "min-height": ready() ? undefined : `${initialItem.size}px` }}
|
||||
|
||||
@@ -47,7 +47,7 @@ const handler = Effect.fn("cli.session.list")(function* (
|
||||
null,
|
||||
2,
|
||||
)
|
||||
: formatList(page.data)) + EOL
|
||||
: formatTable(page.data)) + EOL
|
||||
const write = Effect.tryPromise(
|
||||
() =>
|
||||
new Promise<void>((resolve, reject) => {
|
||||
@@ -96,14 +96,18 @@ export default Runtime.handler(Commands.commands.session.commands.list, (input)
|
||||
),
|
||||
)
|
||||
|
||||
function formatList(sessions: ReadonlyArray<SessionInfo>) {
|
||||
return sessions
|
||||
.map((session) =>
|
||||
[
|
||||
session.id,
|
||||
(session.title ?? "Untitled session").replace(/[\r\n\t]/g, " "),
|
||||
new Date(session.time.updated).toLocaleString(),
|
||||
].join("\t"),
|
||||
)
|
||||
.join(EOL)
|
||||
function formatTable(sessions: ReadonlyArray<SessionInfo>) {
|
||||
const rows = sessions.map((session) => ({
|
||||
id: session.id,
|
||||
title: (session.title ?? "Untitled session").replace(/[\r\n\t]/g, " "),
|
||||
updated: new Date(session.time.updated).toLocaleString(),
|
||||
}))
|
||||
const idWidth = Math.max(20, ...rows.map((row) => row.id.length))
|
||||
const titleWidth = Math.max(25, ...rows.map((row) => row.title.length))
|
||||
const header = `${"Session ID".padEnd(idWidth)} ${"Title".padEnd(titleWidth)} Updated`
|
||||
return [
|
||||
header,
|
||||
"─".repeat(header.length),
|
||||
...rows.map((row) => `${row.id.padEnd(idWidth)} ${row.title.padEnd(titleWidth)} ${row.updated}`),
|
||||
].join(EOL)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import type { RelativePath } from "@opencode/schema/schema"
|
||||
import type { Brand } from "effect"
|
||||
import type { Model } from "@opencode/schema/model"
|
||||
import type { DateTime } from "effect"
|
||||
import type { Permission } from "@opencode/schema/permission"
|
||||
import type { SessionMessage } from "@opencode/schema/session-message"
|
||||
import type { SessionInbox } from "@opencode/schema/session-inbox"
|
||||
import type { PromptInput } from "@opencode/schema/prompt-input"
|
||||
@@ -27,6 +26,7 @@ import type { Integration } from "@opencode/schema/integration"
|
||||
import type { Form } from "@opencode/schema/form"
|
||||
import type { Mcp } from "@opencode/schema/mcp"
|
||||
import type { Credential } from "@opencode/schema/credential"
|
||||
import type { Permission } from "@opencode/schema/permission"
|
||||
import type { PermissionSaved } from "@opencode/schema/permission-saved"
|
||||
import type { FileSystem } from "@opencode/schema/filesystem"
|
||||
import type { Command } from "@opencode/schema/command"
|
||||
@@ -209,7 +209,6 @@ export type SessionCreateInput = {
|
||||
readonly model?: Model.Ref | undefined
|
||||
readonly location?: Location.Ref | undefined
|
||||
readonly metadata?: Session.Metadata | undefined
|
||||
readonly permissions?: Permission.Ruleset | undefined
|
||||
}
|
||||
export type SessionCreateOutput = Session.Info
|
||||
export type SessionCreateOperation<E = never> = (input?: SessionCreateInput) => Effect.Effect<SessionCreateOutput, E>
|
||||
@@ -438,7 +437,6 @@ export type SessionLogOutput =
|
||||
readonly agent?: Agent.ID | undefined
|
||||
readonly model?: Model.Ref | undefined
|
||||
readonly metadata?: Session.Metadata | undefined
|
||||
readonly permissions?: Permission.Ruleset | undefined
|
||||
readonly version: string
|
||||
}
|
||||
}
|
||||
@@ -491,15 +489,6 @@ export type SessionLogOutput =
|
||||
readonly location?: Location.Ref | undefined
|
||||
readonly data: { readonly sessionID: Session.ID; readonly title: string }
|
||||
}
|
||||
| {
|
||||
readonly id: Event.ID
|
||||
readonly created: number
|
||||
readonly metadata?: { readonly [x: string]: unknown } | undefined
|
||||
readonly type: "session.permissions.updated"
|
||||
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
|
||||
readonly location?: Location.Ref | undefined
|
||||
readonly data: { readonly sessionID: Session.ID; readonly permissions: Permission.Ruleset }
|
||||
}
|
||||
| {
|
||||
readonly id: Event.ID
|
||||
readonly created: number
|
||||
@@ -1596,12 +1585,6 @@ export type PermissionReplyOperation<E = never> = (
|
||||
input: PermissionReplyInput,
|
||||
) => Effect.Effect<PermissionReplyOutput, E>
|
||||
|
||||
export type PermissionRulesInput = { readonly sessionID: Session.ID; readonly permissions: Permission.Ruleset }
|
||||
export type PermissionRulesOutput = void
|
||||
export type PermissionRulesOperation<E = never> = (
|
||||
input: PermissionRulesInput,
|
||||
) => Effect.Effect<PermissionRulesOutput, E>
|
||||
|
||||
export interface PermissionApi<E = never> {
|
||||
readonly request: { readonly list: PermissionRequestListOperation<E> }
|
||||
readonly saved: { readonly list: PermissionSavedListOperation<E>; readonly remove: PermissionSavedRemoveOperation<E> }
|
||||
@@ -1609,7 +1592,6 @@ export interface PermissionApi<E = never> {
|
||||
readonly list: PermissionListOperation<E>
|
||||
readonly get: PermissionGetOperation<E>
|
||||
readonly reply: PermissionReplyOperation<E>
|
||||
readonly rules: PermissionRulesOperation<E>
|
||||
}
|
||||
|
||||
export type FileListInput = {
|
||||
|
||||
@@ -181,8 +181,6 @@ import type {
|
||||
PermissionGetOutput,
|
||||
PermissionReplyInput,
|
||||
PermissionReplyOutput,
|
||||
PermissionRulesInput,
|
||||
PermissionRulesOutput,
|
||||
FileListInput,
|
||||
FileListOutput,
|
||||
FileFindInput,
|
||||
@@ -397,7 +395,6 @@ const EndpointSessionCreate = (raw: RawClient["server.session"]) => (input?: Ses
|
||||
model: input?.["model"],
|
||||
location: input?.["location"],
|
||||
metadata: input?.["metadata"],
|
||||
permissions: input?.["permissions"],
|
||||
},
|
||||
}).pipe(
|
||||
Effect.mapError(mapClientError),
|
||||
@@ -1148,14 +1145,6 @@ const EndpointPermissionReply = (raw: RawClient["server.permission"]) => (input:
|
||||
}).pipe(Effect.mapError(mapClientError)),
|
||||
)
|
||||
|
||||
const EndpointPermissionRules = (raw: RawClient["server.permission"]) => (input: PermissionRulesInput) =>
|
||||
preserveEffect<PermissionRulesOutput>()(
|
||||
raw["session.permission.rules"]({
|
||||
params: { sessionID: input["sessionID"] },
|
||||
payload: { permissions: input["permissions"] },
|
||||
}).pipe(Effect.mapError(mapClientError)),
|
||||
)
|
||||
|
||||
const adaptGroupPermission = (raw: RawClient["server.permission"]) => ({
|
||||
request: { list: EndpointPermissionRequestList(raw) },
|
||||
saved: { list: EndpointPermissionSavedList(raw), remove: EndpointPermissionSavedRemove(raw) },
|
||||
@@ -1163,7 +1152,6 @@ const adaptGroupPermission = (raw: RawClient["server.permission"]) => ({
|
||||
list: EndpointPermissionList(raw),
|
||||
get: EndpointPermissionGet(raw),
|
||||
reply: EndpointPermissionReply(raw),
|
||||
rules: EndpointPermissionRules(raw),
|
||||
})
|
||||
|
||||
const EndpointFileList = (raw: RawClient["server.fs"]) => (input?: FileListInput) =>
|
||||
|
||||
@@ -175,8 +175,6 @@ import type {
|
||||
PermissionGetOutput,
|
||||
PermissionReplyInput,
|
||||
PermissionReplyOutput,
|
||||
PermissionRulesInput,
|
||||
PermissionRulesOutput,
|
||||
FileReadInput,
|
||||
FileReadOutput,
|
||||
FileListInput,
|
||||
@@ -567,7 +565,6 @@ export function make(options: ClientOptions) {
|
||||
model: input?.["model"],
|
||||
location: input?.["location"],
|
||||
metadata: input?.["metadata"],
|
||||
permissions: input?.["permissions"],
|
||||
},
|
||||
successStatus: 200,
|
||||
declaredStatuses: [400, 401],
|
||||
@@ -1569,18 +1566,6 @@ export function make(options: ClientOptions) {
|
||||
},
|
||||
requestOptions,
|
||||
),
|
||||
rules: (input: PermissionRulesInput, requestOptions?: RequestOptions) =>
|
||||
request<PermissionRulesOutput>(
|
||||
{
|
||||
method: "PUT",
|
||||
path: `/api/session/${encodeURIComponent(input.sessionID)}/permission/rules`,
|
||||
body: { permissions: input["permissions"] },
|
||||
successStatus: 204,
|
||||
declaredStatuses: [400, 401, 404],
|
||||
empty: true,
|
||||
},
|
||||
requestOptions,
|
||||
),
|
||||
},
|
||||
file: {
|
||||
read: (input: FileReadInput, requestOptions?: RequestOptions) =>
|
||||
|
||||
@@ -551,6 +551,28 @@ export type InstructionEntryInfo = { key: InstructionEntryKey; value: JsonValue
|
||||
|
||||
export type InstructionEntrySnapshot = Array<{ key: InstructionEntryKey; value: JsonValue; removed: boolean }>
|
||||
|
||||
export type SessionCreated = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: { [x: string]: any }
|
||||
type: "session.created"
|
||||
durable: { aggregateID: string; seq: number; version: 1 }
|
||||
location?: LocationRef
|
||||
data: {
|
||||
sessionID: string
|
||||
projectID: string
|
||||
location: LocationRef
|
||||
subpath?: string
|
||||
parentID?: string
|
||||
slug: string
|
||||
title?: string
|
||||
agent?: string
|
||||
model?: ModelRef
|
||||
metadata?: SessionMetadata
|
||||
version: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionAgentSelected = {
|
||||
id: string
|
||||
created: number
|
||||
@@ -1629,6 +1651,24 @@ export type SessionInboxMove = {
|
||||
delivery: SessionInboxDelivery
|
||||
}
|
||||
|
||||
export type SessionInfo = {
|
||||
id: string
|
||||
parentID?: string
|
||||
fork?: { sessionID: string; boundary: SessionForkBoundary }
|
||||
projectID: string
|
||||
agent?: string
|
||||
model?: ModelRef
|
||||
cost: MoneyUSD
|
||||
tokens: TokenUsageInfo
|
||||
outcome?: "succeeded" | "failed" | "interrupted"
|
||||
time: { created: number; updated: number; idle?: number; viewed?: number; archived?: number }
|
||||
title?: string
|
||||
location: LocationRef
|
||||
subpath?: string
|
||||
metadata?: SessionMetadata
|
||||
revert?: SessionRevert
|
||||
}
|
||||
|
||||
export type SessionRevertStaged = {
|
||||
id: string
|
||||
created: number
|
||||
@@ -1872,58 +1912,6 @@ export type AgentInfo = {
|
||||
permissions: PermissionRuleset
|
||||
}
|
||||
|
||||
export type SessionPermissionsUpdated = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: { [x: string]: any }
|
||||
type: "session.permissions.updated"
|
||||
durable: { aggregateID: string; seq: number; version: 1 }
|
||||
location?: LocationRef
|
||||
data: { sessionID: string; permissions: PermissionRuleset }
|
||||
}
|
||||
|
||||
export type SessionInfo = {
|
||||
id: string
|
||||
parentID?: string
|
||||
fork?: { sessionID: string; boundary: SessionForkBoundary }
|
||||
projectID: string
|
||||
agent?: string
|
||||
model?: ModelRef
|
||||
cost: MoneyUSD
|
||||
tokens: TokenUsageInfo
|
||||
outcome?: "succeeded" | "failed" | "interrupted"
|
||||
time: { created: number; updated: number; idle?: number; viewed?: number; archived?: number }
|
||||
title?: string
|
||||
location: LocationRef
|
||||
subpath?: string
|
||||
metadata?: SessionMetadata
|
||||
permissions?: PermissionRuleset
|
||||
revert?: SessionRevert
|
||||
}
|
||||
|
||||
export type SessionCreated = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: { [x: string]: any }
|
||||
type: "session.created"
|
||||
durable: { aggregateID: string; seq: number; version: 1 }
|
||||
location?: LocationRef
|
||||
data: {
|
||||
sessionID: string
|
||||
projectID: string
|
||||
location: LocationRef
|
||||
subpath?: string
|
||||
parentID?: string
|
||||
slug: string
|
||||
title?: string
|
||||
agent?: string
|
||||
model?: ModelRef
|
||||
metadata?: SessionMetadata
|
||||
permissions?: PermissionRuleset
|
||||
version: string
|
||||
}
|
||||
}
|
||||
|
||||
export type ConfigEntry =
|
||||
| {
|
||||
type: "document"
|
||||
@@ -2096,6 +2084,8 @@ export type ConfigEntry =
|
||||
| { type: "agents"; path: string }
|
||||
| { type: "claude"; path: string }
|
||||
|
||||
export type SessionsResponse = { data: Array<SessionInfo>; cursor: { previous?: string | null; next?: string | null } }
|
||||
|
||||
export type SessionInboxUser = {
|
||||
id: string
|
||||
sessionID: string
|
||||
@@ -2150,8 +2140,6 @@ export type FormFields = [FormField, ...Array<FormField>]
|
||||
|
||||
export type FormFields2 = [FormField1, ...Array<FormField1>]
|
||||
|
||||
export type SessionsResponse = { data: Array<SessionInfo>; cursor: { previous?: string | null; next?: string | null } }
|
||||
|
||||
export type SessionInboxInfo = SessionInboxUser | SessionInboxSynthetic | SessionInboxCompaction | SessionInboxMove
|
||||
|
||||
export type SessionInboxEnqueued = {
|
||||
@@ -2245,7 +2233,6 @@ export type SessionEventDurable =
|
||||
| SessionModelSelected
|
||||
| SessionMoved
|
||||
| SessionRenamed
|
||||
| SessionPermissionsUpdated
|
||||
| SessionViewed
|
||||
| SessionDeleted
|
||||
| SessionForked
|
||||
@@ -2305,7 +2292,6 @@ export type V2Event =
|
||||
| SessionModelSelected
|
||||
| SessionMoved
|
||||
| SessionRenamed
|
||||
| SessionPermissionsUpdated
|
||||
| SessionViewed
|
||||
| SessionUsageUpdated
|
||||
| SessionDeleted
|
||||
@@ -2818,11 +2804,6 @@ export type SessionCreateInput = {
|
||||
readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string } | null
|
||||
readonly location?: { readonly directory: string; readonly workspaceID?: string } | null
|
||||
readonly metadata?: { readonly [x: string]: JsonValue } | null
|
||||
readonly permissions?: ReadonlyArray<{
|
||||
readonly action: string
|
||||
readonly resource: string
|
||||
readonly effect: "allow" | "deny" | "ask"
|
||||
}> | null
|
||||
}["id"]
|
||||
readonly title?: {
|
||||
readonly id?: string | null
|
||||
@@ -2831,11 +2812,6 @@ export type SessionCreateInput = {
|
||||
readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string } | null
|
||||
readonly location?: { readonly directory: string; readonly workspaceID?: string } | null
|
||||
readonly metadata?: { readonly [x: string]: JsonValue } | null
|
||||
readonly permissions?: ReadonlyArray<{
|
||||
readonly action: string
|
||||
readonly resource: string
|
||||
readonly effect: "allow" | "deny" | "ask"
|
||||
}> | null
|
||||
}["title"]
|
||||
readonly agent?: {
|
||||
readonly id?: string | null
|
||||
@@ -2844,11 +2820,6 @@ export type SessionCreateInput = {
|
||||
readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string } | null
|
||||
readonly location?: { readonly directory: string; readonly workspaceID?: string } | null
|
||||
readonly metadata?: { readonly [x: string]: JsonValue } | null
|
||||
readonly permissions?: ReadonlyArray<{
|
||||
readonly action: string
|
||||
readonly resource: string
|
||||
readonly effect: "allow" | "deny" | "ask"
|
||||
}> | null
|
||||
}["agent"]
|
||||
readonly model?: {
|
||||
readonly id?: string | null
|
||||
@@ -2857,11 +2828,6 @@ export type SessionCreateInput = {
|
||||
readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string } | null
|
||||
readonly location?: { readonly directory: string; readonly workspaceID?: string } | null
|
||||
readonly metadata?: { readonly [x: string]: JsonValue } | null
|
||||
readonly permissions?: ReadonlyArray<{
|
||||
readonly action: string
|
||||
readonly resource: string
|
||||
readonly effect: "allow" | "deny" | "ask"
|
||||
}> | null
|
||||
}["model"]
|
||||
readonly location?: {
|
||||
readonly id?: string | null
|
||||
@@ -2870,11 +2836,6 @@ export type SessionCreateInput = {
|
||||
readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string } | null
|
||||
readonly location?: { readonly directory: string; readonly workspaceID?: string } | null
|
||||
readonly metadata?: { readonly [x: string]: JsonValue } | null
|
||||
readonly permissions?: ReadonlyArray<{
|
||||
readonly action: string
|
||||
readonly resource: string
|
||||
readonly effect: "allow" | "deny" | "ask"
|
||||
}> | null
|
||||
}["location"]
|
||||
readonly metadata?: {
|
||||
readonly id?: string | null
|
||||
@@ -2883,25 +2844,7 @@ export type SessionCreateInput = {
|
||||
readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string } | null
|
||||
readonly location?: { readonly directory: string; readonly workspaceID?: string } | null
|
||||
readonly metadata?: { readonly [x: string]: JsonValue } | null
|
||||
readonly permissions?: ReadonlyArray<{
|
||||
readonly action: string
|
||||
readonly resource: string
|
||||
readonly effect: "allow" | "deny" | "ask"
|
||||
}> | null
|
||||
}["metadata"]
|
||||
readonly permissions?: {
|
||||
readonly id?: string | null
|
||||
readonly title?: string | null
|
||||
readonly agent?: string | null
|
||||
readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string } | null
|
||||
readonly location?: { readonly directory: string; readonly workspaceID?: string } | null
|
||||
readonly metadata?: { readonly [x: string]: JsonValue } | null
|
||||
readonly permissions?: ReadonlyArray<{
|
||||
readonly action: string
|
||||
readonly resource: string
|
||||
readonly effect: "allow" | "deny" | "ask"
|
||||
}> | null
|
||||
}["permissions"]
|
||||
}
|
||||
|
||||
export type SessionCreateOutput = { data: SessionInfo }["data"]
|
||||
@@ -2939,11 +2882,6 @@ export type SessionImportInput = {
|
||||
readonly location: { readonly directory: string; readonly workspaceID?: string }
|
||||
readonly subpath?: string
|
||||
readonly metadata?: { readonly [x: string]: JsonValue }
|
||||
readonly permissions?: ReadonlyArray<{
|
||||
readonly action: string
|
||||
readonly resource: string
|
||||
readonly effect: "allow" | "deny" | "ask"
|
||||
}>
|
||||
readonly revert?: {
|
||||
readonly messageID: string
|
||||
readonly partID?: string
|
||||
@@ -3249,11 +3187,6 @@ export type SessionImportInput = {
|
||||
readonly location: { readonly directory: string; readonly workspaceID?: string }
|
||||
readonly subpath?: string
|
||||
readonly metadata?: { readonly [x: string]: JsonValue }
|
||||
readonly permissions?: ReadonlyArray<{
|
||||
readonly action: string
|
||||
readonly resource: string
|
||||
readonly effect: "allow" | "deny" | "ask"
|
||||
}>
|
||||
readonly revert?: {
|
||||
readonly messageID: string
|
||||
readonly partID?: string
|
||||
@@ -3559,11 +3492,6 @@ export type SessionImportInput = {
|
||||
readonly location: { readonly directory: string; readonly workspaceID?: string }
|
||||
readonly subpath?: string
|
||||
readonly metadata?: { readonly [x: string]: JsonValue }
|
||||
readonly permissions?: ReadonlyArray<{
|
||||
readonly action: string
|
||||
readonly resource: string
|
||||
readonly effect: "allow" | "deny" | "ask"
|
||||
}>
|
||||
readonly revert?: {
|
||||
readonly messageID: string
|
||||
readonly partID?: string
|
||||
@@ -5825,19 +5753,6 @@ export type PermissionReplyInput = {
|
||||
|
||||
export type PermissionReplyOutput = void
|
||||
|
||||
export type PermissionRulesInput = {
|
||||
readonly sessionID: { readonly sessionID: string }["sessionID"]
|
||||
readonly permissions: {
|
||||
readonly permissions: ReadonlyArray<{
|
||||
readonly action: string
|
||||
readonly resource: string
|
||||
readonly effect: "allow" | "deny" | "ask"
|
||||
}>
|
||||
}["permissions"]
|
||||
}
|
||||
|
||||
export type PermissionRulesOutput = void
|
||||
|
||||
export type FileReadInput = {
|
||||
readonly location?: {
|
||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
||||
|
||||
@@ -695,10 +695,6 @@ export function createData(config: CreateDataInput) {
|
||||
})
|
||||
return
|
||||
}
|
||||
case "session.permissions.updated":
|
||||
if (store.session.info[event.data.sessionID])
|
||||
setStore("session", "info", event.data.sessionID, "permissions", event.data.permissions)
|
||||
return
|
||||
case "session.moved": {
|
||||
const current = store.session.info[event.data.sessionID]
|
||||
if (current) {
|
||||
|
||||
@@ -9,8 +9,7 @@ standard-library surface that programs can use today, plus concrete gaps that ma
|
||||
- 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`).
|
||||
ultimate source of truth.
|
||||
|
||||
## Source and execution model
|
||||
|
||||
@@ -26,10 +25,6 @@ ultimate source of truth. Upstream test262 files run verbatim from `test/test262
|
||||
- [x] The global `search(...)` built-in: synchronous tool discovery that counts as an admitted tool call and is
|
||||
shadowable by program declarations like other globals.
|
||||
- [x] Cooperative timeout, an optional total tool-call limit, output bounding, and unrestricted tool-call concurrency.
|
||||
- [ ] 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
|
||||
|
||||
@@ -69,11 +64,6 @@ ultimate source of truth. Upstream test262 files run verbatim from `test/test262
|
||||
- [x] 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 a key that member access resolves through the owning built-in, such as
|
||||
`const { constructor } = error`, reads `undefined`.
|
||||
- [ ] Member expressions as `for...in` targets (`for (x.y in obj)`).
|
||||
|
||||
## Statements and control flow
|
||||
|
||||
@@ -121,12 +111,6 @@ ultimate source of truth. Upstream test262 files run verbatim from `test/test262
|
||||
- [ ] User-defined constructor calls.
|
||||
- [ ] `Function.prototype.call`, `apply`, and `bind` for CodeMode functions.
|
||||
- [ ] Classes and private fields.
|
||||
- [ ] `name` and `length` properties of functions, including names inferred from bindings and destructuring defaults.
|
||||
- [ ] 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.
|
||||
- [ ] Async generator functions evaluate parameter defaults and destructuring at the first `next()` rather than at the
|
||||
call, so their errors are not thrown synchronously.
|
||||
- [x] 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
|
||||
@@ -170,8 +154,6 @@ ultimate source of truth. Upstream test262 files run verbatim from `test/test262
|
||||
- [x] Plain, arithmetic, bitwise, and logical assignment operators.
|
||||
- [x] Property deletion on plain data objects and arrays, including computed and optional forms; deleting an array index
|
||||
creates a hole without changing its length.
|
||||
- [ ] Operators, `switch` discriminants, and coercion helpers such as `String` and `isNaN` applied to functions and
|
||||
namespaces; JavaScript coerces them, the interpreter rejects non-data operands.
|
||||
|
||||
## Promises and tools
|
||||
|
||||
@@ -244,7 +226,6 @@ ultimate source of truth. Upstream test262 files run verbatim from `test/test262
|
||||
- [x] `Object.is` for supported data values.
|
||||
- [x] `Object.groupBy` over finite collections and custom synchronous iterators/generators, with string-key coercion
|
||||
and null-prototype results.
|
||||
- [ ] `Object.prototype` methods on values: `toString`, `toLocaleString`, `valueOf`, and `hasOwnProperty`.
|
||||
|
||||
## Arrays
|
||||
|
||||
@@ -268,13 +249,6 @@ ultimate source of truth. Upstream test262 files run verbatim from `test/test262
|
||||
`1`; arbitrary array-property assignment remains unsupported.
|
||||
- [x] `Array.prototype.sort` preserves trailing holes, while `toSorted` densifies holes into `undefined` elements,
|
||||
like JavaScript.
|
||||
- [ ] Assigning `length` to truncate or extend an array.
|
||||
- [ ] Non-index own properties on arrays (`arr.foo = 1`, `arr.constructor = null`).
|
||||
- [ ] 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
|
||||
|
||||
@@ -395,6 +369,9 @@ ultimate source of truth. Upstream test262 files run verbatim from `test/test262
|
||||
- [x] `atob` and `btoa` with forgiving-base64 decoding and WebIDL string conversion; invalid input throws an Error
|
||||
named `InvalidCharacterError`, since there is no `DOMException`.
|
||||
- [x] `crypto.randomUUID()`.
|
||||
- [x] `structuredClone` over the data model: objects, arrays with holes, Date, RegExp (`lastIndex` reset), Map, Set,
|
||||
URL, URLSearchParams, and Errors (name, message, and cause only); shared references stay shared within one
|
||||
clone; functions, promises, and tool references throw an Error named `DataCloneError`.
|
||||
- [ ] `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.
|
||||
|
||||
@@ -417,5 +394,3 @@ ultimate source of truth. Upstream test262 files run verbatim from `test/test262
|
||||
- [x] 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 itself carry the generic `Error` name where JavaScript throws a `TypeError`,
|
||||
`RangeError`, or `ReferenceError`, so `e instanceof TypeError` and `e.constructor === TypeError` are false.
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
// Copies the manifest's test262 directories from a local checkout into test/test262, verbatim.
|
||||
// Files needing unsupported flags, features, or harness includes, or whose code crosses one of the
|
||||
// interpreter's intentional boundaries, are not copied, so the vendored tree is exactly what
|
||||
// test/test262.test.ts runs.
|
||||
//
|
||||
// Usage: bun run script/sync-test262.ts /path/to/test262
|
||||
import path from "node:path"
|
||||
import { rm } from "node:fs/promises"
|
||||
|
||||
type Frontmatter = { flags?: Array<string>; features?: Array<string>; includes?: Array<string> }
|
||||
|
||||
const root = path.resolve(import.meta.dir, "../test/test262")
|
||||
const manifest = (await Bun.file(path.join(root, "manifest.json")).json()) as {
|
||||
revision: string
|
||||
directories: Array<string>
|
||||
harness: Array<string>
|
||||
flags: Array<string>
|
||||
features: Array<string>
|
||||
boundaries: Record<string, string>
|
||||
}
|
||||
const boundaries = Object.entries(manifest.boundaries).map(([name, pattern]) => [name, new RegExp(pattern)] as const)
|
||||
const checkout = process.argv[2]
|
||||
if (checkout === undefined) {
|
||||
console.error("usage: bun run script/sync-test262.ts /path/to/test262")
|
||||
process.exit(1)
|
||||
}
|
||||
const head = (await Bun.$`git -C ${checkout} rev-parse HEAD`.text()).trim()
|
||||
if (head !== manifest.revision) {
|
||||
console.error(`checkout is at ${head}; manifest pins ${manifest.revision}`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const excluded = new Map<string, number>()
|
||||
let copied = 0
|
||||
for (const dir of manifest.directories) {
|
||||
await rm(path.join(root, dir), { recursive: true, force: true })
|
||||
const from = path.join(checkout, "test", dir)
|
||||
for await (const file of new Bun.Glob("**/*.js").scan({ cwd: from })) {
|
||||
if (file.endsWith("_FIXTURE.js")) continue
|
||||
const source = await Bun.file(path.join(from, file)).text()
|
||||
const start = source.indexOf("/*---")
|
||||
const end = source.indexOf("---*/", start)
|
||||
const meta = start === -1 ? {} : (Bun.YAML.parse(source.slice(start + 5, end)) as Frontmatter)
|
||||
const code = start === -1 ? source : source.slice(end + 5)
|
||||
const reason =
|
||||
meta.flags?.find((flag) => manifest.flags.includes(flag)) ??
|
||||
meta.features?.find((feature) => manifest.features.includes(feature)) ??
|
||||
meta.includes?.find((include) => !manifest.harness.includes(include)) ??
|
||||
boundaries.find(([, pattern]) => pattern.test(code))?.[0]
|
||||
if (reason !== undefined) {
|
||||
excluded.set(reason, (excluded.get(reason) ?? 0) + 1)
|
||||
continue
|
||||
}
|
||||
await Bun.write(path.join(root, dir, file), Bun.file(path.join(from, file)))
|
||||
copied++
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`copied ${copied} files`)
|
||||
for (const [reason, count] of [...excluded].sort((a, b) => b[1] - a[1])) {
|
||||
console.log(` excluded ${String(count).padStart(5)} ${reason}`)
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
// Runs every vendored test262 file, including skipped ones, and groups failures by cause. Pass
|
||||
// --write to regenerate test/test262/skipped.txt from the current failures.
|
||||
//
|
||||
// Usage: bun run script/test262-report.ts [--write] [path-prefix]
|
||||
import path from "node:path"
|
||||
import { root, run, skipped } from "../test/test262/run.js"
|
||||
|
||||
const write = process.argv.includes("--write")
|
||||
const prefix = process.argv.slice(2).find((arg) => !arg.startsWith("--")) ?? ""
|
||||
const files = [...new Bun.Glob("**/*.js").scanSync({ cwd: root })].filter((file) => file.startsWith(prefix)).sort()
|
||||
|
||||
const failures: Array<{ file: string; reason: string }> = []
|
||||
const recovered: Array<string> = []
|
||||
for (const file of files) {
|
||||
const outcome = await run(file)
|
||||
if (outcome.status === "fail") failures.push({ file, reason: outcome.reason })
|
||||
if (outcome.status === "pass" && skipped.has(file)) recovered.push(file)
|
||||
}
|
||||
|
||||
// Collapse a reason to the part that identifies the cause rather than the test.
|
||||
const bucket = (reason: string) => {
|
||||
const syntax = reason.match(/Syntax '([A-Za-z]+)' is not supported/)
|
||||
if (syntax) return `unsupported syntax ${syntax[1]}`
|
||||
if (reason.startsWith("expected ")) return reason.replace(/ but got .*/, " but the program ran")
|
||||
return reason
|
||||
.replace(/^(\$DONE: |ExecutionFailure: |InvalidDataValue: |ParseError: |Uncaught: |Test262Error: |Error: )+/, "")
|
||||
.replace(/ \(line \d+, col \d+\)/, "")
|
||||
.replace(/^[\w$]+\.(\w+) is not a function/, ".$1 is not a function")
|
||||
.replace(/^[\w$]+ cannot be constructed/, "… cannot be constructed")
|
||||
.replace(/'[^']*'/g, "'…'")
|
||||
.slice(0, 100)
|
||||
}
|
||||
|
||||
const buckets = new Map<string, Array<string>>()
|
||||
for (const failure of failures) {
|
||||
const key = bucket(failure.reason)
|
||||
buckets.set(key, [...(buckets.get(key) ?? []), failure.file])
|
||||
}
|
||||
|
||||
console.log(`${files.length - failures.length} pass, ${failures.length} fail of ${files.length}\n`)
|
||||
for (const [key, list] of [...buckets].sort((a, b) => b[1].length - a[1].length)) {
|
||||
console.log(`${String(list.length).padStart(5)} ${key}`)
|
||||
for (const file of list.slice(0, 3)) console.log(` ${file}`)
|
||||
if (list.length > 3) console.log(` … ${list.length - 3} more`)
|
||||
}
|
||||
if (recovered.length > 0) {
|
||||
console.log(`\n${recovered.length} skipped files pass now; remove them from skipped.txt:`)
|
||||
for (const file of recovered) console.log(` ${file}`)
|
||||
}
|
||||
|
||||
if (write) {
|
||||
const lines = failures.map((failure) => `${failure.file} # ${bucket(failure.reason)}`)
|
||||
await Bun.write(path.join(root, "skipped.txt"), `${lines.join("\n")}\n`)
|
||||
console.log(`\nwrote ${lines.length} entries to skipped.txt`)
|
||||
}
|
||||
@@ -138,6 +138,6 @@ const copy = (value: unknown, label: string, mode: Mode, depth: number, seen: Se
|
||||
|
||||
// Own data property regardless of the target's prototype, so a "__proto__" key on a host object or
|
||||
// array never reaches the Object.prototype setter.
|
||||
const define = (target: object, key: string, value: unknown): void => {
|
||||
export const define = (target: object, key: string, value: unknown): void => {
|
||||
Object.defineProperty(target, key, { value, enumerable: true, writable: true, configurable: true })
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import type { DataValue, Diagnostic, ResolvedExecutionLimits, Result } from "../
|
||||
import { toData } from "../data.js"
|
||||
import { ToolRuntime } from "../tool-runtime.js"
|
||||
import { normalizeError } from "./errors.js"
|
||||
import type { Host } from "./globals.js"
|
||||
import { InterpreterRuntimeError } from "./model.js"
|
||||
import { PromiseRuntime } from "./promises.js"
|
||||
import { Runtime } from "./runtime.js"
|
||||
@@ -17,7 +16,6 @@ export const executeProgram = <R>(
|
||||
prepared: ToolRuntime.Prepared<R>,
|
||||
limits: ResolvedExecutionLimits,
|
||||
hooks: ToolRuntime.ToolCallHooks<R>,
|
||||
extraGlobals?: (host: Host<R>) => ReadonlyArray<readonly [string, unknown]>,
|
||||
): Effect.Effect<Result, never, R> => {
|
||||
if (code.trim().length === 0) {
|
||||
return Effect.succeed({
|
||||
@@ -41,14 +39,7 @@ export const executeProgram = <R>(
|
||||
Effect.gen(function* () {
|
||||
const program = parseProgram(code)
|
||||
const promises = new PromiseRuntime<R>(scope)
|
||||
const value = yield* new Runtime<R>(
|
||||
tools.execute,
|
||||
tools.search,
|
||||
tools.keys,
|
||||
promises,
|
||||
logs,
|
||||
extraGlobals,
|
||||
).run(program)
|
||||
const value = yield* new Runtime<R>(tools.execute, tools.search, tools.keys, promises, logs).run(program)
|
||||
const result = toData(value, "Execution result", "result") as DataValue
|
||||
returned = { value: result, promises }
|
||||
const warnings = yield* promises.interrupt()
|
||||
|
||||
@@ -11,7 +11,7 @@ import { regexpGlobal } from "../stdlib/regexp.js"
|
||||
import { stringGlobal } from "../stdlib/string.js"
|
||||
import { uriGlobal, urlGlobal, urlSearchParamsGlobal } from "../stdlib/url.js"
|
||||
import { coercion, errorConstructors } from "../stdlib/value.js"
|
||||
import { atobGlobal, btoaGlobal, cryptoGlobal } from "../stdlib/web.js"
|
||||
import { atobGlobal, btoaGlobal, cryptoGlobal, structuredCloneGlobal } from "../stdlib/web.js"
|
||||
import { ToolReference } from "../tool-runtime.js"
|
||||
import { errorGlobal } from "./errors.js"
|
||||
import { HostFunction } from "./host.js"
|
||||
@@ -75,5 +75,6 @@ export const globals = <R>(host: Host<R>): ReadonlyArray<readonly [string, unkno
|
||||
["atob", atobGlobal],
|
||||
["btoa", btoaGlobal],
|
||||
["crypto", cryptoGlobal],
|
||||
["structuredClone", structuredCloneGlobal],
|
||||
...[...errorConstructors].map((name) => [name, errorGlobal(name, host.runner)] as const),
|
||||
]
|
||||
|
||||
@@ -66,7 +66,7 @@ import {
|
||||
unsupportedSyntax,
|
||||
} from "./model.js"
|
||||
import { caughtErrorValue } from "./errors.js"
|
||||
import { globals, type Host } from "./globals.js"
|
||||
import { globals } from "./globals.js"
|
||||
import { HostFunction, HostNamespace } from "./host.js"
|
||||
import { invokeIntrinsic } from "./methods.js"
|
||||
import { preserveConsumerError, type Runner } from "./runner.js"
|
||||
@@ -285,7 +285,6 @@ export class Runtime<R> {
|
||||
readonly toolKeys: (path: ReadonlyArray<string>) => ReadonlyArray<string>,
|
||||
readonly promises: PromiseRuntime<R>,
|
||||
readonly logs: Array<string> = [],
|
||||
extraGlobals: (host: Host<R>) => ReadonlyArray<readonly [string, unknown]> = () => [],
|
||||
) {
|
||||
const globalScope = new Map<string, Binding>()
|
||||
// Calling back into the program never reads frame state, so any frame serves; the root is always alive.
|
||||
@@ -296,7 +295,7 @@ export class Runtime<R> {
|
||||
settlePromise: (promise) => this.root.settlePromise(promise),
|
||||
syncIterator: (value, node) => this.root.syncIterator(value, node),
|
||||
}
|
||||
this.builtins = new Map([...globals(this), ...extraGlobals(this)])
|
||||
this.builtins = new Map(globals(this))
|
||||
for (const [name, value] of this.builtins) globalScope.set(name, { mutable: false, value })
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import { define, type SafeObject } from "../data.js"
|
||||
import { HostNamespace, sync } from "../interpreter/host.js"
|
||||
import { InterpreterRuntimeError } from "../interpreter/model.js"
|
||||
import { coerceToString } from "./value.js"
|
||||
import { type AstNode, InterpreterRuntimeError } from "../interpreter/model.js"
|
||||
import { describeValue, isRuntimeReference } from "../interpreter/references.js"
|
||||
import { Values } from "../values.js"
|
||||
import { coerceToString, createErrorValue, errorBrandName } from "./value.js"
|
||||
|
||||
// WebIDL DOMString conversion: a missing argument is a TypeError, anything else stringifies.
|
||||
const base64 = (name: "atob" | "btoa") =>
|
||||
sync(name, (args, node) => {
|
||||
if (args.length === 0)
|
||||
throw new InterpreterRuntimeError(`${name} requires 1 argument (a string)`, node).as("TypeError")
|
||||
if (args.length === 0) {
|
||||
throw new InterpreterRuntimeError(`${name} requires 1 argument, but only 0 were provided.`, node).as("TypeError")
|
||||
}
|
||||
const input = coerceToString(args[0])
|
||||
try {
|
||||
return name === "atob" ? atob(input) : btoa(input)
|
||||
@@ -21,3 +25,56 @@ export const btoaGlobal = base64("btoa")
|
||||
export const cryptoGlobal = new HostNamespace("crypto", {
|
||||
randomUUID: sync("crypto.randomUUID", () => crypto.randomUUID()),
|
||||
})
|
||||
|
||||
// HTML structured clone over the data model: wrappers are copied, shared references stay shared within
|
||||
// one clone, Errors keep only name, message, and cause, and RegExp lastIndex resets like the spec.
|
||||
const cloneValue = (value: unknown, seen: Map<object, unknown>, node: AstNode): unknown => {
|
||||
if (value === null || typeof value !== "object") return value
|
||||
if (value instanceof Values.Promise || (isRuntimeReference(value) && !Values.isValue(value))) {
|
||||
throw new InterpreterRuntimeError(`${describeValue(value)} could not be cloned.`, node).as("DataCloneError")
|
||||
}
|
||||
const existing = seen.get(value)
|
||||
if (existing !== undefined) return existing
|
||||
const remember = <T extends object>(copied: T): T => {
|
||||
seen.set(value, copied)
|
||||
return copied
|
||||
}
|
||||
if (value instanceof Values.Date) return remember(new Values.Date(value.time))
|
||||
if (value instanceof Values.RegExp) return remember(new Values.RegExp(value.regex.source, value.regex.flags))
|
||||
if (value instanceof Values.URL) return remember(new Values.URL(new URL(value.url.href)))
|
||||
if (value instanceof Values.URLSearchParams) {
|
||||
return remember(new Values.URLSearchParams(new URLSearchParams(value.params)))
|
||||
}
|
||||
if (value instanceof Values.Map) {
|
||||
const copied = remember(new Values.Map())
|
||||
for (const [key, item] of value.map) copied.map.set(cloneValue(key, seen, node), cloneValue(item, seen, node))
|
||||
return copied
|
||||
}
|
||||
if (value instanceof Values.Set) {
|
||||
const copied = remember(new Values.Set())
|
||||
for (const item of value.set) copied.set.add(cloneValue(item, seen, node))
|
||||
return copied
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
const copied = remember(new Array<unknown>(value.length))
|
||||
for (const [key, item] of Object.entries(value)) define(copied, key, cloneValue(item, seen, node))
|
||||
return copied
|
||||
}
|
||||
const brand = errorBrandName(value)
|
||||
if (brand !== undefined) {
|
||||
const error = value as { name?: unknown; message?: unknown; cause?: unknown }
|
||||
const copied = remember(createErrorValue(brand, coerceToString(error.message)))
|
||||
if (Object.hasOwn(value, "cause")) copied.cause = cloneValue(error.cause, seen, node)
|
||||
return copied
|
||||
}
|
||||
const copied = remember(Object.create(null) as SafeObject)
|
||||
for (const [key, item] of Object.entries(value)) define(copied, key, cloneValue(item, seen, node))
|
||||
return copied
|
||||
}
|
||||
|
||||
export const structuredCloneGlobal = sync("structuredClone", (args, node) => {
|
||||
if (args.length === 0) {
|
||||
throw new InterpreterRuntimeError("structuredClone requires a value to clone.", node).as("TypeError")
|
||||
}
|
||||
return cloneValue(args[0], new Map(), node)
|
||||
})
|
||||
|
||||
@@ -0,0 +1,245 @@
|
||||
/**
|
||||
* Portions adapted from web-platform-tests at revision 863077959ca8c1a7ceecfbe2534b75d2527b9013:
|
||||
* - html/webappapis/structured-clone/structured-clone-battery-of-tests.js
|
||||
*
|
||||
* Copyright © web-platform-tests contributors. Governed by the 3-Clause BSD license in LICENSE.wpt.
|
||||
*
|
||||
* The battery's `check(description, input, compare)` shape and its `compare_*` helpers are kept, run
|
||||
* inside the interpreter. Ported: primitives, Array/Object of primitives, Date, RegExp, Error, sparse
|
||||
* arrays, identical (shared) property values, and the index-property-plus-length object. Not portable:
|
||||
* boxed primitives, BigInt, Blob/File/ImageData/ArrayBuffer/typed arrays (no binary values), circular
|
||||
* references (rejected at insertion here), property descriptors and prototype properties (no
|
||||
* defineProperty or prototypes), and the throwing-getter case (no getters). `assert_throws_dom` for
|
||||
* `DataCloneError` becomes an `error.name` check.
|
||||
*/
|
||||
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, tools: {} }))
|
||||
if (!result.ok) throw new Error(`expected success, got ${result.error.kind}: ${result.error.message}`)
|
||||
return result.value
|
||||
}
|
||||
|
||||
// The WPT harness, minus async: assertions push a failure description instead of throwing so one run
|
||||
// reports every failing check.
|
||||
const harness = `
|
||||
const failures = []
|
||||
const assert_equals = (a, b, m) => { if (!Object.is(a, b) && !(a !== a && b !== b)) failures.push((m ?? "") + ": " + String(a) + " !== " + String(b)) }
|
||||
const assert_not_equals = (a, b, m) => { if (a === b) failures.push((m ?? "") + ": unexpectedly identical") }
|
||||
const assert_true = (a, m) => { if (a !== true) failures.push((m ?? "") + ": not true") }
|
||||
const assert_false = (a, m) => { if (a !== false) failures.push((m ?? "") + ": not false") }
|
||||
let current = ""
|
||||
function check(description, input, callback) {
|
||||
current = description
|
||||
const newInput = typeof input === "function" ? input() : input
|
||||
const copy = structuredClone(newInput)
|
||||
const before = failures.length
|
||||
callback(copy, newInput)
|
||||
for (let i = before; i < failures.length; i++) failures[i] = description + " — " + failures[i]
|
||||
}
|
||||
function compare_primitive(actual, input) { assert_equals(actual, input) }
|
||||
function compare_Array(callback) {
|
||||
return function (actual, input) {
|
||||
assert_true(Array.isArray(actual), "instanceof Array")
|
||||
assert_not_equals(actual, input)
|
||||
assert_equals(actual.length, input.length, "length")
|
||||
callback(actual, input)
|
||||
}
|
||||
}
|
||||
function compare_Object(callback) {
|
||||
return function (actual, input) {
|
||||
assert_true(actual instanceof Object, "instanceof Object")
|
||||
assert_false(Array.isArray(actual), "instanceof Array")
|
||||
assert_not_equals(actual, input)
|
||||
callback(actual, input)
|
||||
}
|
||||
}
|
||||
function enumerate_props(compare_func) {
|
||||
return function (actual, input) { for (const x in input) compare_func(actual[x], input[x]) }
|
||||
}
|
||||
`
|
||||
|
||||
describe("structuredClone WPT battery", () => {
|
||||
test("primitives, and arrays and objects of primitives", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
${harness}
|
||||
check('primitive undefined', undefined, compare_primitive)
|
||||
check('primitive null', null, compare_primitive)
|
||||
check('primitive true', true, compare_primitive)
|
||||
check('primitive false', false, compare_primitive)
|
||||
check('primitive string, empty string', '', compare_primitive)
|
||||
check('primitive string, lone high surrogate', '\\uD800', compare_primitive)
|
||||
check('primitive string, lone low surrogate', '\\uDC00', compare_primitive)
|
||||
check('primitive string, NUL', '\\u0000', compare_primitive)
|
||||
check('primitive string, astral character', '\\uDBFF\\uDFFD', compare_primitive)
|
||||
check('primitive number, 0.2', 0.2, compare_primitive)
|
||||
check('primitive number, 0', 0, compare_primitive)
|
||||
check('primitive number, -0', -0, compare_primitive)
|
||||
check('primitive number, NaN', NaN, compare_primitive)
|
||||
check('primitive number, Infinity', Infinity, compare_primitive)
|
||||
check('primitive number, -Infinity', -Infinity, compare_primitive)
|
||||
check('primitive number, 9007199254740992', 9007199254740992, compare_primitive)
|
||||
check('primitive number, -9007199254740992', -9007199254740992, compare_primitive)
|
||||
check('primitive number, 9007199254740994', 9007199254740994, compare_primitive)
|
||||
check('primitive number, -9007199254740994', -9007199254740994, compare_primitive)
|
||||
check('Array primitives', [undefined, null, true, false, '', '\\uD800', '\\uDC00', '\\u0000', '\\uDBFF\\uDFFD',
|
||||
0.2, 0, -0, NaN, Infinity, -Infinity, 9007199254740992, -9007199254740992, 9007199254740994, -9007199254740994],
|
||||
compare_Array(enumerate_props(compare_primitive)))
|
||||
check('Object primitives', { 'undefined': undefined, 'null': null, 'true': true, 'false': false, 'empty': '',
|
||||
'high surrogate': '\\uD800', 'low surrogate': '\\uDC00', 'nul': '\\u0000', 'astral': '\\uDBFF\\uDFFD',
|
||||
'0.2': 0.2, '0': 0, '-0': -0, 'NaN': NaN, 'Infinity': Infinity, '-Infinity': -Infinity,
|
||||
'9007199254740992': 9007199254740992, '-9007199254740992': -9007199254740992,
|
||||
'9007199254740994': 9007199254740994, '-9007199254740994': -9007199254740994 },
|
||||
compare_Object(enumerate_props(compare_primitive)))
|
||||
return failures
|
||||
`),
|
||||
).toEqual([])
|
||||
})
|
||||
|
||||
test("Date", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
${harness}
|
||||
function compare_Date(actual, input) {
|
||||
assert_true(actual instanceof Date, 'instanceof Date')
|
||||
assert_equals(Number(actual), Number(input), 'converted to primitive')
|
||||
assert_not_equals(actual, input)
|
||||
}
|
||||
check('Date 0', new Date(0), compare_Date)
|
||||
check('Date -0', new Date(-0), compare_Date)
|
||||
check('Date -8.64e15', new Date(-8.64e15), compare_Date)
|
||||
check('Date 8.64e15', new Date(8.64e15), compare_Date)
|
||||
check('Array Date objects', [new Date(0), new Date(-0), new Date(-8.64e15), new Date(8.64e15)],
|
||||
compare_Array(enumerate_props(compare_Date)))
|
||||
check('Object Date objects', { '0': new Date(0), '-0': new Date(-0), '-8.64e15': new Date(-8.64e15), '8.64e15': new Date(8.64e15) },
|
||||
compare_Object(enumerate_props(compare_Date)))
|
||||
return failures
|
||||
`),
|
||||
).toEqual([])
|
||||
})
|
||||
|
||||
test("RegExp: flags copied, lastIndex reset, source escaped", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
${harness}
|
||||
function compare_RegExp(expected_source) {
|
||||
return function (actual, input) {
|
||||
assert_true(actual instanceof RegExp, 'instanceof RegExp')
|
||||
assert_equals(actual.global, input.global, 'global')
|
||||
assert_equals(actual.ignoreCase, input.ignoreCase, 'ignoreCase')
|
||||
assert_equals(actual.multiline, input.multiline, 'multiline')
|
||||
assert_equals(actual.source, expected_source, 'source')
|
||||
assert_equals(actual.sticky, input.sticky, 'sticky')
|
||||
assert_equals(actual.unicode, input.unicode, 'unicode')
|
||||
assert_equals(actual.lastIndex, 0, 'lastIndex')
|
||||
assert_not_equals(actual, input)
|
||||
}
|
||||
}
|
||||
function func_RegExp_flags_lastIndex() {
|
||||
const r = /foo/gim
|
||||
r.lastIndex = 2
|
||||
return r
|
||||
}
|
||||
function func_RegExp_sticky() { return new RegExp('foo', 'y') }
|
||||
function func_RegExp_unicode() { return new RegExp('foo', 'u') }
|
||||
check('RegExp flags and lastIndex', func_RegExp_flags_lastIndex, compare_RegExp('foo'))
|
||||
check('RegExp sticky flag', func_RegExp_sticky, compare_RegExp('foo'))
|
||||
check('RegExp unicode flag', func_RegExp_unicode, compare_RegExp('foo'))
|
||||
check('RegExp empty', new RegExp(''), compare_RegExp('(?:)'))
|
||||
check('RegExp slash', new RegExp('/'), compare_RegExp('\\\\/'))
|
||||
check('RegExp new line', new RegExp('\\n'), compare_RegExp('\\\\n'))
|
||||
check('Array RegExp object, RegExp flags and lastIndex', [func_RegExp_flags_lastIndex()], compare_Array(enumerate_props(compare_RegExp('foo'))))
|
||||
check('Array RegExp object, RegExp sticky flag', function () { return [func_RegExp_sticky()] }, compare_Array(enumerate_props(compare_RegExp('foo'))))
|
||||
check('Array RegExp object, RegExp unicode flag', function () { return [func_RegExp_unicode()] }, compare_Array(enumerate_props(compare_RegExp('foo'))))
|
||||
check('Array RegExp object, RegExp empty', [new RegExp('')], compare_Array(enumerate_props(compare_RegExp('(?:)'))))
|
||||
check('Array RegExp object, RegExp slash', [new RegExp('/')], compare_Array(enumerate_props(compare_RegExp('\\\\/'))))
|
||||
check('Array RegExp object, RegExp new line', [new RegExp('\\n')], compare_Array(enumerate_props(compare_RegExp('\\\\n'))))
|
||||
check('Object RegExp object, RegExp flags and lastIndex', { 'x': func_RegExp_flags_lastIndex() }, compare_Object(enumerate_props(compare_RegExp('foo'))))
|
||||
check('Object RegExp object, RegExp sticky flag', function () { return { 'x': func_RegExp_sticky() } }, compare_Object(enumerate_props(compare_RegExp('foo'))))
|
||||
check('Object RegExp object, RegExp unicode flag', function () { return { 'x': func_RegExp_unicode() } }, compare_Object(enumerate_props(compare_RegExp('foo'))))
|
||||
check('Object RegExp object, RegExp empty', { 'x': new RegExp('') }, compare_Object(enumerate_props(compare_RegExp('(?:)'))))
|
||||
check('Object RegExp object, RegExp slash', { 'x': new RegExp('/') }, compare_Object(enumerate_props(compare_RegExp('\\\\/'))))
|
||||
check('Object RegExp object, RegExp new line', { 'x': new RegExp('\\n') }, compare_Object(enumerate_props(compare_RegExp('\\\\n'))))
|
||||
return failures
|
||||
`),
|
||||
).toEqual([])
|
||||
})
|
||||
|
||||
test("Error: name and message kept, custom properties dropped", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
${harness}
|
||||
function compare_Error(actual, input) {
|
||||
assert_true(actual instanceof Error, "Checking instanceof")
|
||||
assert_equals(actual.name, input.name, "Checking name")
|
||||
assert_equals(Object.hasOwn(actual, "message"), Object.hasOwn(input, "message"), "Checking message existence")
|
||||
assert_equals(actual.message, input.message, "Checking message")
|
||||
assert_equals(actual.foo, undefined, "Checking for absence of custom property")
|
||||
}
|
||||
check('Empty Error object', new Error(), compare_Error)
|
||||
for (const constructor of [Error, RangeError, ReferenceError, SyntaxError, TypeError, URIError]) {
|
||||
check(constructor.name, () => {
|
||||
const error = new constructor("Error message here")
|
||||
error.foo = "testing"
|
||||
return error
|
||||
}, compare_Error)
|
||||
}
|
||||
return failures
|
||||
`),
|
||||
).toEqual([])
|
||||
})
|
||||
|
||||
test("sparse arrays, index-property objects, and identical property values", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
${harness}
|
||||
check('Array sparse', new Array(10), compare_Array(enumerate_props(compare_primitive)))
|
||||
check('Object with index property and length', { '0': 'foo', 'length': 1 }, compare_Object(enumerate_props(compare_primitive)))
|
||||
function check_identical_property_values(prop1, prop2) {
|
||||
return function (actual) { assert_equals(actual[prop1], actual[prop2]) }
|
||||
}
|
||||
check('Array with identical property values', function () {
|
||||
const obj = {}
|
||||
return [obj, obj]
|
||||
}, compare_Array(check_identical_property_values('0', '1')))
|
||||
check('Object with identical property values', function () {
|
||||
const obj = {}
|
||||
return { 'x': obj, 'y': obj }
|
||||
}, compare_Object(check_identical_property_values('x', 'y')))
|
||||
return failures
|
||||
`),
|
||||
).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
describe("structuredClone beyond the WPT battery", () => {
|
||||
test("Map, Set, URL, and URLSearchParams are copied, with shared references preserved across containers", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
const shared = { n: 1 }
|
||||
const input = { m: new Map([[shared, shared]]), s: new Set([shared]), u: new URL("https://a.b/c?d=1") }
|
||||
const copy = structuredClone(input)
|
||||
const [[key, item]] = [...copy.m]
|
||||
copy.u.searchParams.set("d", "2")
|
||||
return [
|
||||
copy.m !== input.m, key !== shared, key === item, key === [...copy.s][0],
|
||||
copy.u !== input.u, input.u.href, copy.u.href,
|
||||
]
|
||||
`),
|
||||
).toEqual([true, true, true, true, true, "https://a.b/c?d=1", "https://a.b/c?d=2"])
|
||||
})
|
||||
|
||||
test("functions, promises, and tool references throw DataCloneError", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
return [() => 1, Promise.resolve(1), tools, Math, { nested: [() => 1] }].map((input) => {
|
||||
try { structuredClone(input); return "cloned" } catch (error) { return error.name }
|
||||
})
|
||||
`),
|
||||
).toEqual(Array(5).fill("DataCloneError"))
|
||||
expect(await value(`try { structuredClone() } catch (error) { return error.name }`)).toBe("TypeError")
|
||||
})
|
||||
})
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Runs the test262 files vendored under test/test262 (see test/test262/README.md) verbatim.
|
||||
* Files listed in test/test262/skipped.txt fail on a known interpreter gap and are skipped;
|
||||
* `bun run script/test262-report.ts` shows current gaps and which skipped files pass again.
|
||||
* Licensed under test/LICENSE.test262.
|
||||
*/
|
||||
import { test } from "bun:test"
|
||||
import { root, run, skipped } from "./test262/run.js"
|
||||
|
||||
for (const file of [...new Bun.Glob("**/*.js").scanSync({ cwd: root })].sort()) {
|
||||
const define = skipped.has(file) ? test.skip : test
|
||||
define(
|
||||
file,
|
||||
async () => {
|
||||
const outcome = await run(file)
|
||||
if (outcome.status === "fail") throw new Error(outcome.reason)
|
||||
},
|
||||
10_000,
|
||||
)
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
# test262
|
||||
|
||||
Upstream [test262](https://github.com/tc39/test262) files, vendored byte-for-byte and run verbatim by
|
||||
`test/test262.test.ts`. Licensed under `test/LICENSE.test262`.
|
||||
|
||||
## Layout
|
||||
|
||||
- `manifest.json` — the pinned upstream revision, which upstream directories are vendored, and what is left out.
|
||||
- `built-ins/`, `language/` — the vendored files, mirroring upstream `test/`.
|
||||
- `skipped.txt` — vendored files that fail on a known interpreter gap, one `path # reason` per line. They are
|
||||
skipped, and each gap is listed as unchecked in `interpreter-support.md`.
|
||||
- `run.ts` — runs one file: prepends `"use strict"`, provides the harness (`assert`, `Test262Error`,
|
||||
`compareArray`, `$DONE`, `$DONOTEVALUATE`) as host globals, and interprets the file's frontmatter (`negative`,
|
||||
`flags: [async]`).
|
||||
|
||||
## What is not vendored
|
||||
|
||||
`script/sync-test262.ts` skips a file when its frontmatter declares a `flags`, `features`, or `includes` value the
|
||||
manifest marks unsupported, or when its code matches one of the manifest's `boundaries` patterns. Boundaries are
|
||||
intentional limits of the interpreter, not compatibility work: classes, `this`, `arguments`, prototype objects,
|
||||
property descriptors, accessors, boxed primitives, sloppy mode, `eval`, `Symbol()`, and the `$262` host API. If one
|
||||
of those decisions changes, delete its entry and re-sync; the tests are upstream, not lost.
|
||||
|
||||
## Commands
|
||||
|
||||
```sh
|
||||
bun run script/sync-test262.ts /path/to/test262 # re-copy at the pinned revision; edit manifest.json to change scope
|
||||
bun run script/test262-report.ts [--write] [dir] # run everything, group failures by cause; --write regenerates skipped.txt
|
||||
bun test test/test262.test.ts # what CI runs
|
||||
```
|
||||
|
||||
When a fix makes skipped files pass, the report lists them so they can be removed from `skipped.txt`, and the
|
||||
matching gap in `interpreter-support.md` is checked in the same change.
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
// Copyright (C) 2016 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.concat
|
||||
description: >
|
||||
Behavior when `constructor` property is neither an Object nor undefined
|
||||
info: |
|
||||
1. Let O be ? ToObject(this value).
|
||||
2. Let A be ? ArraySpeciesCreate(O, 0).
|
||||
|
||||
9.4.2.3 ArraySpeciesCreate
|
||||
|
||||
[...]
|
||||
5. Let C be ? Get(originalArray, "constructor").
|
||||
[...]
|
||||
9. If IsConstructor(C) is false, throw a TypeError exception.
|
||||
---*/
|
||||
|
||||
var a = [];
|
||||
|
||||
a.constructor = null;
|
||||
assert.throws(TypeError, function() {
|
||||
a.concat();
|
||||
}, 'a.concat() throws a TypeError exception');
|
||||
|
||||
a = [];
|
||||
a.constructor = 1;
|
||||
assert.throws(TypeError, function() {
|
||||
a.concat();
|
||||
}, 'a.concat() throws a TypeError exception');
|
||||
|
||||
a = [];
|
||||
a.constructor = 'string';
|
||||
assert.throws(TypeError, function() {
|
||||
a.concat();
|
||||
}, 'a.concat() throws a TypeError exception');
|
||||
|
||||
a = [];
|
||||
a.constructor = true;
|
||||
assert.throws(TypeError, function() {
|
||||
a.concat();
|
||||
}, 'a.concat() throws a TypeError exception');
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.copywithin
|
||||
description: >
|
||||
end argument is coerced to an integer values.
|
||||
info: |
|
||||
22.1.3.3 Array.prototype.copyWithin (target, start [ , end ] )
|
||||
|
||||
...
|
||||
11. If end is undefined, let relativeEnd be len; else let relativeEnd be
|
||||
ToInteger(end).
|
||||
...
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(1, 0, null), [0, 1, 2, 3],
|
||||
'[0, 1, 2, 3].copyWithin(1, 0, null) must return [0, 1, 2, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(1, 0, NaN), [0, 1, 2, 3],
|
||||
'[0, 1, 2, 3].copyWithin(1, 0, NaN) must return [0, 1, 2, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(1, 0, false), [0, 1, 2, 3],
|
||||
'[0, 1, 2, 3].copyWithin(1, 0, false) must return [0, 1, 2, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(1, 0, true), [0, 0, 2, 3],
|
||||
'[0, 1, 2, 3].copyWithin(1, 0, true) must return [0, 0, 2, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(1, 0, '-2'), [0, 0, 1, 3],
|
||||
'[0, 1, 2, 3].copyWithin(1, 0, "-2") must return [0, 0, 1, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(1, 0, -2.5), [0, 0, 1, 3],
|
||||
'[0, 1, 2, 3].copyWithin(1, 0, -2.5) must return [0, 0, 1, 3]'
|
||||
);
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
// Copyright (C) 2019 Google. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.copywithin
|
||||
description: >
|
||||
SECURITY: start argument is coerced to an integer value
|
||||
and side effects change the length of the array so that
|
||||
the target is out of bounds
|
||||
info: |
|
||||
22.1.3.3 Array.prototype.copyWithin (target, start [ , end ] )
|
||||
|
||||
...
|
||||
8. Let relativeStart be ToInteger(start).
|
||||
...
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
|
||||
// make a long integer Array
|
||||
function longDenseArray(){
|
||||
var a = [0];
|
||||
for(var i = 0; i < 1024; i++){
|
||||
a[i] = i;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
function shorten(){
|
||||
currArray.length = 20;
|
||||
return 1;
|
||||
}
|
||||
|
||||
var array = longDenseArray();
|
||||
array.length = 20;
|
||||
for(var i = 0; i < 19; i++){
|
||||
array[i+1000] = array[i+1];
|
||||
}
|
||||
|
||||
var currArray = longDenseArray();
|
||||
|
||||
assert.compareArray(
|
||||
currArray.copyWithin(1000, {valueOf: shorten}), array,
|
||||
'currArray.copyWithin(1000, {valueOf: shorten}) returns array'
|
||||
);
|
||||
Vendored
-56
@@ -1,56 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.copywithin
|
||||
description: >
|
||||
start argument is coerced to an integer value.
|
||||
info: |
|
||||
22.1.3.3 Array.prototype.copyWithin (target, start [ , end ] )
|
||||
|
||||
...
|
||||
8. Let relativeStart be ToInteger(start).
|
||||
...
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(1, undefined), [0, 0, 1, 2],
|
||||
'[0, 1, 2, 3].copyWithin(1, undefined) must return [0, 0, 1, 2]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(1, false), [0, 0, 1, 2],
|
||||
'[0, 1, 2, 3].copyWithin(1, false) must return [0, 0, 1, 2]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(1, NaN), [0, 0, 1, 2],
|
||||
'[0, 1, 2, 3].copyWithin(1, NaN) must return [0, 0, 1, 2]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(1, null), [0, 0, 1, 2],
|
||||
'[0, 1, 2, 3].copyWithin(1, null) must return [0, 0, 1, 2]'
|
||||
);
|
||||
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(0, true), [1, 2, 3, 3],
|
||||
'[0, 1, 2, 3].copyWithin(0, true) must return [1, 2, 3, 3]'
|
||||
);
|
||||
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(0, '1'), [1, 2, 3, 3],
|
||||
'[0, 1, 2, 3].copyWithin(0, "1") must return [1, 2, 3, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(1, 0.5), [0, 0, 1, 2],
|
||||
'[0, 1, 2, 3].copyWithin(1, 0.5) must return [0, 0, 1, 2]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(0, 1.5), [1, 2, 3, 3],
|
||||
'[0, 1, 2, 3].copyWithin(0, 1.5) must return [1, 2, 3, 3]'
|
||||
);
|
||||
Vendored
-61
@@ -1,61 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.copywithin
|
||||
description: >
|
||||
target argument is coerced to an integer value.
|
||||
info: |
|
||||
22.1.3.3 Array.prototype.copyWithin (target, start [ , end ] )
|
||||
|
||||
...
|
||||
5. Let relativeTarget be ToInteger(target).
|
||||
...
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(undefined, 1), [1, 2, 3, 3],
|
||||
'[0, 1, 2, 3].copyWithin(undefined, 1) must return [1, 2, 3, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(false, 1), [1, 2, 3, 3],
|
||||
'[0, 1, 2, 3].copyWithin(false, 1) must return [1, 2, 3, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(NaN, 1), [1, 2, 3, 3],
|
||||
'[0, 1, 2, 3].copyWithin(NaN, 1) must return [1, 2, 3, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(null, 1), [1, 2, 3, 3],
|
||||
'[0, 1, 2, 3].copyWithin(null, 1) must return [1, 2, 3, 3]'
|
||||
);
|
||||
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(true, 0), [0, 0, 1, 2],
|
||||
'[0, 1, 2, 3].copyWithin(true, 0) must return [0, 0, 1, 2]'
|
||||
);
|
||||
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin('1', 0), [0, 0, 1, 2],
|
||||
'[0, 1, 2, 3].copyWithin("1", 0) must return [0, 0, 1, 2]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(0.5, 1), [1, 2, 3, 3],
|
||||
'[0, 1, 2, 3].copyWithin(0.5, 1) must return [1, 2, 3, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(1.5, 0), [0, 0, 1, 2],
|
||||
'[0, 1, 2, 3].copyWithin(1.5, 0) must return [0, 0, 1, 2]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin({}, 1), [1, 2, 3, 3],
|
||||
'[0, 1, 2, 3].copyWithin({}, 1) must return [1, 2, 3, 3]'
|
||||
);
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.copywithin
|
||||
description: >
|
||||
Loop from each property, even empty holes.
|
||||
---*/
|
||||
|
||||
var arr = [0, 1, , , 1];
|
||||
|
||||
arr.copyWithin(0, 1, 4);
|
||||
|
||||
assert.sameValue(arr.length, 5);
|
||||
assert.sameValue(arr[0], 1);
|
||||
assert.sameValue(arr[4], 1);
|
||||
assert.sameValue(arr.hasOwnProperty(1), false);
|
||||
assert.sameValue(arr.hasOwnProperty(2), false);
|
||||
assert.sameValue(arr.hasOwnProperty(3), false);
|
||||
-58
@@ -1,58 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.copywithin
|
||||
description: >
|
||||
Set values with negative end argument.
|
||||
info: |
|
||||
22.1.3.3 Array.prototype.copyWithin (target, start [ , end ] )
|
||||
|
||||
...
|
||||
11. If end is undefined, let relativeEnd be len; else let relativeEnd be
|
||||
ToInteger(end).
|
||||
12. ReturnIfAbrupt(relativeEnd).
|
||||
13. If relativeEnd < 0, let final be max((len + relativeEnd),0); else let
|
||||
final be min(relativeEnd, len).
|
||||
...
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(0, 1, -1), [1, 2, 2, 3],
|
||||
'[0, 1, 2, 3].copyWithin(0, 1, -1) must return [1, 2, 2, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4].copyWithin(2, 0, -1), [0, 1, 0, 1, 2],
|
||||
'[0, 1, 2, 3, 4].copyWithin(2, 0, -1) must return [0, 1, 0, 1, 2]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4].copyWithin(1, 2, -2), [0, 2, 2, 3, 4],
|
||||
'[0, 1, 2, 3, 4].copyWithin(1, 2, -2) must return [0, 2, 2, 3, 4]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(0, -2, -1), [2, 1, 2, 3],
|
||||
'[0, 1, 2, 3].copyWithin(0, -2, -1) must return [2, 1, 2, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4].copyWithin(2, -2, -1), [0, 1, 3, 3, 4],
|
||||
'[0, 1, 2, 3, 4].copyWithin(2, -2, -1) must return [0, 1, 3, 3, 4]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(-3, -2, -1), [0, 2, 2, 3],
|
||||
'[0, 1, 2, 3].copyWithin(-3, -2, -1) must return [0, 2, 2, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4].copyWithin(-2, -3, -1), [0, 1, 2, 2, 3],
|
||||
'[0, 1, 2, 3, 4].copyWithin(-2, -3, -1) must return [0, 1, 2, 2, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4].copyWithin(-5, -2, -1), [3, 1, 2, 3, 4],
|
||||
'[0, 1, 2, 3, 4].copyWithin(-5, -2, -1) must return [3, 1, 2, 3, 4]'
|
||||
);
|
||||
Vendored
-68
@@ -1,68 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.copywithin
|
||||
description: >
|
||||
Set values with negative out of bounds end argument.
|
||||
info: |
|
||||
22.1.3.3 Array.prototype.copyWithin (target, start [ , end ] )
|
||||
|
||||
...
|
||||
11. If end is undefined, let relativeEnd be len; else let relativeEnd be
|
||||
ToInteger(end).
|
||||
12. ReturnIfAbrupt(relativeEnd).
|
||||
13. If relativeEnd < 0, let final be max((len + relativeEnd),0); else let
|
||||
final be min(relativeEnd, len).
|
||||
...
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(0, 1, -10), [0, 1, 2, 3],
|
||||
'[0, 1, 2, 3].copyWithin(0, 1, -10) must return [0, 1, 2, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[1, 2, 3, 4, 5].copyWithin(0, 1, -Infinity), [1, 2, 3, 4, 5],
|
||||
'[1, 2, 3, 4, 5].copyWithin(0, 1, -Infinity) must return [1, 2, 3, 4, 5]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(0, -2, -10), [0, 1, 2, 3],
|
||||
'[0, 1, 2, 3].copyWithin(0, -2, -10) must return [0, 1, 2, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[1, 2, 3, 4, 5].copyWithin(0, -2, -Infinity), [1, 2, 3, 4, 5],
|
||||
'[1, 2, 3, 4, 5].copyWithin(0, -2, -Infinity) must return [1, 2, 3, 4, 5]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(0, -9, -10), [0, 1, 2, 3],
|
||||
'[0, 1, 2, 3].copyWithin(0, -9, -10) must return [0, 1, 2, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[1, 2, 3, 4, 5].copyWithin(0, -9, -Infinity), [1, 2, 3, 4, 5],
|
||||
'[1, 2, 3, 4, 5].copyWithin(0, -9, -Infinity) must return [1, 2, 3, 4, 5]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(-3, -2, -10), [0, 1, 2, 3],
|
||||
'[0, 1, 2, 3].copyWithin(-3, -2, -10) must return [0, 1, 2, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[1, 2, 3, 4, 5].copyWithin(-3, -2, -Infinity), [1, 2, 3, 4, 5],
|
||||
'[1, 2, 3, 4, 5].copyWithin(-3, -2, -Infinity) must return [1, 2, 3, 4, 5]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(-7, -8, -9), [0, 1, 2, 3],
|
||||
'[0, 1, 2, 3].copyWithin(-7, -8, -9) must return [0, 1, 2, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[1, 2, 3, 4, 5].copyWithin(-7, -8, -Infinity), [1, 2, 3, 4, 5],
|
||||
'[1, 2, 3, 4, 5].copyWithin(-7, -8, -Infinity) must return [1, 2, 3, 4, 5]'
|
||||
);
|
||||
Vendored
-57
@@ -1,57 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.copywithin
|
||||
description: >
|
||||
Set values with out of bounds negative start argument.
|
||||
info: |
|
||||
22.1.3.3 Array.prototype.copyWithin (target, start [ , end ] )
|
||||
|
||||
...
|
||||
10. If relativeStart < 0, let from be max((len + relativeStart),0); else let
|
||||
from be min(relativeStart, len).
|
||||
...
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(0, -10), [0, 1, 2, 3],
|
||||
'[0, 1, 2, 3].copyWithin(0, -10) must return [0, 1, 2, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[1, 2, 3, 4, 5].copyWithin(0, -Infinity), [1, 2, 3, 4, 5],
|
||||
'[1, 2, 3, 4, 5].copyWithin(0, -Infinity) must return [1, 2, 3, 4, 5]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4].copyWithin(2, -10), [0, 1, 0, 1, 2],
|
||||
'[0, 1, 2, 3, 4].copyWithin(2, -10) must return [0, 1, 0, 1, 2]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[1, 2, 3, 4, 5].copyWithin(2, -Infinity), [1, 2, 1, 2, 3],
|
||||
'[1, 2, 3, 4, 5].copyWithin(2, -Infinity) must return [1, 2, 1, 2, 3]'
|
||||
);
|
||||
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4].copyWithin(10, -10), [0, 1, 2, 3, 4],
|
||||
'[0, 1, 2, 3, 4].copyWithin(10, -10) must return [0, 1, 2, 3, 4]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[1, 2, 3, 4, 5].copyWithin(10, -Infinity), [1, 2, 3, 4, 5],
|
||||
'[1, 2, 3, 4, 5].copyWithin(10, -Infinity) must return [1, 2, 3, 4, 5]'
|
||||
);
|
||||
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(-9, -10), [0, 1, 2, 3],
|
||||
'[0, 1, 2, 3].copyWithin(-9, -10) must return [0, 1, 2, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[1, 2, 3, 4, 5].copyWithin(-9, -Infinity), [1, 2, 3, 4, 5],
|
||||
'[1, 2, 3, 4, 5].copyWithin(-9, -Infinity) must return [1, 2, 3, 4, 5]'
|
||||
);
|
||||
packages/codemode/test/test262/built-ins/Array/prototype/copyWithin/negative-out-of-bounds-target.js
Vendored
-35
@@ -1,35 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.copywithin
|
||||
description: >
|
||||
Set values with out of bounds negative target argument.
|
||||
info: |
|
||||
22.1.3.3 Array.prototype.copyWithin (target, start [ , end ] )
|
||||
|
||||
...
|
||||
7. If relativeTarget < 0, let to be max((len + relativeTarget),0); else let to
|
||||
be min(relativeTarget, len).
|
||||
...
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(-10, 0), [0, 1, 2, 3],
|
||||
'[0, 1, 2, 3].copyWithin(-10, 0) must return [0, 1, 2, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[1, 2, 3, 4, 5].copyWithin(-Infinity, 0), [1, 2, 3, 4, 5],
|
||||
'[1, 2, 3, 4, 5].copyWithin(-Infinity, 0) must return [1, 2, 3, 4, 5]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4].copyWithin(-10, 2), [2, 3, 4, 3, 4],
|
||||
'[0, 1, 2, 3, 4].copyWithin(-10, 2) must return [2, 3, 4, 3, 4]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[1, 2, 3, 4, 5].copyWithin(-Infinity, 2), [3, 4, 5, 4, 5],
|
||||
'[1, 2, 3, 4, 5].copyWithin(-Infinity, 2) must return [3, 4, 5, 4, 5]'
|
||||
);
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.copywithin
|
||||
description: >
|
||||
Set values with negative start argument.
|
||||
info: |
|
||||
22.1.3.3 Array.prototype.copyWithin (target, start [ , end ] )
|
||||
|
||||
...
|
||||
10. If relativeStart < 0, let from be max((len + relativeStart),0); else let
|
||||
from be min(relativeStart, len).
|
||||
...
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(0, -1), [3, 1, 2, 3],
|
||||
'[0, 1, 2, 3].copyWithin(0, -1) must return [3, 1, 2, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4].copyWithin(2, -2), [0, 1, 3, 4, 4],
|
||||
'[0, 1, 2, 3, 4].copyWithin(2, -2) must return [0, 1, 3, 4, 4]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4].copyWithin(1, -2), [0, 3, 4, 3, 4],
|
||||
'[0, 1, 2, 3, 4].copyWithin(1, -2) must return [0, 3, 4, 3, 4]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(-1, -2), [0, 1, 2, 2],
|
||||
'[0, 1, 2, 3].copyWithin(-1, -2) must return [0, 1, 2, 2]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4].copyWithin(-2, -3), [0, 1, 2, 2, 3],
|
||||
'[0, 1, 2, 3, 4].copyWithin(-2, -3) must return [0, 1, 2, 2, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4].copyWithin(-5, -2), [3, 4, 2, 3, 4],
|
||||
'[0, 1, 2, 3, 4].copyWithin(-5, -2) must return [3, 4, 2, 3, 4]'
|
||||
);
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.copywithin
|
||||
description: >
|
||||
Set values with negative target argument.
|
||||
info: |
|
||||
22.1.3.3 Array.prototype.copyWithin (target, start [ , end ] )
|
||||
|
||||
...
|
||||
7. If relativeTarget < 0, let to be max((len + relativeTarget),0); else let to
|
||||
be min(relativeTarget, len).
|
||||
...
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(-1, 0), [0, 1, 2, 0],
|
||||
'[0, 1, 2, 3].copyWithin(-1, 0) must return [0, 1, 2, 0]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4].copyWithin(-2, 2), [0, 1, 2, 2, 3],
|
||||
'[0, 1, 2, 3, 4].copyWithin(-2, 2) must return [0, 1, 2, 2, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(-1, 2), [0, 1, 2, 2],
|
||||
'[0, 1, 2, 3].copyWithin(-1, 2) must return [0, 1, 2, 2]'
|
||||
);
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.copywithin
|
||||
description: >
|
||||
Max value of end position is the this.length.
|
||||
info: |
|
||||
22.1.3.3 Array.prototype.copyWithin (target, start [ , end ] )
|
||||
|
||||
...
|
||||
7. If relativeTarget < 0, let to be max((len + relativeTarget),0); else let to
|
||||
be min(relativeTarget, len).
|
||||
...
|
||||
10. If relativeStart < 0, let from be max((len + relativeStart),0); else let
|
||||
from be min(relativeStart, len).
|
||||
11. If end is undefined, let relativeEnd be len; else let relativeEnd be
|
||||
ToInteger(end).
|
||||
...
|
||||
14. Let count be min(final-from, len-to).
|
||||
15. If from<to and to<from+count
|
||||
a. Let direction be -1.
|
||||
b. Let from be from + count -1.
|
||||
c. Let to be to + count -1.
|
||||
16. Else,
|
||||
a. Let direction = 1.
|
||||
17. Repeat, while count > 0
|
||||
...
|
||||
a. If fromPresent is true, then
|
||||
i. Let fromVal be Get(O, fromKey).
|
||||
...
|
||||
iii. Let setStatus be Set(O, toKey, fromVal, true).
|
||||
...
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(0, 1, 6), [1, 2, 3, 3],
|
||||
'[0, 1, 2, 3].copyWithin(0, 1, 6) must return [1, 2, 3, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(0, 1, Infinity), [1, 2, 3, 3],
|
||||
'[0, 1, 2, 3].copyWithin(0, 1, Infinity) must return [1, 2, 3, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4, 5].copyWithin(1, 3, 6), [0, 3, 4, 5, 4, 5],
|
||||
'[0, 1, 2, 3, 4, 5].copyWithin(1, 3, 6) must return [0, 3, 4, 5, 4, 5]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4, 5].copyWithin(1, 3, Infinity), [0, 3, 4, 5, 4, 5],
|
||||
'[0, 1, 2, 3, 4, 5].copyWithin(1, 3, Infinity) must return [0, 3, 4, 5, 4, 5]'
|
||||
);
|
||||
-105
@@ -1,105 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.copywithin
|
||||
description: >
|
||||
Max values of target and start positions are this.length.
|
||||
info: |
|
||||
22.1.3.3 Array.prototype.copyWithin (target, start [ , end ] )
|
||||
|
||||
...
|
||||
7. If relativeTarget < 0, let to be max((len + relativeTarget),0); else let to
|
||||
be min(relativeTarget, len).
|
||||
...
|
||||
10. If relativeStart < 0, let from be max((len + relativeStart),0); else let
|
||||
from be min(relativeStart, len).
|
||||
11. If end is undefined, let relativeEnd be len; else let relativeEnd be
|
||||
ToInteger(end).
|
||||
...
|
||||
14. Let count be min(final-from, len-to).
|
||||
15. If from<to and to<from+count
|
||||
...
|
||||
16. Else,
|
||||
a. Let direction = 1.
|
||||
17. Repeat, while count > 0
|
||||
...
|
||||
...
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4, 5].copyWithin(6, 0), [0, 1, 2, 3, 4, 5],
|
||||
'[0, 1, 2, 3, 4, 5].copyWithin(6, 0) must return [0, 1, 2, 3, 4, 5]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4, 5].copyWithin(7, 0), [0, 1, 2, 3, 4, 5],
|
||||
'[0, 1, 2, 3, 4, 5].copyWithin(7, 0) must return [0, 1, 2, 3, 4, 5]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4, 5].copyWithin(Infinity, 0), [0, 1, 2, 3, 4, 5],
|
||||
'[0, 1, 2, 3, 4, 5].copyWithin(Infinity, 0) must return [0, 1, 2, 3, 4, 5]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4, 5].copyWithin(6, 2), [0, 1, 2, 3, 4, 5],
|
||||
'[0, 1, 2, 3, 4, 5].copyWithin(6, 2) must return [0, 1, 2, 3, 4, 5]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4, 5].copyWithin(7, 2), [0, 1, 2, 3, 4, 5],
|
||||
'[0, 1, 2, 3, 4, 5].copyWithin(7, 2) must return [0, 1, 2, 3, 4, 5]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4, 5].copyWithin(Infinity, 2), [0, 1, 2, 3, 4, 5],
|
||||
'[0, 1, 2, 3, 4, 5].copyWithin(Infinity, 2) must return [0, 1, 2, 3, 4, 5]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4, 5].copyWithin(0, 6), [0, 1, 2, 3, 4, 5],
|
||||
'[0, 1, 2, 3, 4, 5].copyWithin(0, 6) must return [0, 1, 2, 3, 4, 5]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4, 5].copyWithin(0, 7), [0, 1, 2, 3, 4, 5],
|
||||
'[0, 1, 2, 3, 4, 5].copyWithin(0, 7) must return [0, 1, 2, 3, 4, 5]'
|
||||
);
|
||||
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4, 5].copyWithin(0, Infinity), [0, 1, 2, 3, 4, 5],
|
||||
'[0, 1, 2, 3, 4, 5].copyWithin(0, Infinity) must return [0, 1, 2, 3, 4, 5]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4, 5].copyWithin(2, 6), [0, 1, 2, 3, 4, 5],
|
||||
'[0, 1, 2, 3, 4, 5].copyWithin(2, 6) must return [0, 1, 2, 3, 4, 5]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4, 5].copyWithin(1, 7), [0, 1, 2, 3, 4, 5],
|
||||
'[0, 1, 2, 3, 4, 5].copyWithin(1, 7) must return [0, 1, 2, 3, 4, 5]'
|
||||
);
|
||||
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4, 5].copyWithin(3, Infinity), [0, 1, 2, 3, 4, 5],
|
||||
'[0, 1, 2, 3, 4, 5].copyWithin(3, Infinity) must return [0, 1, 2, 3, 4, 5]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4, 5].copyWithin(6, 6), [0, 1, 2, 3, 4, 5],
|
||||
'[0, 1, 2, 3, 4, 5].copyWithin(6, 6) must return [0, 1, 2, 3, 4, 5]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4, 5].copyWithin(10, 10), [0, 1, 2, 3, 4, 5],
|
||||
'[0, 1, 2, 3, 4, 5].copyWithin(10, 10) must return [0, 1, 2, 3, 4, 5]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4, 5].copyWithin(Infinity, Infinity), [0, 1, 2, 3, 4, 5],
|
||||
'[0, 1, 2, 3, 4, 5].copyWithin(Infinity, Infinity) must return [0, 1, 2, 3, 4, 5]'
|
||||
);
|
||||
packages/codemode/test/test262/built-ins/Array/prototype/copyWithin/non-negative-target-and-start.js
Vendored
-52
@@ -1,52 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.copywithin
|
||||
description: >
|
||||
Copy values with non-negative target and start positions.
|
||||
info: |
|
||||
22.1.3.3 Array.prototype.copyWithin (target, start [ , end ] )
|
||||
|
||||
...
|
||||
7. If relativeTarget < 0, let to be max((len + relativeTarget),0); else let to
|
||||
be min(relativeTarget, len).
|
||||
...
|
||||
10. If relativeStart < 0, let from be max((len + relativeStart),0); else let
|
||||
from be min(relativeStart, len).
|
||||
11. If end is undefined, let relativeEnd be len; else let relativeEnd be
|
||||
ToInteger(end).
|
||||
...
|
||||
14. Let count be min(final-from, len-to).
|
||||
15. If from<to and to<from+count
|
||||
...
|
||||
16. Else,
|
||||
a. Let direction = 1.
|
||||
17. Repeat, while count > 0
|
||||
...
|
||||
a. If fromPresent is true, then
|
||||
i. Let fromVal be Get(O, fromKey).
|
||||
...
|
||||
iii. Let setStatus be Set(O, toKey, fromVal, true).
|
||||
...
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
assert.compareArray(
|
||||
['a', 'b', 'c', 'd', 'e', 'f'].copyWithin(0, 0),
|
||||
['a', 'b', 'c', 'd', 'e', 'f']
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
['a', 'b', 'c', 'd', 'e', 'f'].copyWithin(0, 2),
|
||||
['c', 'd', 'e', 'f', 'e', 'f']
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
['a', 'b', 'c', 'd', 'e', 'f'].copyWithin(3, 0),
|
||||
['a', 'b', 'c', 'a', 'b', 'c']
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4, 5].copyWithin(1, 4),
|
||||
[0, 4, 5, 3, 4, 5]
|
||||
);
|
||||
-70
@@ -1,70 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.copywithin
|
||||
description: >
|
||||
Copy values with non-negative target, start and end positions.
|
||||
info: |
|
||||
22.1.3.3 Array.prototype.copyWithin (target, start [ , end ] )
|
||||
|
||||
...
|
||||
7. If relativeTarget < 0, let to be max((len + relativeTarget),0); else let to
|
||||
be min(relativeTarget, len).
|
||||
...
|
||||
10. If relativeStart < 0, let from be max((len + relativeStart),0); else let
|
||||
from be min(relativeStart, len).
|
||||
11. If end is undefined, let relativeEnd be len; else let relativeEnd be
|
||||
ToInteger(end).
|
||||
...
|
||||
14. Let count be min(final-from, len-to).
|
||||
15. If from<to and to<from+count
|
||||
a. Let direction be -1.
|
||||
b. Let from be from + count -1.
|
||||
c. Let to be to + count -1.
|
||||
16. Else,
|
||||
a. Let direction = 1.
|
||||
17. Repeat, while count > 0
|
||||
...
|
||||
a. If fromPresent is true, then
|
||||
i. Let fromVal be Get(O, fromKey).
|
||||
...
|
||||
iii. Let setStatus be Set(O, toKey, fromVal, true).
|
||||
...
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(0, 0, 0), [0, 1, 2, 3],
|
||||
'[0, 1, 2, 3].copyWithin(0, 0, 0) must return [0, 1, 2, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(0, 0, 2), [0, 1, 2, 3],
|
||||
'[0, 1, 2, 3].copyWithin(0, 0, 2) must return [0, 1, 2, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(0, 1, 2), [1, 1, 2, 3],
|
||||
'[0, 1, 2, 3].copyWithin(0, 1, 2) must return [1, 1, 2, 3]'
|
||||
);
|
||||
|
||||
/*
|
||||
* 15. If from<to and to<from+count
|
||||
* a. Let direction be -1.
|
||||
* b. Let from be from + count -1.
|
||||
* c. Let to be to + count -1.
|
||||
*
|
||||
* 0 < 1, 1 < 0 + 2
|
||||
* direction = -1
|
||||
* from = 0 + 2 - 1
|
||||
* to = 1 + 2 - 1
|
||||
*/
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(1, 0, 2), [0, 0, 1, 3],
|
||||
'[0, 1, 2, 3].copyWithin(1, 0, 2) must return [0, 0, 1, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3, 4, 5].copyWithin(1, 3, 5), [0, 3, 4, 3, 4, 5],
|
||||
'[0, 1, 2, 3, 4, 5].copyWithin(1, 3, 5) must return [0, 3, 4, 3, 4, 5]'
|
||||
);
|
||||
Vendored
-24
@@ -1,24 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.copywithin
|
||||
description: >
|
||||
Return abrupt from ToInteger(end).
|
||||
info: |
|
||||
22.1.3.3 Array.prototype.copyWithin (target, start [ , end ] )
|
||||
|
||||
...
|
||||
11. If end is undefined, let relativeEnd be len; else let relativeEnd be
|
||||
ToInteger(end).
|
||||
12. ReturnIfAbrupt(relativeEnd).
|
||||
...
|
||||
---*/
|
||||
|
||||
var o1 = {
|
||||
valueOf: function() {
|
||||
throw new Test262Error();
|
||||
}
|
||||
};
|
||||
assert.throws(Test262Error, function() {
|
||||
[].copyWithin(0, 0, o1);
|
||||
});
|
||||
Vendored
-23
@@ -1,23 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.copywithin
|
||||
description: >
|
||||
Return abrupt from ToInteger(start).
|
||||
info: |
|
||||
22.1.3.3 Array.prototype.copyWithin (target, start [ , end ] )
|
||||
|
||||
...
|
||||
8. Let relativeStart be ToInteger(start).
|
||||
9. ReturnIfAbrupt(relativeStart).
|
||||
...
|
||||
---*/
|
||||
|
||||
var o1 = {
|
||||
valueOf: function() {
|
||||
throw new Test262Error();
|
||||
}
|
||||
};
|
||||
assert.throws(Test262Error, function() {
|
||||
[].copyWithin(0, o1);
|
||||
});
|
||||
Vendored
-23
@@ -1,23 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.copywithin
|
||||
description: >
|
||||
Return abrupt from ToInteger(target).
|
||||
info: |
|
||||
22.1.3.3 Array.prototype.copyWithin (target, start [ , end ] )
|
||||
|
||||
...
|
||||
5. Let relativeTarget be ToInteger(target).
|
||||
6. ReturnIfAbrupt(relativeTarget).
|
||||
...
|
||||
---*/
|
||||
|
||||
var o1 = {
|
||||
valueOf: function() {
|
||||
throw new Test262Error();
|
||||
}
|
||||
};
|
||||
assert.throws(Test262Error, function() {
|
||||
[].copyWithin(o1);
|
||||
});
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.copywithin
|
||||
description: >
|
||||
If `end` is undefined, set final position to `this.length`.
|
||||
info: |
|
||||
22.1.3.3 Array.prototype.copyWithin (target, start [ , end ] )
|
||||
|
||||
...
|
||||
11. If end is undefined, let relativeEnd be len; else let relativeEnd be
|
||||
ToInteger(end).
|
||||
...
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(0, 1, undefined), [1, 2, 3, 3],
|
||||
'[0, 1, 2, 3].copyWithin(0, 1, undefined) must return [1, 2, 3, 3]'
|
||||
);
|
||||
|
||||
assert.compareArray(
|
||||
[0, 1, 2, 3].copyWithin(0, 1), [1, 2, 3, 3],
|
||||
'[0, 1, 2, 3].copyWithin(0, 1) must return [1, 2, 3, 3]'
|
||||
);
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.entries
|
||||
description: >
|
||||
New items in the array are accessible via iteration until iterator is "done".
|
||||
info: |
|
||||
The method should return a valid iterator with the context as the
|
||||
IteratedObject. When an item is added to the array after the iterator is
|
||||
created but before the iterator is "done" (as defined by 22.1.5.2.1) the
|
||||
new item should be accessible via iteration.
|
||||
---*/
|
||||
|
||||
var array = [];
|
||||
var iterator = array.entries();
|
||||
var result;
|
||||
|
||||
array.push('a');
|
||||
|
||||
result = iterator.next();
|
||||
assert.sameValue(result.done, false, 'First result `done` flag');
|
||||
assert.sameValue(result.value[0], 0, 'First result `value` (array key)');
|
||||
assert.sameValue(result.value[1], 'a', 'First result `value (array value)');
|
||||
assert.sameValue(result.value.length, 2, 'First result `value` (length)');
|
||||
|
||||
result = iterator.next();
|
||||
assert.sameValue(result.done, true, 'Exhausted result `done` flag');
|
||||
assert.sameValue(result.value, undefined, 'Exhausted result `value`');
|
||||
|
||||
array.push('b');
|
||||
|
||||
result = iterator.next();
|
||||
assert.sameValue(result.done, true, 'Exhausted result `done` flag (after push)');
|
||||
assert.sameValue(result.value, undefined, 'Exhausted result `value` (after push)');
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.entries
|
||||
description: >
|
||||
The return is a valid iterator with the array's numeric properties.
|
||||
info: |
|
||||
22.1.3.4 Array.prototype.entries ( )
|
||||
|
||||
1. Let O be ToObject(this value).
|
||||
2. ReturnIfAbrupt(O).
|
||||
3. Return CreateArrayIterator(O, "key+value").
|
||||
---*/
|
||||
|
||||
var array = ['a', 'b', 'c'];
|
||||
var iterator = array.entries();
|
||||
var result;
|
||||
|
||||
result = iterator.next();
|
||||
assert.sameValue(result.done, false, 'First result `done` flag');
|
||||
assert.sameValue(result.value[0], 0, 'First result `value` (array key)');
|
||||
assert.sameValue(result.value[1], 'a', 'First result `value` (array value)');
|
||||
assert.sameValue(result.value.length, 2, 'First result `value` (length)');
|
||||
|
||||
result = iterator.next();
|
||||
assert.sameValue(result.done, false, 'Second result `done` flag');
|
||||
assert.sameValue(result.value[0], 1, 'Second result `value` (array key)');
|
||||
assert.sameValue(result.value[1], 'b', 'Second result `value` (array value)');
|
||||
assert.sameValue(result.value.length, 2, 'Second result `value` (length)');
|
||||
|
||||
result = iterator.next();
|
||||
assert.sameValue(result.done, false, 'Third result `done` flag');
|
||||
assert.sameValue(result.value[0], 2, 'Third result `value` (array key)');
|
||||
assert.sameValue(result.value[1], 'c', 'Third result `value` (array value)');
|
||||
assert.sameValue(result.value.length, 2, 'Third result `value` (length)');
|
||||
|
||||
result = iterator.next();
|
||||
assert.sameValue(result.done, true, 'Exhausted result `done` flag');
|
||||
assert.sameValue(result.value, undefined, 'Exhausted result `value`');
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
es5id: 15.4.4.16-4-1
|
||||
description: Array.prototype.every throws TypeError if callbackfn is undefined
|
||||
---*/
|
||||
|
||||
var arr = new Array(10);
|
||||
assert.throws(TypeError, function() {
|
||||
arr.every();
|
||||
});
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
es5id: 15.4.4.16-4-12
|
||||
description: Array.prototype.every - 'callbackfn' is a function
|
||||
---*/
|
||||
|
||||
function callbackfn(val, idx, obj) {
|
||||
return val > 10;
|
||||
}
|
||||
|
||||
assert.sameValue([11, 9].every(callbackfn), false, '[11, 9].every(callbackfn)');
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
es5id: 15.4.4.16-4-3
|
||||
description: Array.prototype.every throws TypeError if callbackfn is null
|
||||
---*/
|
||||
|
||||
var arr = new Array(10);
|
||||
assert.throws(TypeError, function() {
|
||||
arr.every(null);
|
||||
});
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
es5id: 15.4.4.16-4-4
|
||||
description: Array.prototype.every throws TypeError if callbackfn is boolean
|
||||
---*/
|
||||
|
||||
var arr = new Array(10);
|
||||
assert.throws(TypeError, function() {
|
||||
arr.every(true);
|
||||
});
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
es5id: 15.4.4.16-4-5
|
||||
description: Array.prototype.every throws TypeError if callbackfn is number
|
||||
---*/
|
||||
|
||||
var arr = new Array(10);
|
||||
assert.throws(TypeError, function() {
|
||||
arr.every(5);
|
||||
});
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
es5id: 15.4.4.16-4-6
|
||||
description: Array.prototype.every throws TypeError if callbackfn is string
|
||||
---*/
|
||||
|
||||
var arr = new Array(10);
|
||||
assert.throws(TypeError, function() {
|
||||
arr.every("abc");
|
||||
});
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
es5id: 15.4.4.16-4-7
|
||||
description: >
|
||||
Array.prototype.every throws TypeError if callbackfn is Object
|
||||
without a Call internal method
|
||||
---*/
|
||||
|
||||
var arr = new Array(10);
|
||||
assert.throws(TypeError, function() {
|
||||
arr.every({});
|
||||
});
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every considers new elements added to array after
|
||||
the call
|
||||
---*/
|
||||
|
||||
var calledForThree = false;
|
||||
|
||||
function callbackfn(val, Idx, obj)
|
||||
{
|
||||
arr[2] = 3;
|
||||
if (val == 3)
|
||||
calledForThree = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
var arr = [1, 2, , 4, 5];
|
||||
|
||||
var res = arr.every(callbackfn);
|
||||
|
||||
assert(calledForThree, 'calledForThree !== true');
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every considers new value of elements in array
|
||||
after the call
|
||||
---*/
|
||||
|
||||
function callbackfn(val, Idx, obj)
|
||||
{
|
||||
arr[4] = 6;
|
||||
if (val < 6)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
var arr = [1, 2, 3, 4, 5];
|
||||
|
||||
|
||||
assert.sameValue(arr.every(callbackfn), false, 'arr.every(callbackfn)');
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every doesn't visit deleted elements in array
|
||||
after the call
|
||||
---*/
|
||||
|
||||
function callbackfn(val, Idx, obj)
|
||||
{
|
||||
delete arr[2];
|
||||
if (val == 3)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
var arr = [1, 2, 3, 4, 5];
|
||||
|
||||
|
||||
assert.sameValue(arr.every(callbackfn), true, 'arr.every(callbackfn)');
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every doesn't visit deleted elements when
|
||||
Array.length is decreased
|
||||
---*/
|
||||
|
||||
function callbackfn(val, Idx, obj)
|
||||
{
|
||||
arr.length = 3;
|
||||
if (val < 4)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
var arr = [1, 2, 3, 4, 6];
|
||||
|
||||
|
||||
assert.sameValue(arr.every(callbackfn), true, 'arr.every(callbackfn)');
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every doesn't consider newly added elements in
|
||||
sparse array
|
||||
---*/
|
||||
|
||||
function callbackfn(val, Idx, obj)
|
||||
{
|
||||
arr[1000] = 3;
|
||||
if (val < 3)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
var arr = new Array(10);
|
||||
arr[1] = 1;
|
||||
arr[2] = 2;
|
||||
|
||||
|
||||
assert.sameValue(arr.every(callbackfn), true, 'arr.every(callbackfn)');
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every - Deleting the array itself within the
|
||||
callbackfn of Array.prototype.every is successful once
|
||||
Array.prototype.every is called for all elements
|
||||
---*/
|
||||
|
||||
var o = new Object();
|
||||
o.arr = [1, 2, 3, 4, 5];
|
||||
|
||||
function callbackfn(val, Idx, obj) {
|
||||
delete o.arr;
|
||||
if (val === Idx + 1)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(o.arr.every(callbackfn), 'o.arr.every(callbackfn) !== true');
|
||||
assert.sameValue(o.hasOwnProperty("arr"), false, 'o.hasOwnProperty("arr")');
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every - callbackfn not called for indexes never
|
||||
been assigned values
|
||||
---*/
|
||||
|
||||
var callCnt = 0.;
|
||||
|
||||
function callbackfn(val, Idx, obj)
|
||||
{
|
||||
callCnt++;
|
||||
return true;
|
||||
}
|
||||
|
||||
var arr = new Array(10);
|
||||
arr[1] = undefined;
|
||||
arr.every(callbackfn);
|
||||
|
||||
assert.sameValue(callCnt, 1, 'callCnt');
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every - element to be retrieved is own data
|
||||
property on an Array
|
||||
---*/
|
||||
|
||||
var called = 0;
|
||||
|
||||
function callbackfn(val, idx, obj) {
|
||||
called++;
|
||||
return val === 11;
|
||||
}
|
||||
|
||||
assert([11].every(callbackfn), '[11].every(callbackfn) !== true');
|
||||
assert.sameValue(called, 1, 'called');
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: Array.prototype.every - callbackfn called with correct parameters
|
||||
---*/
|
||||
|
||||
function callbackfn(val, Idx, obj)
|
||||
{
|
||||
if (obj[Idx] === val)
|
||||
return true;
|
||||
}
|
||||
|
||||
var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
|
||||
|
||||
assert.sameValue(arr.every(callbackfn), true, 'arr.every(callbackfn)');
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every - callbackfn is called with 1 formal
|
||||
parameter
|
||||
---*/
|
||||
|
||||
var called = 0;
|
||||
|
||||
function callbackfn(val) {
|
||||
called++;
|
||||
return val > 10;
|
||||
}
|
||||
|
||||
assert([11, 12].every(callbackfn), '[11, 12].every(callbackfn) !== true');
|
||||
assert.sameValue(called, 2, 'called');
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every - callbackfn is called with 3 formal
|
||||
parameter
|
||||
---*/
|
||||
|
||||
var called = 0;
|
||||
|
||||
function callbackfn(val, idx, obj) {
|
||||
called++;
|
||||
return val > 10 && obj[idx] === val;
|
||||
}
|
||||
|
||||
assert([11, 12, 13].every(callbackfn), '[11, 12, 13].every(callbackfn) !== true');
|
||||
assert.sameValue(called, 3, 'called');
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every immediately returns false if callbackfn
|
||||
returns false
|
||||
---*/
|
||||
|
||||
var callCnt = 0;
|
||||
|
||||
function callbackfn(val, idx, obj)
|
||||
{
|
||||
callCnt++;
|
||||
if (idx > 5)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
|
||||
|
||||
assert.sameValue(arr.every(callbackfn), false, 'arr.every(callbackfn)');
|
||||
assert.sameValue(callCnt, 7, 'callCnt');
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every - k values are passed in ascending numeric
|
||||
order
|
||||
---*/
|
||||
|
||||
var arr = [0, 1, 2, 3, 4, 5];
|
||||
var lastIdx = 0;
|
||||
var called = 0;
|
||||
|
||||
function callbackfn(val, idx, o) {
|
||||
called++;
|
||||
if (lastIdx !== idx) {
|
||||
return false;
|
||||
} else {
|
||||
lastIdx++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
assert(arr.every(callbackfn), 'arr.every(callbackfn) !== true');
|
||||
assert.sameValue(arr.length, called, 'arr.length');
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every - k values are accessed during each
|
||||
iteration and not prior to starting the loop on an Array
|
||||
---*/
|
||||
|
||||
var called = 0;
|
||||
var kIndex = [];
|
||||
|
||||
//By below way, we could verify that k would be setted as 0, 1, ..., length - 1 in order, and each value will be setted one time.
|
||||
function callbackfn(val, idx, obj) {
|
||||
called++;
|
||||
//Each position should be visited one time, which means k is accessed one time during iterations.
|
||||
if (typeof kIndex[idx] === "undefined") {
|
||||
//when current position is visited, its previous index should has been visited.
|
||||
if (idx !== 0 && typeof kIndex[idx - 1] === "undefined") {
|
||||
return false;
|
||||
}
|
||||
kIndex[idx] = 1;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
assert([11, 12, 13, 14].every(callbackfn, undefined), '[11, 12, 13, 14].every(callbackfn, undefined) !== true');
|
||||
assert.sameValue(called, 4, 'called');
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every - callbackfn is called with 0 formal
|
||||
parameter
|
||||
---*/
|
||||
|
||||
var called = 0;
|
||||
|
||||
function callbackfn() {
|
||||
called++;
|
||||
return true;
|
||||
}
|
||||
|
||||
assert([11, 12].every(callbackfn), '[11, 12].every(callbackfn) !== true');
|
||||
assert.sameValue(called, 2, 'called');
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every - return value of callbackfn is a number
|
||||
(value is Infinity)
|
||||
---*/
|
||||
|
||||
var accessed = false;
|
||||
|
||||
function callbackfn(val, idx, obj) {
|
||||
accessed = true;
|
||||
return Infinity;
|
||||
}
|
||||
|
||||
assert([11].every(callbackfn), '[11].every(callbackfn) !== true');
|
||||
assert(accessed, 'accessed !== true');
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every - return value of callbackfn is a number
|
||||
(value is -Infinity)
|
||||
---*/
|
||||
|
||||
var accessed = false;
|
||||
|
||||
function callbackfn(val, idx, obj) {
|
||||
accessed = true;
|
||||
return -Infinity;
|
||||
}
|
||||
|
||||
assert([11].every(callbackfn), '[11].every(callbackfn) !== true');
|
||||
assert(accessed, 'accessed !== true');
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every - return value of callbackfn is a number
|
||||
(value is NaN)
|
||||
---*/
|
||||
|
||||
var accessed = false;
|
||||
|
||||
function callbackfn(val, idx, obj) {
|
||||
accessed = true;
|
||||
return NaN;
|
||||
}
|
||||
|
||||
assert.sameValue([11].every(callbackfn), false, '[11].every(callbackfn)');
|
||||
assert(accessed, 'accessed !== true');
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every - return value of callbackfn is an empty
|
||||
string
|
||||
---*/
|
||||
|
||||
var accessed = false;
|
||||
|
||||
function callbackfn(val, idx, obj) {
|
||||
accessed = true;
|
||||
return "";
|
||||
}
|
||||
|
||||
assert.sameValue([11].every(callbackfn), false, '[11].every(callbackfn)');
|
||||
assert(accessed, 'accessed !== true');
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every - return value of callbackfn is a non-empty
|
||||
string
|
||||
---*/
|
||||
|
||||
var accessed = false;
|
||||
|
||||
function callbackfn(val, idx, obj) {
|
||||
accessed = true;
|
||||
return "non-empty string";
|
||||
}
|
||||
|
||||
assert([11].every(callbackfn), '[11].every(callbackfn) !== true');
|
||||
assert(accessed, 'accessed !== true');
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every - return value of callbackfn is a Function
|
||||
object
|
||||
---*/
|
||||
|
||||
var accessed = false;
|
||||
|
||||
function callbackfn(val, idx, obj) {
|
||||
accessed = true;
|
||||
return function() {};
|
||||
}
|
||||
|
||||
assert([11].every(callbackfn), '[11].every(callbackfn) !== true');
|
||||
assert(accessed, 'accessed !== true');
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every - return value of callbackfn is an Array
|
||||
object
|
||||
---*/
|
||||
|
||||
var accessed = false;
|
||||
|
||||
function callbackfn(val, idx, obj) {
|
||||
accessed = true;
|
||||
return [];
|
||||
}
|
||||
|
||||
assert([11].every(callbackfn), '[11].every(callbackfn) !== true');
|
||||
assert(accessed, 'accessed !== true');
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every - return value of callbackfn is the Math
|
||||
object
|
||||
---*/
|
||||
|
||||
var accessed = false;
|
||||
|
||||
function callbackfn(val, idx, obj) {
|
||||
accessed = true;
|
||||
return Math;
|
||||
}
|
||||
|
||||
assert([11].every(callbackfn), '[11].every(callbackfn) !== true');
|
||||
assert(accessed, 'accessed !== true');
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: Array.prototype.every - return value of callbackfn is a Date object
|
||||
---*/
|
||||
|
||||
var accessed = false;
|
||||
|
||||
function callbackfn(val, idx, obj) {
|
||||
accessed = true;
|
||||
return new Date(0);
|
||||
}
|
||||
|
||||
assert([11].every(callbackfn), '[11].every(callbackfn) !== true');
|
||||
assert(accessed, 'accessed !== true');
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every - return value of callbackfn is a RegExp
|
||||
object
|
||||
---*/
|
||||
|
||||
var accessed = false;
|
||||
|
||||
function callbackfn(val, idx, obj) {
|
||||
accessed = true;
|
||||
return new RegExp();
|
||||
}
|
||||
|
||||
assert([11].every(callbackfn), '[11].every(callbackfn) !== true');
|
||||
assert(accessed, 'accessed !== true');
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every - return value of callbackfn is the JSON
|
||||
object
|
||||
---*/
|
||||
|
||||
var accessed = false;
|
||||
|
||||
function callbackfn(val, idx, obj) {
|
||||
accessed = true;
|
||||
return JSON;
|
||||
}
|
||||
|
||||
assert([11].every(callbackfn), '[11].every(callbackfn) !== true');
|
||||
assert(accessed, 'accessed !== true');
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every - return value of callbackfn is an Error
|
||||
object
|
||||
---*/
|
||||
|
||||
var accessed = false;
|
||||
|
||||
function callbackfn(val, idx, obj) {
|
||||
accessed = true;
|
||||
return new EvalError();
|
||||
}
|
||||
|
||||
assert([11].every(callbackfn), '[11].every(callbackfn) !== true');
|
||||
assert(accessed, 'accessed !== true');
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every - return value of callbackfn is a number
|
||||
(value is 0)
|
||||
---*/
|
||||
|
||||
var accessed = false;
|
||||
|
||||
function callbackfn(val, idx, obj) {
|
||||
accessed = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert.sameValue([11].every(callbackfn), false, '[11].every(callbackfn)');
|
||||
assert(accessed, 'accessed !== true');
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every - return value of callbackfn is a number
|
||||
(value is +0)
|
||||
---*/
|
||||
|
||||
var accessed = false;
|
||||
|
||||
function callbackfn(val, idx, obj) {
|
||||
accessed = true;
|
||||
return +0;
|
||||
}
|
||||
|
||||
assert.sameValue([11].every(callbackfn), false, '[11].every(callbackfn)');
|
||||
assert(accessed, 'accessed !== true');
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every - return value of callbackfn is a nunmber
|
||||
(value is -0)
|
||||
---*/
|
||||
|
||||
var accessed = false;
|
||||
|
||||
function callbackfn(val, idx, obj) {
|
||||
accessed = true;
|
||||
return -0;
|
||||
}
|
||||
|
||||
assert.sameValue([11].every(callbackfn), false, '[11].every(callbackfn)');
|
||||
assert(accessed, 'accessed !== true');
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every - return value of callbackfn is a number
|
||||
(value is positive number)
|
||||
---*/
|
||||
|
||||
var accessed = false;
|
||||
|
||||
function callbackfn(val, idx, obj) {
|
||||
accessed = true;
|
||||
return 5;
|
||||
}
|
||||
|
||||
assert([11].every(callbackfn), '[11].every(callbackfn) !== true');
|
||||
assert(accessed, 'accessed !== true');
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every - return value of callbackfn is a number
|
||||
(value is negative number)
|
||||
---*/
|
||||
|
||||
var accessed = false;
|
||||
|
||||
function callbackfn(val, idx, obj) {
|
||||
accessed = true;
|
||||
return -5;
|
||||
}
|
||||
|
||||
assert([11].every(callbackfn), '[11].every(callbackfn) !== true');
|
||||
assert(accessed, 'accessed !== true');
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: Array.prototype.every returns true if 'length' is 0 (empty array)
|
||||
---*/
|
||||
|
||||
function cb() {}
|
||||
var i = [].every(cb);
|
||||
|
||||
assert.sameValue(i, true, 'i');
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every returns true when all calls to callbackfn
|
||||
return true
|
||||
---*/
|
||||
|
||||
var callCnt = 0;
|
||||
|
||||
function callbackfn(val, idx, obj)
|
||||
{
|
||||
callCnt++;
|
||||
return true;
|
||||
}
|
||||
|
||||
var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
|
||||
|
||||
assert.sameValue(arr.every(callbackfn), true, 'arr.every(callbackfn)');
|
||||
assert.sameValue(callCnt, 10, 'callCnt');
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: >
|
||||
Array.prototype.every doesn't mutate the array on which it is
|
||||
called on
|
||||
---*/
|
||||
|
||||
function callbackfn(val, idx, obj)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
var arr = [1, 2, 3, 4, 5];
|
||||
arr.every(callbackfn);
|
||||
|
||||
assert.sameValue(arr[0], 1, 'arr[0]');
|
||||
assert.sameValue(arr[1], 2, 'arr[1]');
|
||||
assert.sameValue(arr[2], 3, 'arr[2]');
|
||||
assert.sameValue(arr[3], 4, 'arr[3]');
|
||||
assert.sameValue(arr[4], 5, 'arr[4]');
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
// Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-array.prototype.every
|
||||
description: Array.prototype.every doesn't visit expandos
|
||||
---*/
|
||||
|
||||
var callCnt = 0;
|
||||
|
||||
function callbackfn(val, idx, obj)
|
||||
{
|
||||
callCnt++;
|
||||
return true;
|
||||
}
|
||||
|
||||
var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
arr["i"] = 10;
|
||||
arr[true] = 11;
|
||||
|
||||
|
||||
assert.sameValue(arr.every(callbackfn), true, 'arr.every(callbackfn)');
|
||||
assert.sameValue(callCnt, 10, 'callCnt');
|
||||
-82
@@ -1,82 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.fill
|
||||
description: >
|
||||
Fills elements from coerced to Integer `start` and `end` values
|
||||
info: |
|
||||
Array.prototype.fill ( _value_ [ , _start_ [ , _end_ ] ] )
|
||||
|
||||
3. Let _relativeStart_ be ? ToIntegerOrInfinity(_start_).
|
||||
4. If _relativeStart_ = -∞, let _k_ be 0.
|
||||
5. Else if _relativeStart_ < 0, let _k_ be max(_len_ + _relativeStart_, 0).
|
||||
|
||||
7. If _end_ is *undefined*, let _relativeEnd_ be _len_; else let _relativeEnd_ be ? ToIntegerOrInfinity(_end_).
|
||||
8. If _relativeEnd_ = -∞, let _final_ be 0.
|
||||
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
assert.compareArray([0, 0].fill(1, undefined), [1, 1],
|
||||
'[0, 0].fill(1, undefined) must return [1, 1]'
|
||||
);
|
||||
|
||||
assert.compareArray([0, 0].fill(1, 0, undefined), [1, 1],
|
||||
'[0, 0].fill(1, 0, undefined) must return [1, 1]'
|
||||
);
|
||||
|
||||
assert.compareArray([0, 0].fill(1, null), [1, 1],
|
||||
'[0, 0].fill(1, null) must return [1, 1]'
|
||||
);
|
||||
|
||||
assert.compareArray([0, 0].fill(1, 0, null), [0, 0],
|
||||
'[0, 0].fill(1, 0, null) must return [0, 0]'
|
||||
);
|
||||
|
||||
assert.compareArray([0, 0].fill(1, true), [0, 1],
|
||||
'[0, 0].fill(1, true) must return [0, 1]'
|
||||
);
|
||||
|
||||
assert.compareArray([0, 0].fill(1, 0, true), [1, 0],
|
||||
'[0, 0].fill(1, 0, true) must return [1, 0]'
|
||||
);
|
||||
|
||||
assert.compareArray([0, 0].fill(1, false), [1, 1],
|
||||
'[0, 0].fill(1, false) must return [1, 1]'
|
||||
);
|
||||
|
||||
assert.compareArray([0, 0].fill(1, 0, false), [0, 0],
|
||||
'[0, 0].fill(1, 0, false) must return [0, 0]'
|
||||
);
|
||||
|
||||
assert.compareArray([0, 0].fill(1, NaN), [1, 1],
|
||||
'[0, 0].fill(1, NaN) must return [1, 1]'
|
||||
);
|
||||
|
||||
assert.compareArray([0, 0].fill(1, 0, NaN), [0, 0],
|
||||
'[0, 0].fill(1, 0, NaN) must return [0, 0]'
|
||||
);
|
||||
|
||||
assert.compareArray([0, 0].fill(1, '1'), [0, 1],
|
||||
'[0, 0].fill(1, "1") must return [0, 1]'
|
||||
);
|
||||
|
||||
assert.compareArray([0, 0].fill(1, 0, '1'), [1, 0],
|
||||
'[0, 0].fill(1, 0, "1") must return [1, 0]'
|
||||
);
|
||||
|
||||
assert.compareArray([0, 0].fill(1, 1.5), [0, 1],
|
||||
'[0, 0].fill(1, 1.5) must return [0, 1]'
|
||||
);
|
||||
|
||||
assert.compareArray([0, 0].fill(1, 0, 1.5), [1, 0],
|
||||
'[0, 0].fill(1, 0, 1.5) must return [1, 0]'
|
||||
);
|
||||
|
||||
assert.compareArray([0, 0].fill(1, Number.NEGATIVE_INFINITY, 1), [1, 0],
|
||||
'[0, 0].fill(1, Number.NEGATIVE_INFINITY, 1) must return [1, 0]'
|
||||
);
|
||||
|
||||
assert.compareArray([0, 0].fill(1, 0, Number.NEGATIVE_INFINITY), [0, 0],
|
||||
'[0, 0].fill(1, 0, Number.NEGATIVE_INFINITY) must return [0, 0]'
|
||||
);
|
||||
Vendored
-38
@@ -1,38 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.fill
|
||||
description: >
|
||||
Fills all the elements from a with a custom start and end indexes.
|
||||
info: |
|
||||
22.1.3.6 Array.prototype.fill (value [ , start [ , end ] ] )
|
||||
|
||||
...
|
||||
7. If relativeStart < 0, let k be max((len + relativeStart),0); else let k be
|
||||
min(relativeStart, len).
|
||||
8. If end is undefined, let relativeEnd be len; else let relativeEnd be
|
||||
ToInteger(end).
|
||||
9. ReturnIfAbrupt(relativeEnd).
|
||||
10. If relativeEnd < 0, let final be max((len + relativeEnd),0); else let
|
||||
final be min(relativeEnd, len).
|
||||
...
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
assert.compareArray([0, 0, 0].fill(8, 1, 2), [0, 8, 0], '[0, 0, 0].fill(8, 1, 2) must return [0, 8, 0]');
|
||||
assert.compareArray(
|
||||
[0, 0, 0, 0, 0].fill(8, -3, 4),
|
||||
[0, 0, 8, 8, 0],
|
||||
'[0, 0, 0, 0, 0].fill(8, -3, 4) must return [0, 0, 8, 8, 0]'
|
||||
);
|
||||
assert.compareArray(
|
||||
[0, 0, 0, 0, 0].fill(8, -2, -1),
|
||||
[0, 0, 0, 8, 0],
|
||||
'[0, 0, 0, 0, 0].fill(8, -2, -1) must return [0, 0, 0, 8, 0]'
|
||||
);
|
||||
assert.compareArray(
|
||||
[0, 0, 0, 0, 0].fill(8, -1, -3),
|
||||
[0, 0, 0, 0, 0],
|
||||
'[0, 0, 0, 0, 0].fill(8, -1, -3) must return [0, 0, 0, 0, 0]'
|
||||
);
|
||||
assert.compareArray([, , , , 0].fill(8, 1, 3), [, 8, 8, , 0], '[, , , , 0].fill(8, 1, 3) must return [, 8, 8, , 0]');
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.fill
|
||||
description: >
|
||||
Fills all the elements from a with a custom start index.
|
||||
info: |
|
||||
22.1.3.6 Array.prototype.fill (value [ , start [ , end ] ] )
|
||||
|
||||
...
|
||||
8. If end is undefined, let relativeEnd be len; else let relativeEnd be
|
||||
ToInteger(end).
|
||||
9. ReturnIfAbrupt(relativeEnd).
|
||||
10. If relativeEnd < 0, let final be max((len + relativeEnd),0); else let
|
||||
final be min(relativeEnd, len).
|
||||
...
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
assert.compareArray([0, 0, 0].fill(8, 0, 1), [8, 0, 0],
|
||||
'[0, 0, 0].fill(8, 0, 1) must return [8, 0, 0]'
|
||||
);
|
||||
|
||||
assert.compareArray([0, 0, 0].fill(8, 0, -1), [8, 8, 0],
|
||||
'[0, 0, 0].fill(8, 0, -1) must return [8, 8, 0]'
|
||||
);
|
||||
|
||||
assert.compareArray([0, 0, 0].fill(8, 0, 5), [8, 8, 8],
|
||||
'[0, 0, 0].fill(8, 0, 5) must return [8, 8, 8]'
|
||||
);
|
||||
Vendored
-27
@@ -1,27 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.fill
|
||||
description: >
|
||||
Fills all the elements from a with a custom start index.
|
||||
info: |
|
||||
22.1.3.6 Array.prototype.fill (value [ , start [ , end ] ] )
|
||||
|
||||
...
|
||||
7. If relativeStart < 0, let k be max((len + relativeStart),0); else let k be
|
||||
min(relativeStart, len).
|
||||
...
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
assert.compareArray([0, 0, 0].fill(8, 1), [0, 8, 8],
|
||||
'[0, 0, 0].fill(8, 1) must return [0, 8, 8]'
|
||||
);
|
||||
|
||||
assert.compareArray([0, 0, 0].fill(8, 4), [0, 0, 0],
|
||||
'[0, 0, 0].fill(8, 4) must return [0, 0, 0]'
|
||||
);
|
||||
|
||||
assert.compareArray([0, 0, 0].fill(8, -1), [0, 0, 8],
|
||||
'[0, 0, 0].fill(8, -1) must return [0, 0, 8]'
|
||||
);
|
||||
@@ -1,33 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.fill
|
||||
description: >
|
||||
Fills all the elements with `value` from a defaul start and index.
|
||||
info: |
|
||||
22.1.3.6 Array.prototype.fill (value [ , start [ , end ] ] )
|
||||
|
||||
...
|
||||
7. If relativeStart < 0, let k be max((len + relativeStart),0); else let k be
|
||||
min(relativeStart, len).
|
||||
8. If end is undefined, let relativeEnd be len; else let relativeEnd be
|
||||
ToInteger(end).
|
||||
9. ReturnIfAbrupt(relativeEnd).
|
||||
10. If relativeEnd < 0, let final be max((len + relativeEnd),0); else let
|
||||
final be min(relativeEnd, len).
|
||||
11. Repeat, while k < final
|
||||
a. Let Pk be ToString(k).
|
||||
b. Let setStatus be Set(O, Pk, value, true).
|
||||
c. ReturnIfAbrupt(setStatus).
|
||||
d. Increase k by 1.
|
||||
12. Return O.
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
assert.compareArray([].fill(8), [], '[].fill(8) must return []');
|
||||
|
||||
assert.compareArray([0, 0].fill(), [undefined, undefined], '[0, 0].fill() must return [undefined, undefined]');
|
||||
|
||||
assert.compareArray([0, 0, 0].fill(8), [8, 8, 8],
|
||||
'[0, 0, 0].fill(8) must return [8, 8, 8]'
|
||||
);
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.fill
|
||||
description: >
|
||||
Return abrupt from ToInteger(end).
|
||||
info: |
|
||||
22.1.3.6 Array.prototype.fill (value [ , start [ , end ] ] )
|
||||
|
||||
...
|
||||
8. If end is undefined, let relativeEnd be len; else let relativeEnd be
|
||||
ToInteger(end).
|
||||
9. ReturnIfAbrupt(relativeEnd).
|
||||
...
|
||||
---*/
|
||||
|
||||
var end = {
|
||||
valueOf: function() {
|
||||
throw new Test262Error();
|
||||
}
|
||||
};
|
||||
|
||||
assert.throws(Test262Error, function() {
|
||||
[].fill(1, 0, end);
|
||||
});
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-array.prototype.fill
|
||||
description: >
|
||||
Return abrupt from ToInteger(start).
|
||||
info: |
|
||||
22.1.3.6 Array.prototype.fill (value [ , start [ , end ] ] )
|
||||
|
||||
...
|
||||
5. Let relativeStart be ToInteger(start).
|
||||
6. ReturnIfAbrupt(relativeStart).
|
||||
...
|
||||
---*/
|
||||
|
||||
var start = {
|
||||
valueOf: function() {
|
||||
throw new Test262Error();
|
||||
}
|
||||
};
|
||||
|
||||
assert.throws(Test262Error, function() {
|
||||
[].fill(1, start);
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user