@opencode/codemode 2.0.12 → 2.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/data.d.ts +5 -4
- package/dist/interpreter/callback.d.ts +10 -15
- package/dist/interpreter/callback.js +15 -7
- package/dist/interpreter/errors.d.ts +3 -3
- package/dist/interpreter/errors.js +1 -2
- package/dist/interpreter/execute.d.ts +2 -1
- package/dist/interpreter/extensions.d.ts +2 -1
- package/dist/interpreter/extensions.js +7 -35
- package/dist/interpreter/globals.d.ts +2 -1
- package/dist/interpreter/globals.js +1 -1
- package/dist/interpreter/interpreter.d.ts +8 -19
- package/dist/interpreter/interpreter.js +96 -98
- package/dist/interpreter/intrinsics.d.ts +3 -3
- package/dist/interpreter/intrinsics.js +2 -0
- package/dist/interpreter/model.d.ts +7 -8
- package/dist/interpreter/model.js +0 -1
- package/dist/interpreter/native.d.ts +5 -5
- package/dist/interpreter/objects.d.ts +148 -47
- package/dist/interpreter/objects.js +224 -26
- package/dist/interpreter/promises.d.ts +7 -7
- package/dist/interpreter/promises.js +32 -11
- package/dist/interpreter/references.d.ts +8 -7
- package/dist/interpreter/references.js +10 -46
- package/dist/interpreter/scope.d.ts +5 -4
- package/dist/stdlib/array.d.ts +2 -1
- package/dist/stdlib/array.js +29 -51
- package/dist/stdlib/bytes.js +14 -24
- package/dist/stdlib/collections.js +27 -30
- package/dist/stdlib/console.d.ts +2 -2
- package/dist/stdlib/console.js +6 -50
- package/dist/stdlib/date.js +1 -2
- package/dist/stdlib/headers.js +10 -22
- package/dist/stdlib/iterator.d.ts +1 -1
- package/dist/stdlib/iterator.js +294 -6
- package/dist/stdlib/json.js +3 -5
- package/dist/stdlib/math.js +5 -17
- package/dist/stdlib/number.js +8 -21
- package/dist/stdlib/object.d.ts +3 -4
- package/dist/stdlib/object.js +5 -16
- package/dist/stdlib/regexp.d.ts +3 -3
- package/dist/stdlib/regexp.js +1 -2
- package/dist/stdlib/string.js +10 -20
- package/dist/stdlib/url.d.ts +2 -1
- package/dist/stdlib/url.js +6 -16
- package/dist/stdlib/value.d.ts +0 -3
- package/dist/stdlib/value.js +2 -74
- package/dist/stdlib/web.js +1 -2
- package/dist/tool-runtime.js +38 -28
- package/package.json +1 -1
|
@@ -4,7 +4,7 @@ import { CallSite, Throw, rangeError, typeError } from "./model.js";
|
|
|
4
4
|
import { Callable, define, get, hidden, Arr, Fn, Obj, PromiseObj, record } from "./objects.js";
|
|
5
5
|
import { constructor, fn, methods, native, receiver, requiresNew } from "./native.js";
|
|
6
6
|
import { createAggregateErrorValue, locate, materialize, normalizeError } from "./errors.js";
|
|
7
|
-
import { typeofValue } from "./references.js";
|
|
7
|
+
import { describeValue, typeofValue } from "./references.js";
|
|
8
8
|
import { applyCollectionCallback, isSupportedCallback } from "./callback.js";
|
|
9
9
|
// A `resolve`/`reject` handed to an executor or thenable: calling it settles the capability.
|
|
10
10
|
const capability = (ctx, name, settle) => fn(ctx.builtins, name, 1, (_, args) => {
|
|
@@ -119,7 +119,7 @@ export const resolvePromise = (ctx, value) => {
|
|
|
119
119
|
return Effect.succeed(value);
|
|
120
120
|
return ctx.pending.createWithSelf((self) => resolvePromiseValue(ctx, value, self));
|
|
121
121
|
};
|
|
122
|
-
const promiseStatics = ["all", "allSettled", "race", "any", "resolve", "reject"];
|
|
122
|
+
const promiseStatics = ["all", "allSettled", "race", "any", "resolve", "reject", "withResolvers", "try"];
|
|
123
123
|
const invokePromiseMethod = (ctx, name, args) => {
|
|
124
124
|
if (name === "resolve") {
|
|
125
125
|
return resolvePromise(ctx, args[0]);
|
|
@@ -127,10 +127,26 @@ const invokePromiseMethod = (ctx, name, args) => {
|
|
|
127
127
|
if (name === "reject") {
|
|
128
128
|
return ctx.pending.create(Effect.fail(new Throw(args[0])));
|
|
129
129
|
}
|
|
130
|
+
if (name === "withResolvers") {
|
|
131
|
+
return Effect.map(promiseCapability(ctx), (made) => record(ctx.builtins.Object, { promise: made.promise, resolve: made.resolve, reject: made.reject }));
|
|
132
|
+
}
|
|
133
|
+
if (name === "try") {
|
|
134
|
+
if (typeofValue(args[0]) !== "function") {
|
|
135
|
+
throw typeError(`Promise.try expects a function, received ${describeValue(args[0])}.`);
|
|
136
|
+
}
|
|
137
|
+
return Effect.flatMap(Effect.exit(ctx.call(args[0], undefined, args.slice(1))), (called) => {
|
|
138
|
+
if (Exit.isSuccess(called))
|
|
139
|
+
return resolvePromise(ctx, called.value);
|
|
140
|
+
if (Cause.hasInterruptsOnly(called.cause))
|
|
141
|
+
return Effect.failCause(called.cause);
|
|
142
|
+
return ctx.pending.create(Effect.fail(Cause.squash(called.cause)));
|
|
143
|
+
});
|
|
144
|
+
}
|
|
130
145
|
return ctx.pending.create(Effect.gen(function* () {
|
|
131
146
|
const cursor = yield* ctx.iterate(args[0]);
|
|
132
|
-
if (cursor === undefined)
|
|
133
|
-
throw typeError(`Promise.${name} expects
|
|
147
|
+
if (cursor === undefined) {
|
|
148
|
+
throw typeError(`Promise.${name} expects a synchronous iterable, received ${describeValue(args[0])}.`);
|
|
149
|
+
}
|
|
134
150
|
const items = [];
|
|
135
151
|
while (true) {
|
|
136
152
|
const step = yield* cursor.next;
|
|
@@ -188,22 +204,27 @@ const instanceMethod = (ctx, name, thisValue, args) => {
|
|
|
188
204
|
const onRejected = reactionHandler(name === "then" ? args[1] : args[0], method);
|
|
189
205
|
return chainReaction(ctx, promise, onFulfilled, onRejected, method);
|
|
190
206
|
};
|
|
207
|
+
/** NewPromiseCapability: a pending promise with the resolve/reject callables that settle it exactly once. */
|
|
208
|
+
const promiseCapability = (ctx) => Effect.gen(function* () {
|
|
209
|
+
const deferred = Deferred.makeUnsafe();
|
|
210
|
+
const promise = yield* ctx.pending.createWithSelf((self) => Effect.flatMap(Deferred.await(deferred), (value) => resolvePromiseValue(ctx, value, self)));
|
|
211
|
+
const resolve = capability(ctx, "resolve", (value) => Deferred.doneUnsafe(deferred, Exit.succeed(value)));
|
|
212
|
+
const reject = capability(ctx, "reject", (value) => Deferred.doneUnsafe(deferred, Exit.fail(new Throw(value))));
|
|
213
|
+
return { promise, resolve, reject, deferred };
|
|
214
|
+
});
|
|
191
215
|
const constructPromise = (ctx, executor) => {
|
|
192
216
|
if (!(executor instanceof Fn)) {
|
|
193
217
|
throw typeError("new Promise(...) expects an executor function (e.g. new Promise((resolve, reject) => { ... })).");
|
|
194
218
|
}
|
|
195
219
|
return Effect.gen(function* () {
|
|
196
|
-
const
|
|
197
|
-
const
|
|
198
|
-
const resolve = capability(ctx, "resolve", (value) => Deferred.doneUnsafe(deferred, Exit.succeed(value)));
|
|
199
|
-
const reject = capability(ctx, "reject", (value) => Deferred.doneUnsafe(deferred, Exit.fail(new Throw(value))));
|
|
200
|
-
const executed = yield* Effect.exit(ctx.call(executor, undefined, [resolve, reject]));
|
|
220
|
+
const made = yield* promiseCapability(ctx);
|
|
221
|
+
const executed = yield* Effect.exit(ctx.call(executor, undefined, [made.resolve, made.reject]));
|
|
201
222
|
if (!Exit.isSuccess(executed)) {
|
|
202
223
|
if (Cause.hasInterruptsOnly(executed.cause))
|
|
203
224
|
return yield* Effect.failCause(executed.cause);
|
|
204
|
-
Deferred.doneUnsafe(deferred, Exit.fail(Cause.squash(executed.cause)));
|
|
225
|
+
Deferred.doneUnsafe(made.deferred, Exit.fail(Cause.squash(executed.cause)));
|
|
205
226
|
}
|
|
206
|
-
return promise;
|
|
227
|
+
return made.promise;
|
|
207
228
|
});
|
|
208
229
|
};
|
|
209
230
|
// Settle one reaction turn after the deciding member, after its existing reactions.
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export declare const
|
|
4
|
-
export declare const
|
|
5
|
-
export declare const
|
|
6
|
-
export declare const
|
|
7
|
-
export declare const
|
|
1
|
+
import { Obj, type Value } from "./objects.js";
|
|
2
|
+
/** Interpreter machinery that is never data, unlike a Date or Map, which cross some boundaries as copies. */
|
|
3
|
+
export declare const isOpaque: (value: Value) => boolean;
|
|
4
|
+
export declare const containsRuntimeReference: (value: Value) => boolean;
|
|
5
|
+
export declare const containsOpaqueReference: (value: Value) => boolean;
|
|
6
|
+
export declare const rejectCircularInsertion: (container: Obj, value: Value, label: string, seen?: Set<object>) => void;
|
|
7
|
+
export declare const describeValue: (value: Value) => string;
|
|
8
|
+
export declare const typeofValue: (value: Value) => string;
|
|
@@ -1,19 +1,8 @@
|
|
|
1
1
|
import { ToolReference } from "../tool-runtime.js";
|
|
2
2
|
import { invalidData } from "./model.js";
|
|
3
|
-
import { Callable, getOwn,
|
|
4
|
-
/**
|
|
5
|
-
export const
|
|
6
|
-
value instanceof GeneratorObj ||
|
|
7
|
-
value instanceof IteratorObj ||
|
|
8
|
-
value instanceof ToolReference ||
|
|
9
|
-
value instanceof PromiseObj ||
|
|
10
|
-
isWrapper(value);
|
|
11
|
-
function* childValues(value) {
|
|
12
|
-
if (!(value instanceof Obj))
|
|
13
|
-
return;
|
|
14
|
-
for (const key of ownKeys(value))
|
|
15
|
-
yield getOwn(value, key);
|
|
16
|
-
}
|
|
3
|
+
import { Callable, getOwn, isRuntimeReference, Obj, Opaque, ownKeys } from "./objects.js";
|
|
4
|
+
/** Interpreter machinery that is never data, unlike a Date or Map, which cross some boundaries as copies. */
|
|
5
|
+
export const isOpaque = (value) => value instanceof Opaque || value instanceof ToolReference;
|
|
17
6
|
// Depth-first search over a value tree. `match` stops the walk; `skip` prunes a subtree without matching it.
|
|
18
7
|
const find = (value, match, skip, seen) => {
|
|
19
8
|
const pending = [[value].values()];
|
|
@@ -26,17 +15,18 @@ const find = (value, match, skip, seen) => {
|
|
|
26
15
|
const current = next.value;
|
|
27
16
|
if (match(current))
|
|
28
17
|
return true;
|
|
29
|
-
if (current
|
|
18
|
+
if (!(current instanceof Obj) || skip(current) || seen.has(current))
|
|
30
19
|
continue;
|
|
31
20
|
seen.add(current);
|
|
32
|
-
pending.push(
|
|
21
|
+
pending.push(ownKeys(current)
|
|
22
|
+
.map((key) => getOwn(current, key))
|
|
23
|
+
.values());
|
|
33
24
|
}
|
|
34
25
|
return false;
|
|
35
26
|
};
|
|
36
27
|
const never = () => false;
|
|
37
28
|
export const containsRuntimeReference = (value) => find(value, isRuntimeReference, never, new Set());
|
|
38
|
-
|
|
39
|
-
export const containsOpaqueReference = (value) => find(value, (current) => !isWrapper(current) && isRuntimeReference(current), isWrapper, new Set());
|
|
29
|
+
export const containsOpaqueReference = (value) => find(value, isOpaque, (current) => isRuntimeReference(current) && !isOpaque(current), new Set());
|
|
40
30
|
// Reject cycles before mutation so later boundary walks remain safe.
|
|
41
31
|
export const rejectCircularInsertion = (container, value, label, seen = new Set()) => {
|
|
42
32
|
if (find(value, (current) => current === container, isRuntimeReference, seen)) {
|
|
@@ -46,36 +36,10 @@ export const rejectCircularInsertion = (container, value, label, seen = new Set(
|
|
|
46
36
|
export const describeValue = (value) => {
|
|
47
37
|
if (value === null || value === undefined)
|
|
48
38
|
return String(value);
|
|
49
|
-
if (value instanceof
|
|
50
|
-
return
|
|
51
|
-
if (value instanceof PromiseObj)
|
|
52
|
-
return "an un-awaited Promise";
|
|
39
|
+
if (value instanceof Obj)
|
|
40
|
+
return value.describe;
|
|
53
41
|
if (value instanceof ToolReference)
|
|
54
42
|
return "a tool reference";
|
|
55
|
-
if (value instanceof DateObj)
|
|
56
|
-
return "a Date";
|
|
57
|
-
if (value instanceof RegExpObj)
|
|
58
|
-
return "a RegExp";
|
|
59
|
-
if (value instanceof MapObj)
|
|
60
|
-
return "a Map";
|
|
61
|
-
if (value instanceof SetObj)
|
|
62
|
-
return "a Set";
|
|
63
|
-
if (value instanceof URLObj)
|
|
64
|
-
return "a URL";
|
|
65
|
-
if (value instanceof URLSearchParamsObj)
|
|
66
|
-
return "a URLSearchParams";
|
|
67
|
-
if (value instanceof HeadersObj)
|
|
68
|
-
return "a Headers";
|
|
69
|
-
if (value instanceof Bytes)
|
|
70
|
-
return "a Uint8Array";
|
|
71
|
-
if (value instanceof GeneratorObj)
|
|
72
|
-
return "a generator";
|
|
73
|
-
if (value instanceof IteratorObj)
|
|
74
|
-
return "an iterator";
|
|
75
|
-
if (isRuntimeReference(value))
|
|
76
|
-
return "a function";
|
|
77
|
-
if (typeof value === "object")
|
|
78
|
-
return "a data object";
|
|
79
43
|
return `a ${typeof value}`;
|
|
80
44
|
};
|
|
81
45
|
export const typeofValue = (value) => {
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { type AstNode, type Binding } from "./model.js";
|
|
2
|
+
import type { Value } from "./objects.js";
|
|
2
3
|
export declare class ScopeStack {
|
|
3
4
|
private readonly scopes;
|
|
4
5
|
constructor(scopes: Array<Map<string, Binding>>);
|
|
5
6
|
reserve(name: string, mutable: boolean, node: AstNode): void;
|
|
6
|
-
initialize(name: string, value:
|
|
7
|
-
declare(name: string, value:
|
|
8
|
-
get(name: string, node: AstNode):
|
|
9
|
-
set(name: string, value:
|
|
7
|
+
initialize(name: string, value: Value, node: AstNode): void;
|
|
8
|
+
declare(name: string, value: Value, mutable: boolean, node: AstNode): void;
|
|
9
|
+
get(name: string, node: AstNode): Value;
|
|
10
|
+
set(name: string, value: Value, node: AstNode): Value;
|
|
10
11
|
resolve(name: string): Binding | undefined;
|
|
11
12
|
current(): Map<string, Binding>;
|
|
12
13
|
push(scope?: Map<string, Binding>): void;
|
package/dist/stdlib/array.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
|
+
import { type Value } from "../interpreter/objects.js";
|
|
2
3
|
import type { Interpreter } from "../interpreter/interpreter.js";
|
|
3
|
-
export declare const sortArray: <R>(ctx: Interpreter<R>, target: Array<
|
|
4
|
+
export declare const sortArray: <R>(ctx: Interpreter<R>, target: Array<Value>, comparator: Value, name: string) => Effect.Effect<Array<Value>, unknown, R>;
|
|
4
5
|
export declare const arrayGlobal: <R>(ctx: Interpreter<R>) => import("../interpreter/objects.js").Native<R>;
|
package/dist/stdlib/array.js
CHANGED
|
@@ -2,19 +2,18 @@ import { Effect } from "effect";
|
|
|
2
2
|
import { constructor, methods, prototypeFrom, receiver } from "../interpreter/native.js";
|
|
3
3
|
import { checkArrayLength, checkStringLength, MAX_ARRAY_LENGTH } from "../interpreter/limits.js";
|
|
4
4
|
import { invalidData, IteratorSymbol, rangeError, typeError } from "../interpreter/model.js";
|
|
5
|
-
import { define, get, hidden, Arr, GeneratorObj,
|
|
5
|
+
import { define, get, hidden, Arr, GeneratorObj, hostIterator, Obj, PromiseObj, coerceToInteger, coerceToNumber, coerceToString, } from "../interpreter/objects.js";
|
|
6
6
|
import { describeValue, rejectCircularInsertion } from "../interpreter/references.js";
|
|
7
7
|
import { applyCollectionCallback, invoke, preserveConsumerError } from "../interpreter/callback.js";
|
|
8
8
|
import { compareText } from "../tool-runtime.js";
|
|
9
|
-
import { coerceToNumber, coerceToString } from "./value.js";
|
|
10
9
|
const arrayLikeSource = (source) => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
checkArrayLength(
|
|
15
|
-
return { length
|
|
10
|
+
// JS would treat a promise as an empty array-like; that would hide a missing `await`.
|
|
11
|
+
if (source instanceof Obj && !(source instanceof PromiseObj)) {
|
|
12
|
+
const length = Math.max(0, coerceToInteger(get(source, "length")));
|
|
13
|
+
checkArrayLength(length);
|
|
14
|
+
return { length, source };
|
|
16
15
|
}
|
|
17
|
-
throw invalidData(`Array.from expects an
|
|
16
|
+
throw invalidData(`Array.from expects an iterable or array-like value, received ${describeValue(source)}.`);
|
|
18
17
|
};
|
|
19
18
|
const arrayFrom = (ctx, args) => {
|
|
20
19
|
const source = args[0];
|
|
@@ -24,7 +23,7 @@ const arrayFrom = (ctx, args) => {
|
|
|
24
23
|
const cursor = yield* ctx.iterate(source);
|
|
25
24
|
if (cursor === undefined) {
|
|
26
25
|
if (source instanceof GeneratorObj) {
|
|
27
|
-
throw typeError(
|
|
26
|
+
throw typeError(`Array.from expects a synchronous iterable or array-like value, received ${describeValue(source)}.`);
|
|
28
27
|
}
|
|
29
28
|
const arrayLike = arrayLikeSource(source);
|
|
30
29
|
const values = [];
|
|
@@ -40,7 +39,7 @@ const arrayFrom = (ctx, args) => {
|
|
|
40
39
|
const step = yield* cursor.next;
|
|
41
40
|
if (step.done)
|
|
42
41
|
return new Arr(proto, values);
|
|
43
|
-
values.push(apply === undefined ? step.value : yield* preserveConsumerError(cursor, apply([step.value, index])));
|
|
42
|
+
values.push(apply === undefined ? step.value : yield* preserveConsumerError(cursor.close, apply([step.value, index])));
|
|
44
43
|
index += 1;
|
|
45
44
|
}
|
|
46
45
|
});
|
|
@@ -103,14 +102,7 @@ export const arrayGlobal = (ctx) => {
|
|
|
103
102
|
["from", 1, (_, args) => arrayFrom(ctx, args)],
|
|
104
103
|
]);
|
|
105
104
|
const self = (thisValue, name) => receiver(Arr, thisValue, `Array.prototype.${name}`);
|
|
106
|
-
const optNumber = (
|
|
107
|
-
if (value === undefined)
|
|
108
|
-
return undefined;
|
|
109
|
-
if (typeof value !== "number") {
|
|
110
|
-
throw typeError(`Array.${name} expects ${label} to be a number.`);
|
|
111
|
-
}
|
|
112
|
-
return value;
|
|
113
|
-
};
|
|
105
|
+
const optNumber = (value) => (value === undefined ? undefined : coerceToInteger(value));
|
|
114
106
|
// Callback methods fix the iteration length while reading existing elements live.
|
|
115
107
|
const iterate = (name, length, body) => [
|
|
116
108
|
name,
|
|
@@ -125,13 +117,9 @@ export const arrayGlobal = (ctx) => {
|
|
|
125
117
|
"join",
|
|
126
118
|
1,
|
|
127
119
|
(thisValue, args) => {
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
const joined = target
|
|
133
|
-
.map((item) => coerceToString(item ?? ""))
|
|
134
|
-
.join(args.length === 0 ? "," : args[0]);
|
|
120
|
+
const joined = self(thisValue, "join")
|
|
121
|
+
.items.map((item) => coerceToString(item ?? ""))
|
|
122
|
+
.join(args[0] === undefined ? "," : coerceToString(args[0]));
|
|
135
123
|
checkStringLength(joined.length);
|
|
136
124
|
return joined;
|
|
137
125
|
},
|
|
@@ -147,33 +135,23 @@ export const arrayGlobal = (ctx) => {
|
|
|
147
135
|
"includes",
|
|
148
136
|
1,
|
|
149
137
|
(thisValue, args) => {
|
|
150
|
-
|
|
151
|
-
if (args.length === 0 || args.length > 2) {
|
|
152
|
-
throw typeError("Array.includes expects a value and optional start index.");
|
|
153
|
-
}
|
|
154
|
-
return target.includes(args[0], optNumber("includes", args[1], "start index"));
|
|
138
|
+
return self(thisValue, "includes").items.includes(args[0], optNumber(args[1]));
|
|
155
139
|
},
|
|
156
140
|
],
|
|
157
|
-
[
|
|
158
|
-
"indexOf",
|
|
159
|
-
1,
|
|
160
|
-
(thisValue, args) => self(thisValue, "indexOf").items.indexOf(args[0], optNumber("indexOf", args[1], "start index")),
|
|
161
|
-
],
|
|
141
|
+
["indexOf", 1, (thisValue, args) => self(thisValue, "indexOf").items.indexOf(args[0], optNumber(args[1]))],
|
|
162
142
|
[
|
|
163
143
|
"lastIndexOf",
|
|
164
144
|
1,
|
|
165
145
|
(thisValue, args) => {
|
|
166
146
|
const target = self(thisValue, "lastIndexOf").items;
|
|
167
|
-
return args[1] === undefined
|
|
168
|
-
? target.lastIndexOf(args[0])
|
|
169
|
-
: target.lastIndexOf(args[0], optNumber("lastIndexOf", args[1], "start index"));
|
|
147
|
+
return args[1] === undefined ? target.lastIndexOf(args[0]) : target.lastIndexOf(args[0], optNumber(args[1]));
|
|
170
148
|
},
|
|
171
149
|
],
|
|
172
|
-
["at", 1, (thisValue, args) => self(thisValue, "at").items.at(optNumber(
|
|
150
|
+
["at", 1, (thisValue, args) => self(thisValue, "at").items.at(optNumber(args[0]) ?? 0)],
|
|
173
151
|
[
|
|
174
152
|
"slice",
|
|
175
153
|
2,
|
|
176
|
-
(thisValue, args) => wrap(self(thisValue, "slice").items.slice(optNumber(
|
|
154
|
+
(thisValue, args) => wrap(self(thisValue, "slice").items.slice(optNumber(args[0]), optNumber(args[1]))),
|
|
177
155
|
],
|
|
178
156
|
[
|
|
179
157
|
"concat",
|
|
@@ -189,7 +167,7 @@ export const arrayGlobal = (ctx) => {
|
|
|
189
167
|
0,
|
|
190
168
|
(thisValue, args) => {
|
|
191
169
|
const flatten = (items, depth) => items.flatMap((item) => (item instanceof Arr && depth > 0 ? flatten(item.items, depth - 1) : [item]));
|
|
192
|
-
const flattened = flatten(self(thisValue, "flat").items, optNumber(
|
|
170
|
+
const flattened = flatten(self(thisValue, "flat").items, optNumber(args[0]) ?? 1);
|
|
193
171
|
checkArrayLength(flattened.length);
|
|
194
172
|
return wrap(flattened);
|
|
195
173
|
},
|
|
@@ -234,7 +212,7 @@ export const arrayGlobal = (ctx) => {
|
|
|
234
212
|
2,
|
|
235
213
|
(thisValue, args) => {
|
|
236
214
|
const target = self(thisValue, "with").items;
|
|
237
|
-
const index = optNumber(
|
|
215
|
+
const index = optNumber(args[0]) ?? 0;
|
|
238
216
|
const resolved = index < 0 ? target.length + index : index;
|
|
239
217
|
if (resolved < 0 || resolved >= target.length)
|
|
240
218
|
throw rangeError("Array.with index is out of range.");
|
|
@@ -273,10 +251,10 @@ export const arrayGlobal = (ctx) => {
|
|
|
273
251
|
const target = self(thisValue, "splice");
|
|
274
252
|
if (args.length === 0)
|
|
275
253
|
return wrap(target.items.splice(0, 0));
|
|
276
|
-
const start = optNumber(
|
|
254
|
+
const start = optNumber(args[0]) ?? 0;
|
|
277
255
|
if (args.length === 1)
|
|
278
256
|
return wrap(target.items.splice(start));
|
|
279
|
-
const deleteCount = optNumber(
|
|
257
|
+
const deleteCount = optNumber(args[1]) ?? 0;
|
|
280
258
|
const inserted = args.slice(2);
|
|
281
259
|
for (const item of inserted)
|
|
282
260
|
rejectCircularInsertion(target, item, "Array.splice result");
|
|
@@ -290,11 +268,11 @@ export const arrayGlobal = (ctx) => {
|
|
|
290
268
|
const copied = [...self(thisValue, "toSpliced").items];
|
|
291
269
|
if (args.length === 0)
|
|
292
270
|
return wrap(copied);
|
|
293
|
-
const start = optNumber(
|
|
271
|
+
const start = optNumber(args[0]) ?? 0;
|
|
294
272
|
if (args.length === 1)
|
|
295
273
|
copied.splice(start);
|
|
296
274
|
else
|
|
297
|
-
copied.splice(start, optNumber(
|
|
275
|
+
copied.splice(start, optNumber(args[1]) ?? 0, ...args.slice(2));
|
|
298
276
|
return wrap(copied);
|
|
299
277
|
},
|
|
300
278
|
],
|
|
@@ -304,7 +282,7 @@ export const arrayGlobal = (ctx) => {
|
|
|
304
282
|
(thisValue, args) => {
|
|
305
283
|
const target = self(thisValue, "fill");
|
|
306
284
|
rejectCircularInsertion(target, args[0], "Array.fill result");
|
|
307
|
-
target.items.fill(args[0], optNumber(
|
|
285
|
+
target.items.fill(args[0], optNumber(args[1]), optNumber(args[2]));
|
|
308
286
|
return target;
|
|
309
287
|
},
|
|
310
288
|
],
|
|
@@ -313,7 +291,7 @@ export const arrayGlobal = (ctx) => {
|
|
|
313
291
|
2,
|
|
314
292
|
(thisValue, args) => {
|
|
315
293
|
const target = self(thisValue, "copyWithin");
|
|
316
|
-
target.items.copyWithin(optNumber(
|
|
294
|
+
target.items.copyWithin(optNumber(args[0]) ?? 0, optNumber(args[1]) ?? 0, optNumber(args[2]));
|
|
317
295
|
return target;
|
|
318
296
|
},
|
|
319
297
|
],
|
|
@@ -324,12 +302,12 @@ export const arrayGlobal = (ctx) => {
|
|
|
324
302
|
? Effect.succeed("")
|
|
325
303
|
: Effect.map(invoke(ctx, item, "toLocaleString", "Array.prototype.toLocaleString"), coerceToString)), (parts) => parts.join(",")),
|
|
326
304
|
],
|
|
327
|
-
["keys", 0, (thisValue) =>
|
|
328
|
-
["values", 0, (thisValue) =>
|
|
305
|
+
["keys", 0, (thisValue) => hostIterator(builtins, self(thisValue, "keys").items.keys())],
|
|
306
|
+
["values", 0, (thisValue) => hostIterator(builtins, self(thisValue, "values").items.values())],
|
|
329
307
|
[
|
|
330
308
|
"entries",
|
|
331
309
|
0,
|
|
332
|
-
(thisValue) =>
|
|
310
|
+
(thisValue) => hostIterator(builtins, self(thisValue, "entries")
|
|
333
311
|
.items.entries()
|
|
334
312
|
.map(([index, item]) => wrap([index, item]))),
|
|
335
313
|
],
|
package/dist/stdlib/bytes.js
CHANGED
|
@@ -2,9 +2,8 @@ import { Effect } from "effect";
|
|
|
2
2
|
import { checkArrayLength, checkStringLength } from "../interpreter/limits.js";
|
|
3
3
|
import { constructor, methods, prototypeFrom, receiver, requiresNew } from "../interpreter/native.js";
|
|
4
4
|
import { IteratorSymbol, rangeError, syntaxError, typeError } from "../interpreter/model.js";
|
|
5
|
-
import { define, defineAccessor, get, hidden, Arr, Bytes,
|
|
5
|
+
import { define, defineAccessor, get, hidden, Arr, Bytes, hostIterator, Obj, coerceToInteger, coerceToNumber, coerceToString, } from "../interpreter/objects.js";
|
|
6
6
|
import { describeValue } from "../interpreter/references.js";
|
|
7
|
-
import { coerceToNumber, coerceToString } from "./value.js";
|
|
8
7
|
/** The bytes a Uint8Array, array, or other iterable of numbers describes; the host array clamps each value. */
|
|
9
8
|
const collectBytes = (ctx, source, name) => {
|
|
10
9
|
if (source instanceof Bytes)
|
|
@@ -62,34 +61,28 @@ export const uint8ArrayGlobal = (ctx) => {
|
|
|
62
61
|
["fromHex", 1, (_, args) => decode("fromHex", args, (text) => Uint8Array.fromHex(text))],
|
|
63
62
|
]);
|
|
64
63
|
const self = (thisValue, name) => receiver(Bytes, thisValue, `Uint8Array.prototype.${name}`);
|
|
65
|
-
const optNumber = (
|
|
66
|
-
if (value === undefined)
|
|
67
|
-
return undefined;
|
|
68
|
-
if (typeof value !== "number")
|
|
69
|
-
throw typeError(`Uint8Array.${name} expects ${label} to be a number.`);
|
|
70
|
-
return value;
|
|
71
|
-
};
|
|
64
|
+
const optNumber = (value) => (value === undefined ? undefined : coerceToInteger(value));
|
|
72
65
|
const wrapAll = (items) => new Arr(builtins.Array, items);
|
|
73
66
|
defineAccessor(proto, "length", (thisValue) => self(thisValue, "length").bytes.length);
|
|
74
67
|
methods(builtins, proto, [
|
|
75
|
-
["at", 1, (thisValue, args) => self(thisValue, "at").bytes.at(optNumber(
|
|
68
|
+
["at", 1, (thisValue, args) => self(thisValue, "at").bytes.at(optNumber(args[0]) ?? 0)],
|
|
76
69
|
[
|
|
77
70
|
"slice",
|
|
78
71
|
2,
|
|
79
|
-
(thisValue, args) => wrap(self(thisValue, "slice").bytes.slice(optNumber(
|
|
72
|
+
(thisValue, args) => wrap(self(thisValue, "slice").bytes.slice(optNumber(args[0]), optNumber(args[1]))),
|
|
80
73
|
],
|
|
81
74
|
// A view on the same bytes, as in JS: writes through one are visible through the other.
|
|
82
75
|
[
|
|
83
76
|
"subarray",
|
|
84
77
|
2,
|
|
85
|
-
(thisValue, args) => wrap(self(thisValue, "subarray").bytes.subarray(optNumber(
|
|
78
|
+
(thisValue, args) => wrap(self(thisValue, "subarray").bytes.subarray(optNumber(args[0]), optNumber(args[1]))),
|
|
86
79
|
],
|
|
87
80
|
[
|
|
88
81
|
"set",
|
|
89
82
|
1,
|
|
90
83
|
(thisValue, args) => {
|
|
91
84
|
const target = self(thisValue, "set");
|
|
92
|
-
const offset = optNumber(
|
|
85
|
+
const offset = optNumber(args[1]) ?? 0;
|
|
93
86
|
return Effect.map(collectBytes(ctx, args[0], "Uint8Array.set"), (source) => {
|
|
94
87
|
if (!Number.isInteger(offset) || offset < 0 || source.length + offset > target.bytes.length) {
|
|
95
88
|
throw rangeError("Uint8Array.set: the source does not fit at that offset.");
|
|
@@ -104,7 +97,7 @@ export const uint8ArrayGlobal = (ctx) => {
|
|
|
104
97
|
1,
|
|
105
98
|
(thisValue, args) => {
|
|
106
99
|
const target = self(thisValue, "fill");
|
|
107
|
-
target.bytes.fill(coerceToNumber(args[0]), optNumber(
|
|
100
|
+
target.bytes.fill(coerceToNumber(args[0]), optNumber(args[1]), optNumber(args[2]));
|
|
108
101
|
return target;
|
|
109
102
|
},
|
|
110
103
|
],
|
|
@@ -120,7 +113,7 @@ export const uint8ArrayGlobal = (ctx) => {
|
|
|
120
113
|
[
|
|
121
114
|
"indexOf",
|
|
122
115
|
1,
|
|
123
|
-
(thisValue, args) => self(thisValue, "indexOf").bytes.indexOf(coerceToNumber(args[0]), optNumber(
|
|
116
|
+
(thisValue, args) => self(thisValue, "indexOf").bytes.indexOf(coerceToNumber(args[0]), optNumber(args[1])),
|
|
124
117
|
],
|
|
125
118
|
[
|
|
126
119
|
"lastIndexOf",
|
|
@@ -129,22 +122,19 @@ export const uint8ArrayGlobal = (ctx) => {
|
|
|
129
122
|
const target = self(thisValue, "lastIndexOf").bytes;
|
|
130
123
|
return args[1] === undefined
|
|
131
124
|
? target.lastIndexOf(coerceToNumber(args[0]))
|
|
132
|
-
: target.lastIndexOf(coerceToNumber(args[0]), optNumber(
|
|
125
|
+
: target.lastIndexOf(coerceToNumber(args[0]), optNumber(args[1]));
|
|
133
126
|
},
|
|
134
127
|
],
|
|
135
128
|
[
|
|
136
129
|
"includes",
|
|
137
130
|
1,
|
|
138
|
-
(thisValue, args) => self(thisValue, "includes").bytes.includes(coerceToNumber(args[0]), optNumber(
|
|
131
|
+
(thisValue, args) => self(thisValue, "includes").bytes.includes(coerceToNumber(args[0]), optNumber(args[1])),
|
|
139
132
|
],
|
|
140
133
|
[
|
|
141
134
|
"join",
|
|
142
135
|
1,
|
|
143
136
|
(thisValue, args) => {
|
|
144
|
-
|
|
145
|
-
throw typeError("Uint8Array.join expects zero arguments or one string separator.");
|
|
146
|
-
}
|
|
147
|
-
const joined = self(thisValue, "join").bytes.join(args.length === 0 ? "," : args[0]);
|
|
137
|
+
const joined = self(thisValue, "join").bytes.join(args[0] === undefined ? "," : coerceToString(args[0]));
|
|
148
138
|
checkStringLength(joined.length);
|
|
149
139
|
return joined;
|
|
150
140
|
},
|
|
@@ -152,12 +142,12 @@ export const uint8ArrayGlobal = (ctx) => {
|
|
|
152
142
|
["toString", 0, (thisValue) => self(thisValue, "toString").bytes.join(",")],
|
|
153
143
|
["toBase64", 0, (thisValue) => self(thisValue, "toBase64").bytes.toBase64()],
|
|
154
144
|
["toHex", 0, (thisValue) => self(thisValue, "toHex").bytes.toHex()],
|
|
155
|
-
["keys", 0, (thisValue) =>
|
|
156
|
-
["values", 0, (thisValue) =>
|
|
145
|
+
["keys", 0, (thisValue) => hostIterator(builtins, self(thisValue, "keys").bytes.keys())],
|
|
146
|
+
["values", 0, (thisValue) => hostIterator(builtins, self(thisValue, "values").bytes.values())],
|
|
157
147
|
[
|
|
158
148
|
"entries",
|
|
159
149
|
0,
|
|
160
|
-
(thisValue) =>
|
|
150
|
+
(thisValue) => hostIterator(builtins, self(thisValue, "entries")
|
|
161
151
|
.bytes.entries()
|
|
162
152
|
.map(([index, byte]) => wrapAll([index, byte]))),
|
|
163
153
|
],
|