Compare commits

..
Author SHA1 Message Date
Shoubhit Dash d5518553b5 Merge remote-tracking branch 'origin/v2' into session-diff
# Conflicts:
#	packages/server/src/handlers/session.ts
2026-09-10 16:52:26 +05:30
Shoubhit Dash 6eb2042acd Merge remote-tracking branch 'origin/v2' into session-diff
# Conflicts:
#	packages/client/src/effect/api/api.ts
#	packages/core/src/session.ts
#	packages/core/test/git.test.ts
#	packages/protocol/src/groups/session.ts
#	packages/server/src/handlers/session-error.ts
#	packages/server/src/handlers/session.ts
2026-09-08 19:30:14 +05:30
Shoubhit Dash 54504ab3a5 fix(client): synthesize idle messages live
The solid data layer mirrors every projected marker message from its event so the in-memory transcript matches the server before the next read; do the same for the idle marker on execution succeeded, failed, and non-shutdown interrupted.
2026-09-07 23:57:17 +05:30
Shoubhit Dash cc5086d127 feat(session): add turn diff route
GET /api/session/:sessionID/diff?messageID&to&context returns FileDiff.Info[] for the turn containing a user message (default: the newest one), or the contiguous range through a later user message's turn. A turn runs from the first prompt after the Session was last idle until its idle marker, so steers belong to the turn they interrupted; Sessions without markers fall back to prompt-to-next-prompt. The diff compares the range's first recorded step snapshot with its last recorded one, or with the working copy only while the Session is actively executing, resolves the snapshot repository from the Location in effect at the range (rejecting ranges that span a move), and defaults to full-file patches like vcs.diff. Shared missingMessage and failedSnapshot handler helpers replace the inlined mappings in the session handlers.
2026-09-07 22:08:19 +05:30
Shoubhit Dash b20482461c feat(session): record idle boundaries as messages
Project an idle message when a busy period ends (execution succeeded, failed, or interrupted for any reason other than shutdown, which resumes the same turn). Every step since the previous marker is one turn, including prompts steered in while the Session was busy, so turns are derivable from session_message alone without persisting events or a separate table. The marker is invisible to the model and to the TUI and web transcripts.
2026-09-07 22:00:36 +05:30
Shoubhit Dash 5b5368fe98 perf(core): batch snapshot tree diffs
Git.tree.diff ran --name-status, --numstat, and a patch once per changed file, sequentially, so a turn or revert touching N files cost 1 + 3N git processes (~50ms per file). Run the three once over the tree pair, split the patch with VcsPatch.chunksByFile, cap patch output at MAX_TOTAL_PATCH_BYTES like VCS diffs (capped files get an empty patch, stats stay exact), keep core.quotepath=false so non-ASCII paths still match their chunk, and pass --no-ext-diff. Snapshot.diff diffs first and filters ignored paths from the result instead of listing changed files twice and passing every path as a pathspec.
2026-09-07 21:53:19 +05:30
4118 changed files with 3515 additions and 194619 deletions
@@ -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
+4 -32
View File
@@ -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
-4
View File
@@ -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)
}),
)
+2 -110
View File
@@ -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" } }
+10 -5
View File
@@ -126,9 +126,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 +326,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,
@@ -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)
}
+12 -20
View File
@@ -11,13 +11,13 @@ 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"
import type { AgentAttachment } from "@opencode/schema/prompt"
import type { Skill } from "@opencode/schema/skill"
import type { Event } from "@opencode/schema/event"
import type { FileDiff } from "@opencode/schema/file-diff"
import type { InstructionEntry } from "@opencode/schema/instruction-entry"
import type { Schema } from "effect"
import type { EventLog } from "@opencode/schema/event-log"
@@ -27,6 +27,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"
@@ -36,7 +37,6 @@ import type { PtyTicket } from "@opencode/schema/pty-ticket"
import type { Reference } from "@opencode/schema/reference"
import type { Worktree } from "@opencode/schema/worktree"
import type { Vcs } from "@opencode/schema/vcs"
import type { FileDiff } from "@opencode/schema/file-diff"
import type { WebSearch } from "@opencode/schema/websearch"
import type { Config } from "@opencode/schema/config"
@@ -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>
@@ -361,6 +360,15 @@ export type SessionContextInput = { readonly sessionID: Session.ID }
export type SessionContextOutput = ReadonlyArray<SessionMessage.Info>
export type SessionContextOperation<E = never> = (input: SessionContextInput) => Effect.Effect<SessionContextOutput, E>
export type SessionDiffInput = {
readonly sessionID: Session.ID
readonly messageID?: SessionMessage.ID | undefined
readonly to?: SessionMessage.ID | undefined
readonly context?: number | undefined
}
export type SessionDiffOutput = ReadonlyArray<FileDiff.Info>
export type SessionDiffOperation<E = never> = (input: SessionDiffInput) => Effect.Effect<SessionDiffOutput, E>
export type SessionInboxListInput = { readonly sessionID: Session.ID }
export type SessionInboxListOutput = ReadonlyArray<SessionInbox.Info>
export type SessionInboxListOperation<E = never> = (
@@ -438,7 +446,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 +498,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
@@ -1150,6 +1148,7 @@ export interface SessionApi<E = never> {
readonly commit: SessionRevertCommitOperation<E>
}
readonly context: SessionContextOperation<E>
readonly diff: SessionDiffOperation<E>
readonly inbox: {
readonly list: SessionInboxListOperation<E>
readonly cancel: SessionInboxCancelOperation<E>
@@ -1596,12 +1595,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 +1602,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 = {
+14 -12
View File
@@ -68,6 +68,8 @@ import type {
SessionRevertCommitOutput,
SessionContextInput,
SessionContextOutput,
SessionDiffInput,
SessionDiffOutput,
SessionInboxListInput,
SessionInboxListOutput,
SessionInboxCancelInput,
@@ -181,8 +183,6 @@ import type {
PermissionGetOutput,
PermissionReplyInput,
PermissionReplyOutput,
PermissionRulesInput,
PermissionRulesOutput,
FileListInput,
FileListOutput,
FileFindInput,
@@ -397,7 +397,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),
@@ -595,6 +594,17 @@ const EndpointSessionContext = (raw: RawClient["server.session"]) => (input: Ses
),
)
const EndpointSessionDiff = (raw: RawClient["server.session"]) => (input: SessionDiffInput) =>
preserveEffect<SessionDiffOutput>()(
raw["session.diff"]({
params: { sessionID: input["sessionID"] },
query: { messageID: input["messageID"], to: input["to"], context: input["context"] },
}).pipe(
Effect.mapError(mapClientError),
Effect.map((value) => value.data),
),
)
const EndpointSessionInboxList = (raw: RawClient["server.session"]) => (input: SessionInboxListInput) =>
preserveEffect<SessionInboxListOutput>()(
raw["session.inbox.list"]({ params: { sessionID: input["sessionID"] } }).pipe(
@@ -734,6 +744,7 @@ const adaptGroupSession = (raw: RawClient["server.session"]) => ({
commit: EndpointSessionRevertCommit(raw),
},
context: EndpointSessionContext(raw),
diff: EndpointSessionDiff(raw),
inbox: {
list: EndpointSessionInboxList(raw),
cancel: EndpointSessionInboxCancel(raw),
@@ -1148,14 +1159,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 +1166,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) =>
+14 -15
View File
@@ -62,6 +62,8 @@ import type {
SessionRevertCommitOutput,
SessionContextInput,
SessionContextOutput,
SessionDiffInput,
SessionDiffOutput,
SessionInboxListInput,
SessionInboxListOutput,
SessionInboxCancelInput,
@@ -175,8 +177,6 @@ import type {
PermissionGetOutput,
PermissionReplyInput,
PermissionReplyOutput,
PermissionRulesInput,
PermissionRulesOutput,
FileReadInput,
FileReadOutput,
FileListInput,
@@ -567,7 +567,6 @@ export function make(options: ClientOptions) {
model: input?.["model"],
location: input?.["location"],
metadata: input?.["metadata"],
permissions: input?.["permissions"],
},
successStatus: 200,
declaredStatuses: [400, 401],
@@ -845,6 +844,18 @@ export function make(options: ClientOptions) {
},
requestOptions,
).then((value) => value.data),
diff: (input: SessionDiffInput, requestOptions?: RequestOptions) =>
request<{ readonly data: SessionDiffOutput }>(
{
method: "GET",
path: `/api/session/${encodeURIComponent(input.sessionID)}/diff`,
query: { messageID: input["messageID"], to: input["to"], context: input["context"] },
successStatus: 200,
declaredStatuses: [400, 401, 404, 500],
empty: false,
},
requestOptions,
).then((value) => value.data),
inbox: {
list: (input: SessionInboxListInput, requestOptions?: RequestOptions) =>
request<{ readonly data: SessionInboxListOutput }>(
@@ -1569,18 +1580,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) =>
+93 -127
View File
@@ -147,6 +147,14 @@ export type SessionProviderContextProvenance = {
endpoint: string
}
export type SessionMessageIdle = {
id: string
metadata?: { [x: string]: JsonValue }
time: { created: number }
type: "idle"
outcome: "succeeded" | "failed" | "interrupted"
}
export type SessionActive = { type: "running" }
export type SessionInboxDelivery = "steer" | "queue"
@@ -551,6 +559,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 +1659,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 +1920,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 +2092,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 +2148,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 = {
@@ -2206,6 +2202,7 @@ export type SessionMessageInfo =
| SessionMessageShell
| SessionMessageAssistant
| SessionMessageCompaction
| SessionMessageIdle
export type SessionMessageContentUpdated = {
id: string
@@ -2245,7 +2242,6 @@ export type SessionEventDurable =
| SessionModelSelected
| SessionMoved
| SessionRenamed
| SessionPermissionsUpdated
| SessionViewed
| SessionDeleted
| SessionForked
@@ -2305,7 +2301,6 @@ export type V2Event =
| SessionModelSelected
| SessionMoved
| SessionRenamed
| SessionPermissionsUpdated
| SessionViewed
| SessionUsageUpdated
| SessionDeleted
@@ -2818,11 +2813,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 +2821,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 +2829,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 +2837,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 +2845,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 +2853,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 +2891,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
@@ -3214,6 +3161,13 @@ export type SessionImportInput = {
}
}
)
| {
readonly id: string
readonly metadata?: { readonly [x: string]: JsonValue }
readonly time: { readonly created: number }
readonly type: "idle"
readonly outcome: "succeeded" | "failed" | "interrupted"
}
>
readonly location?: { readonly directory: string; readonly workspaceID?: string } | null
}["info"]
@@ -3249,11 +3203,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
@@ -3524,6 +3473,13 @@ export type SessionImportInput = {
}
}
)
| {
readonly id: string
readonly metadata?: { readonly [x: string]: JsonValue }
readonly time: { readonly created: number }
readonly type: "idle"
readonly outcome: "succeeded" | "failed" | "interrupted"
}
>
readonly location?: { readonly directory: string; readonly workspaceID?: string } | null
}["messages"]
@@ -3559,11 +3515,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
@@ -3834,6 +3785,13 @@ export type SessionImportInput = {
}
}
)
| {
readonly id: string
readonly metadata?: { readonly [x: string]: JsonValue }
readonly time: { readonly created: number }
readonly type: "idle"
readonly outcome: "succeeded" | "failed" | "interrupted"
}
>
readonly location?: { readonly directory: string; readonly workspaceID?: string } | null
}["location"]
@@ -4323,6 +4281,27 @@ export type SessionContextInput = { readonly sessionID: { readonly sessionID: st
export type SessionContextOutput = { data: Array<SessionMessageInfo> }["data"]
export type SessionDiffInput = {
readonly sessionID: { readonly sessionID: string }["sessionID"]
readonly messageID?: {
readonly messageID?: string | undefined
readonly to?: string | undefined
readonly context?: number | undefined
}["messageID"]
readonly to?: {
readonly messageID?: string | undefined
readonly to?: string | undefined
readonly context?: number | undefined
}["to"]
readonly context?: {
readonly messageID?: string | undefined
readonly to?: string | undefined
readonly context?: number | undefined
}["context"]
}
export type SessionDiffOutput = { data: Array<FileDiffInfo> }["data"]
export type SessionInboxListInput = { readonly sessionID: { readonly sessionID: string }["sessionID"] }
export type SessionInboxListOutput = { data: Array<SessionInboxInfo> }["data"]
@@ -5825,19 +5804,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
+12 -4
View File
@@ -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) {
@@ -1028,6 +1024,18 @@ export function createData(config: CreateDataInput) {
if (currentAssistant) currentAssistant.retry = undefined
})
if (event.type === "session.execution.interrupted" && event.data.reason === "shutdown") return
// Mirror the projected idle marker so turn boundaries match before the next message read.
message.insert(event.data.sessionID, {
id: messageIDFromEvent(event.id),
type: "idle",
outcome:
event.type === "session.execution.succeeded"
? "succeeded"
: event.type === "session.execution.failed"
? "failed"
: "interrupted",
time: { created: event.created },
})
// An event can overtake the first read; queue a revalidation when that read is still active.
if (!store.session.info[event.data.sessionID] && !sync.has(`session:${event.data.sessionID}`)) return
result.session.invalidate(event.data.sessionID)
+1 -29
View File
@@ -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
@@ -417,5 +391,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.
-62
View File
@@ -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`)
}
+1 -10
View File
@@ -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()
+2 -3
View File
@@ -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 })
}
+3 -2
View File
@@ -5,8 +5,9 @@ import { coerceToString } 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)
-20
View File
@@ -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,
)
}
-33
View File
@@ -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.
@@ -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');
@@ -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]'
);
@@ -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'
);
@@ -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]'
);
@@ -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]'
);
@@ -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);
@@ -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]'
);
@@ -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]'
);
@@ -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]'
);
@@ -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]'
);
@@ -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]'
);
@@ -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]'
);
@@ -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]'
);
@@ -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]'
);
@@ -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]
);
@@ -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]'
);
@@ -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);
});
@@ -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);
});
@@ -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);
});
@@ -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]'
);
@@ -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)');
@@ -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`');
@@ -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();
});
@@ -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)');
@@ -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);
});
@@ -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);
});
@@ -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);
});
@@ -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");
});
@@ -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({});
});
@@ -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');
@@ -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)');
@@ -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)');
@@ -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)');
@@ -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)');
@@ -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")');
@@ -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');
@@ -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');
@@ -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)');
@@ -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');
@@ -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');
@@ -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');
@@ -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');
@@ -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');
@@ -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');
@@ -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');
@@ -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');
@@ -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');
@@ -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');
@@ -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');
@@ -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');
@@ -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');
@@ -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');
@@ -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');
@@ -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');
@@ -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');
@@ -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');
@@ -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');
@@ -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');
@@ -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');
@@ -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');
@@ -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');
@@ -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');
@@ -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');
@@ -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]');
@@ -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');
@@ -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_ &lt; 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]'
);
@@ -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]');
@@ -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]'
);
@@ -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]'
);
@@ -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);
});
@@ -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);
});
@@ -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.filter
description: >
Array.prototype.filter doesn't mutate the Array on which it is
called on
---*/
function callbackfn(val, idx, obj)
{
return true;
}
var srcArr = [1, 2, 3, 4, 5];
srcArr.filter(callbackfn);
assert.sameValue(srcArr[0], 1, 'srcArr[0]');
assert.sameValue(srcArr[1], 2, 'srcArr[1]');
assert.sameValue(srcArr[2], 3, 'srcArr[2]');
assert.sameValue(srcArr[3], 4, 'srcArr[3]');
assert.sameValue(srcArr[4], 5, 'srcArr[4]');
@@ -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.filter
description: >
Array.prototype.filter returns new Array with length equal to
number of true returned by callbackfn
---*/
function callbackfn(val, idx, obj)
{
if (val % 2)
return true;
else
return false;
}
var srcArr = [1, 2, 3, 4, 5];
var resArr = srcArr.filter(callbackfn);
assert.sameValue(resArr.length, 3, 'resArr.length');
assert.sameValue(resArr[0], 1, 'resArr[0]');
assert.sameValue(resArr[1], 3, 'resArr[1]');
assert.sameValue(resArr[2], 5, 'resArr[2]');
@@ -1,21 +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.filter
description: Array.prototype.filter doesn't visit expandos
---*/
var callCnt = 0;
function callbackfn(val, idx, obj)
{
callCnt++;
}
var srcArr = [1, 2, 3, 4, 5];
srcArr["i"] = 10;
srcArr[true] = 11;
var resArr = srcArr.filter(callbackfn);
assert.sameValue(callCnt, 5, 'callCnt');
@@ -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.filter
description: Array.prototype.filter - 'length' is own data property on an Array
---*/
function callbackfn(val, idx, obj) {
return obj.length === 2;
}
var newArr = [12, 11].filter(callbackfn);
assert.sameValue(newArr.length, 2, 'newArr.length');
@@ -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.filter
description: Array.prototype.filter throws TypeError if callbackfn is undefined
---*/
var arr = new Array(10);
assert.throws(TypeError, function() {
arr.filter();
});
@@ -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.filter
description: Array.prototype.filter - 'callbackfn' is a function
---*/
function callbackfn(val, idx, obj) {
if (idx === 1) {
return val === 9;
}
return false;
}
var newArr = [11, 9].filter(callbackfn);
assert.sameValue(newArr.length, 1, 'newArr.length');
assert.sameValue(newArr[0], 9, 'newArr[0]');

Some files were not shown because too many files have changed in this diff Show More