@opencode/codemode 0.0.0-dev-19631 → 0.0.0-dev-19634
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/codemode.js +1 -1
- package/dist/data.d.ts +3 -3
- package/dist/data.js +37 -31
- package/dist/interpreter/callback.d.ts +20 -0
- package/dist/interpreter/{runner.js → callback.js} +10 -10
- package/dist/interpreter/errors.d.ts +5 -5
- package/dist/interpreter/errors.js +21 -22
- package/dist/interpreter/execute.d.ts +2 -2
- package/dist/interpreter/execute.js +11 -11
- package/dist/interpreter/extensions.d.ts +2 -2
- package/dist/interpreter/extensions.js +42 -36
- package/dist/interpreter/generators.d.ts +2 -3
- package/dist/interpreter/generators.js +8 -8
- package/dist/interpreter/globals.d.ts +2 -12
- package/dist/interpreter/globals.js +41 -37
- package/dist/interpreter/interpreter.d.ts +31 -0
- package/dist/interpreter/{runtime.js → interpreter.js} +118 -117
- package/dist/interpreter/intrinsics.d.ts +5 -5
- package/dist/interpreter/intrinsics.js +16 -10
- package/dist/interpreter/model.d.ts +3 -3
- package/dist/interpreter/model.js +1 -1
- package/dist/interpreter/native.d.ts +9 -9
- package/dist/interpreter/native.js +9 -9
- package/dist/interpreter/objects.d.ts +51 -46
- package/dist/interpreter/objects.js +57 -40
- package/dist/interpreter/promises.d.ts +13 -13
- package/dist/interpreter/promises.js +70 -70
- package/dist/interpreter/references.js +17 -15
- package/dist/openapi/types.d.ts +1 -1
- package/dist/stdlib/array.d.ts +3 -3
- package/dist/stdlib/array.js +31 -31
- package/dist/stdlib/bytes.d.ts +10 -0
- package/dist/stdlib/bytes.js +228 -0
- package/dist/stdlib/collections.d.ts +4 -4
- package/dist/stdlib/collections.js +55 -55
- package/dist/stdlib/console.d.ts +3 -3
- package/dist/stdlib/console.js +24 -22
- package/dist/stdlib/date.d.ts +2 -2
- package/dist/stdlib/date.js +19 -19
- package/dist/stdlib/json.d.ts +3 -3
- package/dist/stdlib/json.js +24 -24
- package/dist/stdlib/math.d.ts +3 -3
- package/dist/stdlib/math.js +7 -7
- package/dist/stdlib/number.d.ts +3 -3
- package/dist/stdlib/number.js +11 -11
- package/dist/stdlib/object.d.ts +5 -5
- package/dist/stdlib/object.js +41 -39
- package/dist/stdlib/regexp.d.ts +6 -6
- package/dist/stdlib/regexp.js +24 -24
- package/dist/stdlib/string.d.ts +2 -2
- package/dist/stdlib/string.js +24 -24
- package/dist/stdlib/url.d.ts +6 -6
- package/dist/stdlib/url.js +39 -39
- package/dist/stdlib/value.d.ts +3 -3
- package/dist/stdlib/value.js +18 -14
- package/dist/stdlib/web.d.ts +4 -4
- package/dist/stdlib/web.js +19 -5
- package/dist/tool-runtime.d.ts +2 -2
- package/dist/tool-runtime.js +2 -2
- package/package.json +1 -1
- package/dist/interpreter/runner.d.ts +0 -27
- package/dist/interpreter/runtime.d.ts +0 -19
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { checkArrayLength, checkStringLength } from "../interpreter/limits.js";
|
|
3
|
+
import { constructor, methods, prototypeFrom, receiver, requiresNew } from "../interpreter/native.js";
|
|
4
|
+
import { rangeError, syntaxError, typeError } from "../interpreter/model.js";
|
|
5
|
+
import { defineAccessor, get, Arr, Bytes, Obj } from "../interpreter/objects.js";
|
|
6
|
+
import { describeValue } from "../interpreter/references.js";
|
|
7
|
+
import { coerceToNumber, coerceToString } from "./value.js";
|
|
8
|
+
/** The bytes a Uint8Array, array, or other iterable of numbers describes; the host array clamps each value. */
|
|
9
|
+
const collectBytes = (ctx, source, name) => {
|
|
10
|
+
if (source instanceof Bytes)
|
|
11
|
+
return Effect.succeed(new Uint8Array(source.bytes));
|
|
12
|
+
return Effect.gen(function* () {
|
|
13
|
+
const cursor = yield* ctx.iterate(source);
|
|
14
|
+
if (cursor === undefined) {
|
|
15
|
+
throw typeError(`${name} expects a Uint8Array, an array, or an iterable of numbers, received ${describeValue(source)}.`);
|
|
16
|
+
}
|
|
17
|
+
const values = [];
|
|
18
|
+
while (true) {
|
|
19
|
+
const step = yield* cursor.next;
|
|
20
|
+
if (step.done)
|
|
21
|
+
return Uint8Array.from(values);
|
|
22
|
+
values.push(coerceToNumber(step.value));
|
|
23
|
+
checkArrayLength(values.length);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
const constructBytes = (ctx, args, proto) => {
|
|
28
|
+
const source = args[0];
|
|
29
|
+
if (source !== null && typeof source === "object") {
|
|
30
|
+
return Effect.map(collectBytes(ctx, source, "new Uint8Array(...)"), (bytes) => new Bytes(proto, bytes));
|
|
31
|
+
}
|
|
32
|
+
const length = source === undefined ? 0 : coerceToNumber(source);
|
|
33
|
+
if (!Number.isInteger(length) || length < 0)
|
|
34
|
+
throw rangeError(`Invalid typed array length: ${coerceToString(source)}`);
|
|
35
|
+
checkArrayLength(length);
|
|
36
|
+
return Effect.succeed(new Bytes(proto, new Uint8Array(length)));
|
|
37
|
+
};
|
|
38
|
+
export const uint8ArrayGlobal = (ctx) => {
|
|
39
|
+
const builtins = ctx.builtins;
|
|
40
|
+
const proto = builtins.Uint8Array;
|
|
41
|
+
const wrap = (bytes) => new Bytes(proto, bytes);
|
|
42
|
+
const uint8Array = constructor(builtins, proto, {
|
|
43
|
+
name: "Uint8Array",
|
|
44
|
+
length: 3,
|
|
45
|
+
call: requiresNew("Uint8Array"),
|
|
46
|
+
construct: (args, newTarget) => constructBytes(ctx, args, prototypeFrom(newTarget, proto)),
|
|
47
|
+
});
|
|
48
|
+
const decode = (name, args, from) => {
|
|
49
|
+
if (typeof args[0] !== "string")
|
|
50
|
+
throw typeError(`Uint8Array.${name} expects a string.`);
|
|
51
|
+
try {
|
|
52
|
+
return wrap(from(args[0]));
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
throw syntaxError(`Uint8Array.${name}: the string is not valid ${name === "fromHex" ? "hex" : "base64"}.`);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
methods(builtins, uint8Array, [
|
|
59
|
+
["from", 1, (_, args) => Effect.map(collectBytes(ctx, args[0], "Uint8Array.from"), wrap)],
|
|
60
|
+
["of", 0, (_, args) => wrap(Uint8Array.from(args, coerceToNumber))],
|
|
61
|
+
["fromBase64", 1, (_, args) => decode("fromBase64", args, (text) => Uint8Array.fromBase64(text))],
|
|
62
|
+
["fromHex", 1, (_, args) => decode("fromHex", args, (text) => Uint8Array.fromHex(text))],
|
|
63
|
+
]);
|
|
64
|
+
const self = (thisValue, name) => receiver(Bytes, thisValue, `Uint8Array.prototype.${name}`);
|
|
65
|
+
const optNumber = (name, value, label) => {
|
|
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
|
+
};
|
|
72
|
+
const wrapAll = (items) => new Arr(builtins.Array, items);
|
|
73
|
+
defineAccessor(proto, "length", (thisValue) => self(thisValue, "length").bytes.length);
|
|
74
|
+
methods(builtins, proto, [
|
|
75
|
+
["at", 1, (thisValue, args) => self(thisValue, "at").bytes.at(optNumber("at", args[0], "index") ?? 0)],
|
|
76
|
+
[
|
|
77
|
+
"slice",
|
|
78
|
+
2,
|
|
79
|
+
(thisValue, args) => wrap(self(thisValue, "slice").bytes.slice(optNumber("slice", args[0], "start"), optNumber("slice", args[1], "end"))),
|
|
80
|
+
],
|
|
81
|
+
// A view on the same bytes, as in JS: writes through one are visible through the other.
|
|
82
|
+
[
|
|
83
|
+
"subarray",
|
|
84
|
+
2,
|
|
85
|
+
(thisValue, args) => wrap(self(thisValue, "subarray").bytes.subarray(optNumber("subarray", args[0], "start"), optNumber("subarray", args[1], "end"))),
|
|
86
|
+
],
|
|
87
|
+
[
|
|
88
|
+
"set",
|
|
89
|
+
1,
|
|
90
|
+
(thisValue, args) => {
|
|
91
|
+
const target = self(thisValue, "set");
|
|
92
|
+
const offset = optNumber("set", args[1], "offset") ?? 0;
|
|
93
|
+
return Effect.map(collectBytes(ctx, args[0], "Uint8Array.set"), (source) => {
|
|
94
|
+
if (!Number.isInteger(offset) || offset < 0 || source.length + offset > target.bytes.length) {
|
|
95
|
+
throw rangeError("Uint8Array.set: the source does not fit at that offset.");
|
|
96
|
+
}
|
|
97
|
+
target.bytes.set(source, offset);
|
|
98
|
+
return undefined;
|
|
99
|
+
});
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
[
|
|
103
|
+
"fill",
|
|
104
|
+
1,
|
|
105
|
+
(thisValue, args) => {
|
|
106
|
+
const target = self(thisValue, "fill");
|
|
107
|
+
target.bytes.fill(coerceToNumber(args[0]), optNumber("fill", args[1], "start"), optNumber("fill", args[2], "end"));
|
|
108
|
+
return target;
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
[
|
|
112
|
+
"reverse",
|
|
113
|
+
0,
|
|
114
|
+
(thisValue) => {
|
|
115
|
+
const target = self(thisValue, "reverse");
|
|
116
|
+
target.bytes.reverse();
|
|
117
|
+
return target;
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
[
|
|
121
|
+
"indexOf",
|
|
122
|
+
1,
|
|
123
|
+
(thisValue, args) => self(thisValue, "indexOf").bytes.indexOf(coerceToNumber(args[0]), optNumber("indexOf", args[1], "start index")),
|
|
124
|
+
],
|
|
125
|
+
[
|
|
126
|
+
"lastIndexOf",
|
|
127
|
+
1,
|
|
128
|
+
(thisValue, args) => {
|
|
129
|
+
const target = self(thisValue, "lastIndexOf").bytes;
|
|
130
|
+
return args[1] === undefined
|
|
131
|
+
? target.lastIndexOf(coerceToNumber(args[0]))
|
|
132
|
+
: target.lastIndexOf(coerceToNumber(args[0]), optNumber("lastIndexOf", args[1], "start index"));
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
[
|
|
136
|
+
"includes",
|
|
137
|
+
1,
|
|
138
|
+
(thisValue, args) => self(thisValue, "includes").bytes.includes(coerceToNumber(args[0]), optNumber("includes", args[1], "start index")),
|
|
139
|
+
],
|
|
140
|
+
[
|
|
141
|
+
"join",
|
|
142
|
+
1,
|
|
143
|
+
(thisValue, args) => {
|
|
144
|
+
if (args.length > 1 || (args.length === 1 && typeof args[0] !== "string")) {
|
|
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]);
|
|
148
|
+
checkStringLength(joined.length);
|
|
149
|
+
return joined;
|
|
150
|
+
},
|
|
151
|
+
],
|
|
152
|
+
["toString", 0, (thisValue) => self(thisValue, "toString").bytes.join(",")],
|
|
153
|
+
["toBase64", 0, (thisValue) => self(thisValue, "toBase64").bytes.toBase64()],
|
|
154
|
+
["toHex", 0, (thisValue) => self(thisValue, "toHex").bytes.toHex()],
|
|
155
|
+
["keys", 0, (thisValue) => wrapAll(Array.from(self(thisValue, "keys").bytes.keys()))],
|
|
156
|
+
["values", 0, (thisValue) => wrapAll(Array.from(self(thisValue, "values").bytes.values()))],
|
|
157
|
+
[
|
|
158
|
+
"entries",
|
|
159
|
+
0,
|
|
160
|
+
(thisValue) => wrapAll(Array.from(self(thisValue, "entries").bytes.entries(), ([index, byte]) => wrapAll([index, byte]))),
|
|
161
|
+
],
|
|
162
|
+
]);
|
|
163
|
+
return uint8Array;
|
|
164
|
+
};
|
|
165
|
+
export const textEncoderGlobal = (ctx) => {
|
|
166
|
+
const builtins = ctx.builtins;
|
|
167
|
+
const proto = builtins.TextEncoder;
|
|
168
|
+
const encoder = new TextEncoder();
|
|
169
|
+
defineAccessor(proto, "encoding", () => "utf-8");
|
|
170
|
+
methods(builtins, proto, [
|
|
171
|
+
["encode", 0, (_, args) => new Bytes(builtins.Uint8Array, encoder.encode(coerceToString(args[0] ?? "")))],
|
|
172
|
+
]);
|
|
173
|
+
return constructor(builtins, proto, {
|
|
174
|
+
name: "TextEncoder",
|
|
175
|
+
call: requiresNew("TextEncoder"),
|
|
176
|
+
construct: (_, newTarget) => Effect.succeed(new Obj(prototypeFrom(newTarget, proto))),
|
|
177
|
+
});
|
|
178
|
+
};
|
|
179
|
+
/** A `TextDecoder` holding the host decoder its label and options configured. */
|
|
180
|
+
export class TextDecoderObj extends Obj {
|
|
181
|
+
decoder;
|
|
182
|
+
constructor(proto, decoder) {
|
|
183
|
+
super(proto);
|
|
184
|
+
this.decoder = decoder;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// The WHATWG labels for UTF-8, the only encoding CodeMode decodes.
|
|
188
|
+
const utf8Labels = new Set(["unicode-1-1-utf-8", "unicode11utf8", "unicode20utf8", "utf-8", "utf8", "x-unicode20utf8"]);
|
|
189
|
+
export const textDecoderGlobal = (ctx) => {
|
|
190
|
+
const builtins = ctx.builtins;
|
|
191
|
+
const proto = builtins.TextDecoder;
|
|
192
|
+
const self = (thisValue, name) => receiver(TextDecoderObj, thisValue, `TextDecoder.prototype.${name}`);
|
|
193
|
+
defineAccessor(proto, "encoding", (thisValue) => self(thisValue, "encoding").decoder.encoding);
|
|
194
|
+
defineAccessor(proto, "fatal", (thisValue) => self(thisValue, "fatal").decoder.fatal);
|
|
195
|
+
defineAccessor(proto, "ignoreBOM", (thisValue) => self(thisValue, "ignoreBOM").decoder.ignoreBOM);
|
|
196
|
+
methods(builtins, proto, [
|
|
197
|
+
[
|
|
198
|
+
"decode",
|
|
199
|
+
0,
|
|
200
|
+
(thisValue, args) => {
|
|
201
|
+
const decoder = self(thisValue, "decode").decoder;
|
|
202
|
+
if (args[0] === undefined)
|
|
203
|
+
return "";
|
|
204
|
+
if (!(args[0] instanceof Bytes)) {
|
|
205
|
+
throw typeError(`TextDecoder.decode expects a Uint8Array, received ${describeValue(args[0])}.`);
|
|
206
|
+
}
|
|
207
|
+
try {
|
|
208
|
+
return decoder.decode(args[0].bytes);
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
throw typeError(`TextDecoder.decode: the input is not valid ${decoder.encoding}.`);
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
],
|
|
215
|
+
]);
|
|
216
|
+
return constructor(builtins, proto, {
|
|
217
|
+
name: "TextDecoder",
|
|
218
|
+
call: requiresNew("TextDecoder"),
|
|
219
|
+
construct: (args, newTarget) => Effect.sync(() => {
|
|
220
|
+
const label = args[0] === undefined ? "utf-8" : coerceToString(args[0]).trim().toLowerCase();
|
|
221
|
+
if (!utf8Labels.has(label))
|
|
222
|
+
throw rangeError(`The "${label}" encoding is not supported; only UTF-8 is.`);
|
|
223
|
+
const options = args[1] instanceof Obj ? args[1] : undefined;
|
|
224
|
+
const flag = (name) => options !== undefined && Boolean(get(options, name));
|
|
225
|
+
return new TextDecoderObj(prototypeFrom(newTarget, proto), new TextDecoder("utf-8", { fatal: flag("fatal"), ignoreBOM: flag("ignoreBOM") }));
|
|
226
|
+
}),
|
|
227
|
+
});
|
|
228
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Interpreter } from "../interpreter/interpreter.js";
|
|
2
2
|
/** `Map.groupBy` and `Object.groupBy`: the same iteration, keyed into a Map or a data object. */
|
|
3
|
-
export declare const groupBy: <R>(
|
|
4
|
-
export declare const mapGlobal: <R>(
|
|
5
|
-
export declare const setGlobal: <R>(
|
|
3
|
+
export declare const groupBy: <R>(ctx: Interpreter<R>, namespace: "Map" | "Object") => import("../interpreter/objects.js").Native<R>;
|
|
4
|
+
export declare const mapGlobal: <R>(ctx: Interpreter<R>) => import("../interpreter/objects.js").Native<R>;
|
|
5
|
+
export declare const setGlobal: <R>(ctx: Interpreter<R>) => import("../interpreter/objects.js").Native<R>;
|
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { constructor, fn, methods, prototypeFrom, receiver, requiresNew } from "../interpreter/native.js";
|
|
3
3
|
import { invalidData, typeError } from "../interpreter/model.js";
|
|
4
|
-
import { define, defineAccessor, get, getOwn, hidden, isWrapper,
|
|
4
|
+
import { define, defineAccessor, get, getOwn, hidden, isWrapper, Arr, MapObj, Obj, PromiseObj, SetObj, } from "../interpreter/objects.js";
|
|
5
5
|
import { describeValue, isRuntimeReference } from "../interpreter/references.js";
|
|
6
|
-
import { applyCollectionCallback, isSupportedCallback, preserveConsumerError, toPrimitiveNumber, toPrimitiveString, } from "../interpreter/
|
|
7
|
-
const coerceGroupByPropertyKey = (
|
|
8
|
-
if (value instanceof
|
|
6
|
+
import { applyCollectionCallback, isSupportedCallback, preserveConsumerError, toPrimitiveNumber, toPrimitiveString, } from "../interpreter/callback.js";
|
|
7
|
+
const coerceGroupByPropertyKey = (ctx, value) => {
|
|
8
|
+
if (value instanceof PromiseObj)
|
|
9
9
|
return Effect.succeed("[object Promise]");
|
|
10
10
|
if (!isWrapper(value) && isRuntimeReference(value)) {
|
|
11
11
|
throw invalidData(`Object.groupBy callback must return a data value, received ${describeValue(value)}.`);
|
|
12
12
|
}
|
|
13
|
-
return toPrimitiveString(
|
|
13
|
+
return toPrimitiveString(ctx, value);
|
|
14
14
|
};
|
|
15
15
|
/** `Map.groupBy` and `Object.groupBy`: the same iteration, keyed into a Map or a data object. */
|
|
16
|
-
export const groupBy = (
|
|
17
|
-
const
|
|
16
|
+
export const groupBy = (ctx, namespace) => fn(ctx.builtins, "groupBy", 2, (_, args) => {
|
|
17
|
+
const builtins = ctx.builtins;
|
|
18
18
|
const source = args[0];
|
|
19
19
|
if (source === null || source === undefined) {
|
|
20
20
|
throw typeError(`${namespace}.groupBy expects an iterable collection.`);
|
|
21
21
|
}
|
|
22
|
-
const apply = applyCollectionCallback(
|
|
22
|
+
const apply = applyCollectionCallback(ctx, args[1], `${namespace}.groupBy`);
|
|
23
23
|
return Effect.gen(function* () {
|
|
24
|
-
const cursor = yield*
|
|
24
|
+
const cursor = yield* ctx.iterate(source);
|
|
25
25
|
if (cursor === undefined) {
|
|
26
26
|
throw typeError(`${namespace}.groupBy expects an iterable collection.`);
|
|
27
27
|
}
|
|
28
28
|
if (namespace === "Map") {
|
|
29
|
-
const result = new
|
|
29
|
+
const result = new MapObj(builtins.Map);
|
|
30
30
|
let index = 0;
|
|
31
31
|
while (true) {
|
|
32
32
|
const step = yield* cursor.next;
|
|
@@ -36,36 +36,36 @@ export const groupBy = (runner, namespace) => fn(runner.prototypes, "groupBy", 2
|
|
|
36
36
|
const key = yield* preserveConsumerError(cursor, apply([item, index]));
|
|
37
37
|
const group = result.map.get(key);
|
|
38
38
|
if (group === undefined)
|
|
39
|
-
result.map.set(key, new
|
|
39
|
+
result.map.set(key, new Arr(builtins.Array, [item]));
|
|
40
40
|
else
|
|
41
41
|
group.items.push(item);
|
|
42
42
|
index += 1;
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
// Object.groupBy returns a null-prototype object, so group names never collide with inherited methods.
|
|
46
|
-
const result = new
|
|
46
|
+
const result = new Obj(null);
|
|
47
47
|
let index = 0;
|
|
48
48
|
while (true) {
|
|
49
49
|
const step = yield* cursor.next;
|
|
50
50
|
if (step.done)
|
|
51
51
|
return result;
|
|
52
52
|
const item = step.value;
|
|
53
|
-
const key = yield* preserveConsumerError(cursor, Effect.flatMap(apply([item, index]), (value) => coerceGroupByPropertyKey(
|
|
53
|
+
const key = yield* preserveConsumerError(cursor, Effect.flatMap(apply([item, index]), (value) => coerceGroupByPropertyKey(ctx, value)));
|
|
54
54
|
const group = getOwn(result, key);
|
|
55
55
|
if (group === undefined)
|
|
56
|
-
define(result, key, new
|
|
56
|
+
define(result, key, new Arr(builtins.Array, [item]));
|
|
57
57
|
else
|
|
58
58
|
group.items.push(item);
|
|
59
59
|
index += 1;
|
|
60
60
|
}
|
|
61
61
|
});
|
|
62
62
|
});
|
|
63
|
-
const constructMap = (
|
|
64
|
-
const target = new
|
|
63
|
+
const constructMap = (ctx, init, proto) => {
|
|
64
|
+
const target = new MapObj(proto);
|
|
65
65
|
if (init === undefined || init === null)
|
|
66
66
|
return Effect.succeed(target);
|
|
67
67
|
return Effect.gen(function* () {
|
|
68
|
-
const cursor = yield*
|
|
68
|
+
const cursor = yield* ctx.iterate(init);
|
|
69
69
|
if (cursor === undefined) {
|
|
70
70
|
throw typeError("new Map(...) expects an iterable of [key, value] pairs or no argument.");
|
|
71
71
|
}
|
|
@@ -74,7 +74,7 @@ const constructMap = (runner, init, proto) => {
|
|
|
74
74
|
if (step.done)
|
|
75
75
|
return target;
|
|
76
76
|
yield* preserveConsumerError(cursor, Effect.sync(() => {
|
|
77
|
-
if (!(step.value instanceof
|
|
77
|
+
if (!(step.value instanceof Obj)) {
|
|
78
78
|
throw typeError("new Map(...) expects [key, value] pairs as entry objects.");
|
|
79
79
|
}
|
|
80
80
|
target.map.set(getOwn(step.value, 0), getOwn(step.value, 1));
|
|
@@ -82,12 +82,12 @@ const constructMap = (runner, init, proto) => {
|
|
|
82
82
|
}
|
|
83
83
|
});
|
|
84
84
|
};
|
|
85
|
-
const constructSet = (
|
|
86
|
-
const target = new
|
|
85
|
+
const constructSet = (ctx, init, proto) => {
|
|
86
|
+
const target = new SetObj(proto);
|
|
87
87
|
if (init === undefined || init === null)
|
|
88
88
|
return Effect.succeed(target);
|
|
89
89
|
return Effect.gen(function* () {
|
|
90
|
-
const cursor = yield*
|
|
90
|
+
const cursor = yield* ctx.iterate(init);
|
|
91
91
|
if (cursor === undefined) {
|
|
92
92
|
throw typeError("new Set(...) expects a synchronous iterable or no argument.");
|
|
93
93
|
}
|
|
@@ -99,19 +99,19 @@ const constructSet = (runner, init, proto) => {
|
|
|
99
99
|
}
|
|
100
100
|
});
|
|
101
101
|
};
|
|
102
|
-
export const mapGlobal = (
|
|
103
|
-
const
|
|
104
|
-
const proto =
|
|
105
|
-
const map = constructor(
|
|
102
|
+
export const mapGlobal = (ctx) => {
|
|
103
|
+
const builtins = ctx.builtins;
|
|
104
|
+
const proto = builtins.Map;
|
|
105
|
+
const map = constructor(builtins, proto, {
|
|
106
106
|
name: "Map",
|
|
107
107
|
call: requiresNew("Map"),
|
|
108
|
-
construct: (args, newTarget) => constructMap(
|
|
108
|
+
construct: (args, newTarget) => constructMap(ctx, args[0], prototypeFrom(newTarget, proto)),
|
|
109
109
|
});
|
|
110
|
-
define(map, "groupBy", groupBy(
|
|
111
|
-
const self = (thisValue, name) => receiver(
|
|
112
|
-
const wrap = (items) => new
|
|
113
|
-
defineAccessor(proto, "size", (thisValue) => receiver(
|
|
114
|
-
methods(
|
|
110
|
+
define(map, "groupBy", groupBy(ctx, "Map"), hidden);
|
|
111
|
+
const self = (thisValue, name) => receiver(MapObj, thisValue, `Map.prototype.${name}`);
|
|
112
|
+
const wrap = (items) => new Arr(builtins.Array, items);
|
|
113
|
+
defineAccessor(proto, "size", (thisValue) => receiver(MapObj, thisValue, "Map.prototype.size").map.size);
|
|
114
|
+
methods(builtins, proto, [
|
|
115
115
|
["get", 1, (thisValue, args) => self(thisValue, "get").map.get(args[0])],
|
|
116
116
|
["has", 1, (thisValue, args) => self(thisValue, "has").map.has(args[0])],
|
|
117
117
|
[
|
|
@@ -144,7 +144,7 @@ export const mapGlobal = (runner) => {
|
|
|
144
144
|
1,
|
|
145
145
|
(thisValue, args) => {
|
|
146
146
|
const target = self(thisValue, "forEach");
|
|
147
|
-
const apply = applyCollectionCallback(
|
|
147
|
+
const apply = applyCollectionCallback(ctx, args[0], "Map.forEach");
|
|
148
148
|
return Effect.gen(function* () {
|
|
149
149
|
for (const [key, item] of Array.from(target.map.entries()))
|
|
150
150
|
yield* apply([item, key, target]);
|
|
@@ -155,26 +155,26 @@ export const mapGlobal = (runner) => {
|
|
|
155
155
|
]);
|
|
156
156
|
return map;
|
|
157
157
|
};
|
|
158
|
-
const loadSetRecord = (
|
|
159
|
-
if (source instanceof
|
|
158
|
+
const loadSetRecord = (ctx, source, name) => {
|
|
159
|
+
if (source instanceof SetObj) {
|
|
160
160
|
return Effect.succeed({
|
|
161
161
|
size: source.set.size,
|
|
162
162
|
has: (item) => Effect.succeed(source.set.has(item)),
|
|
163
163
|
keys: () => Effect.succeed(source.set.values()),
|
|
164
164
|
});
|
|
165
165
|
}
|
|
166
|
-
if (source instanceof
|
|
166
|
+
if (source instanceof MapObj) {
|
|
167
167
|
return Effect.succeed({
|
|
168
168
|
size: source.map.size,
|
|
169
169
|
has: (item) => Effect.succeed(source.map.has(item)),
|
|
170
170
|
keys: () => Effect.succeed(source.map.keys()),
|
|
171
171
|
});
|
|
172
172
|
}
|
|
173
|
-
if (!(source instanceof
|
|
173
|
+
if (!(source instanceof Obj)) {
|
|
174
174
|
throw typeError(`Set.${name} expects a Set-like object.`);
|
|
175
175
|
}
|
|
176
176
|
return Effect.gen(function* () {
|
|
177
|
-
const size = yield* toPrimitiveNumber(
|
|
177
|
+
const size = yield* toPrimitiveNumber(ctx, get(source, "size"));
|
|
178
178
|
if (Number.isNaN(size)) {
|
|
179
179
|
throw typeError(`Set.${name} received a Set-like object with an invalid size.`);
|
|
180
180
|
}
|
|
@@ -185,19 +185,19 @@ const loadSetRecord = (runner, source, name) => {
|
|
|
185
185
|
}
|
|
186
186
|
return {
|
|
187
187
|
size: Math.max(Math.trunc(size), 0),
|
|
188
|
-
has: (item) => Effect.map(
|
|
189
|
-
keys: () => Effect.flatMap(
|
|
190
|
-
if (result instanceof
|
|
188
|
+
has: (item) => Effect.map(ctx.call(has, source, [item]), Boolean),
|
|
189
|
+
keys: () => Effect.flatMap(ctx.call(keys, source, []), (result) => {
|
|
190
|
+
if (result instanceof Arr)
|
|
191
191
|
return Effect.succeed(result.items);
|
|
192
192
|
throw typeError(`Set.${name} expected 'keys' to return an iterator.`);
|
|
193
193
|
}),
|
|
194
194
|
};
|
|
195
195
|
});
|
|
196
196
|
};
|
|
197
|
-
const setOperation = (
|
|
198
|
-
const other = yield* loadSetRecord(
|
|
197
|
+
const setOperation = (ctx, target, name, source) => Effect.gen(function* () {
|
|
198
|
+
const other = yield* loadSetRecord(ctx, source, name);
|
|
199
199
|
const copy = () => {
|
|
200
|
-
const result = new
|
|
200
|
+
const result = new SetObj(ctx.builtins.Set);
|
|
201
201
|
for (const item of target.set.values())
|
|
202
202
|
result.set.add(item);
|
|
203
203
|
return result;
|
|
@@ -209,7 +209,7 @@ const setOperation = (runner, target, name, source) => Effect.gen(function* () {
|
|
|
209
209
|
return result;
|
|
210
210
|
}
|
|
211
211
|
if (name === "intersection") {
|
|
212
|
-
const result = new
|
|
212
|
+
const result = new SetObj(ctx.builtins.Set);
|
|
213
213
|
if (target.set.size <= other.size) {
|
|
214
214
|
for (const item of target.set.values()) {
|
|
215
215
|
if (yield* other.has(item))
|
|
@@ -277,23 +277,23 @@ const setOperation = (runner, target, name, source) => Effect.gen(function* () {
|
|
|
277
277
|
}
|
|
278
278
|
return true;
|
|
279
279
|
});
|
|
280
|
-
export const setGlobal = (
|
|
281
|
-
const
|
|
282
|
-
const proto =
|
|
283
|
-
const set = constructor(
|
|
280
|
+
export const setGlobal = (ctx) => {
|
|
281
|
+
const builtins = ctx.builtins;
|
|
282
|
+
const proto = builtins.Set;
|
|
283
|
+
const set = constructor(builtins, proto, {
|
|
284
284
|
name: "Set",
|
|
285
285
|
call: requiresNew("Set"),
|
|
286
|
-
construct: (args, newTarget) => constructSet(
|
|
286
|
+
construct: (args, newTarget) => constructSet(ctx, args[0], prototypeFrom(newTarget, proto)),
|
|
287
287
|
});
|
|
288
|
-
const self = (thisValue, name) => receiver(
|
|
289
|
-
const wrap = (items) => new
|
|
288
|
+
const self = (thisValue, name) => receiver(SetObj, thisValue, `Set.prototype.${name}`);
|
|
289
|
+
const wrap = (items) => new Arr(builtins.Array, items);
|
|
290
290
|
const operation = (name) => [
|
|
291
291
|
name,
|
|
292
292
|
1,
|
|
293
|
-
(thisValue, args) => setOperation(
|
|
293
|
+
(thisValue, args) => setOperation(ctx, self(thisValue, name), name, args[0]),
|
|
294
294
|
];
|
|
295
|
-
defineAccessor(proto, "size", (thisValue) => receiver(
|
|
296
|
-
methods(
|
|
295
|
+
defineAccessor(proto, "size", (thisValue) => receiver(SetObj, thisValue, "Set.prototype.size").set.size);
|
|
296
|
+
methods(builtins, proto, [
|
|
297
297
|
["has", 1, (thisValue, args) => self(thisValue, "has").set.has(args[0])],
|
|
298
298
|
[
|
|
299
299
|
"add",
|
|
@@ -325,7 +325,7 @@ export const setGlobal = (runner) => {
|
|
|
325
325
|
1,
|
|
326
326
|
(thisValue, args) => {
|
|
327
327
|
const target = self(thisValue, "forEach");
|
|
328
|
-
const apply = applyCollectionCallback(
|
|
328
|
+
const apply = applyCollectionCallback(ctx, args[0], "Set.forEach");
|
|
329
329
|
return Effect.gen(function* () {
|
|
330
330
|
for (const item of Array.from(target.set.values()))
|
|
331
331
|
yield* apply([item, item, target]);
|
package/dist/stdlib/console.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type {
|
|
1
|
+
import { Obj } from "../interpreter/objects.js";
|
|
2
|
+
import type { Interpreter } from "../interpreter/interpreter.js";
|
|
3
3
|
/** Captured console: every method appends one formatted line to `logs`. */
|
|
4
|
-
export declare const consoleGlobal: <R>(
|
|
4
|
+
export declare const consoleGlobal: <R>(ctx: Interpreter<R>) => Obj;
|
package/dist/stdlib/console.js
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
import { toData, toProgram } from "../data.js";
|
|
2
2
|
import { methods } from "../interpreter/native.js";
|
|
3
|
-
import { entries, get,
|
|
3
|
+
import { entries, get, Arr, Bytes, DateObj, MapObj, Obj, PromiseObj, RegExpObj, SetObj, URLObj, URLSearchParamsObj, } from "../interpreter/objects.js";
|
|
4
4
|
import { containsOpaqueReference, containsRuntimeReference, isRuntimeReference } from "../interpreter/references.js";
|
|
5
5
|
import { coerceToString } from "./value.js";
|
|
6
6
|
const consoleMethods = ["log", "info", "debug", "warn", "error", "dir", "table"];
|
|
7
7
|
/** Captured console: every method appends one formatted line to `logs`. */
|
|
8
|
-
export const consoleGlobal = (
|
|
9
|
-
const
|
|
10
|
-
const console = new
|
|
11
|
-
methods(
|
|
8
|
+
export const consoleGlobal = (ctx) => {
|
|
9
|
+
const builtins = ctx.builtins;
|
|
10
|
+
const console = new Obj(builtins.Object);
|
|
11
|
+
methods(builtins, console, consoleMethods.map((name) => [
|
|
12
12
|
name,
|
|
13
13
|
0,
|
|
14
14
|
(_, args) => {
|
|
15
|
-
logs.push(formatConsoleMessage(
|
|
15
|
+
ctx.logs.push(formatConsoleMessage(builtins, name, args));
|
|
16
16
|
return undefined;
|
|
17
17
|
},
|
|
18
18
|
]));
|
|
19
19
|
return console;
|
|
20
20
|
};
|
|
21
21
|
const MAX_CONSOLE_DEPTH = 32;
|
|
22
|
-
const formatConsoleMessage = (
|
|
22
|
+
const formatConsoleMessage = (builtins, name, args) => {
|
|
23
23
|
if (name === "dir")
|
|
24
24
|
return args.length === 0 ? "undefined" : formatConsoleArgument(args[0]);
|
|
25
25
|
if (name === "table")
|
|
26
|
-
return formatConsoleTable(
|
|
26
|
+
return formatConsoleTable(builtins, args[0], args[1]);
|
|
27
27
|
const prefix = name === "warn" ? "[warn] " : name === "error" ? "[error] " : name === "debug" ? "[debug] " : "";
|
|
28
28
|
return `${prefix}${args.map((arg) => formatConsoleArgument(arg)).join(" ")}`;
|
|
29
29
|
};
|
|
@@ -43,21 +43,23 @@ const formatConsoleValue = (value, seen, depth) => {
|
|
|
43
43
|
return String(value);
|
|
44
44
|
if (typeof value !== "object")
|
|
45
45
|
return String(value);
|
|
46
|
-
if (value instanceof
|
|
46
|
+
if (value instanceof PromiseObj)
|
|
47
47
|
return "[Promise (await it to get its value)]";
|
|
48
|
-
if (value instanceof
|
|
48
|
+
if (value instanceof DateObj)
|
|
49
49
|
return coerceToString(value);
|
|
50
|
-
if (value instanceof
|
|
50
|
+
if (value instanceof RegExpObj)
|
|
51
51
|
return coerceToString(value);
|
|
52
|
-
if (value instanceof
|
|
52
|
+
if (value instanceof URLObj)
|
|
53
53
|
return coerceToString(value);
|
|
54
|
-
if (value instanceof
|
|
54
|
+
if (value instanceof URLSearchParamsObj)
|
|
55
55
|
return coerceToString(value);
|
|
56
|
+
if (value instanceof Bytes)
|
|
57
|
+
return `Uint8Array(${value.bytes.length}) [${value.bytes.join(",")}]`;
|
|
56
58
|
if (depth > MAX_CONSOLE_DEPTH)
|
|
57
59
|
return "...";
|
|
58
60
|
if (seen.has(value))
|
|
59
61
|
return "[Circular]";
|
|
60
|
-
if (value instanceof
|
|
62
|
+
if (value instanceof MapObj) {
|
|
61
63
|
seen.add(value);
|
|
62
64
|
try {
|
|
63
65
|
const items = Array.from(value.map.entries(), ([key, item]) => `[${formatItems([key, item], seen, depth + 1)}]`);
|
|
@@ -67,7 +69,7 @@ const formatConsoleValue = (value, seen, depth) => {
|
|
|
67
69
|
seen.delete(value);
|
|
68
70
|
}
|
|
69
71
|
}
|
|
70
|
-
if (value instanceof
|
|
72
|
+
if (value instanceof SetObj) {
|
|
71
73
|
seen.add(value);
|
|
72
74
|
try {
|
|
73
75
|
return `Set(${value.set.size}) [${formatItems([...value.set.values()], seen, depth + 1)}]`;
|
|
@@ -80,9 +82,9 @@ const formatConsoleValue = (value, seen, depth) => {
|
|
|
80
82
|
return "[opaque reference]";
|
|
81
83
|
seen.add(value);
|
|
82
84
|
try {
|
|
83
|
-
if (value instanceof
|
|
85
|
+
if (value instanceof Arr)
|
|
84
86
|
return `[${formatItems(value.items, seen, depth + 1)}]`;
|
|
85
|
-
if (!(value instanceof
|
|
87
|
+
if (!(value instanceof Obj))
|
|
86
88
|
return "[object Object]";
|
|
87
89
|
return `{${entries(value)
|
|
88
90
|
.map(([key, item]) => `${JSON.stringify(key)}:${formatConsoleValue(item, seen, depth + 1)}`)
|
|
@@ -93,12 +95,12 @@ const formatConsoleValue = (value, seen, depth) => {
|
|
|
93
95
|
}
|
|
94
96
|
};
|
|
95
97
|
const formatItems = (items, seen, depth) => items.map((item) => formatConsoleValue(item, seen, depth)).join(",");
|
|
96
|
-
const formatConsoleTable = (
|
|
98
|
+
const formatConsoleTable = (builtins, value, columnsArgument) => {
|
|
97
99
|
if (value === undefined)
|
|
98
100
|
return "undefined";
|
|
99
101
|
if (containsOpaqueReference(value))
|
|
100
102
|
return "[opaque reference]";
|
|
101
|
-
const data = toProgram(
|
|
103
|
+
const data = toProgram(builtins, value, "console.table argument");
|
|
102
104
|
const columns = consoleTableColumns(columnsArgument);
|
|
103
105
|
const rows = consoleTableRows(data, columns);
|
|
104
106
|
const keys = columns ?? Array.from(new Set(rows.flatMap((row) => Object.keys(row.values))));
|
|
@@ -117,16 +119,16 @@ const consoleTableColumns = (value) => {
|
|
|
117
119
|
return Array.isArray(columns) ? columns.map((column) => String(column)) : undefined;
|
|
118
120
|
};
|
|
119
121
|
const consoleTableRows = (data, columns) => {
|
|
120
|
-
if (data instanceof
|
|
122
|
+
if (data instanceof Arr) {
|
|
121
123
|
return data.items.map((item, index) => ({ index: String(index), values: consoleTableValues(item, columns) }));
|
|
122
124
|
}
|
|
123
|
-
if (data instanceof
|
|
125
|
+
if (data instanceof Obj) {
|
|
124
126
|
return entries(data).map(([index, item]) => ({ index, values: consoleTableValues(item, columns) }));
|
|
125
127
|
}
|
|
126
128
|
return [{ index: "0", values: { Value: data } }];
|
|
127
129
|
};
|
|
128
130
|
const consoleTableValues = (value, columns) => {
|
|
129
|
-
if (value instanceof
|
|
131
|
+
if (value instanceof Obj && !(value instanceof Arr)) {
|
|
130
132
|
if (columns !== undefined)
|
|
131
133
|
return Object.fromEntries(columns.map((column) => [column, get(value, column)]));
|
|
132
134
|
return Object.fromEntries(entries(value));
|
package/dist/stdlib/date.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare const dateGlobal: <R>(
|
|
1
|
+
import type { Interpreter } from "../interpreter/interpreter.js";
|
|
2
|
+
export declare const dateGlobal: <R>(ctx: Interpreter<R>) => import("../interpreter/objects.js").Native<R>;
|