@opencode/codemode 2.0.2 → 2.0.4
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.d.ts +3 -0
- package/dist/codemode.js +12 -1
- package/dist/data.d.ts +14 -21
- package/dist/data.js +72 -140
- package/dist/extension.d.ts +11 -0
- package/dist/extension.js +9 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/interpreter/callback.d.ts +20 -0
- package/dist/interpreter/{runner.js → callback.js} +14 -14
- package/dist/interpreter/errors.d.ts +12 -5
- package/dist/interpreter/errors.js +66 -54
- package/dist/interpreter/execute.d.ts +2 -2
- package/dist/interpreter/execute.js +15 -15
- package/dist/interpreter/extensions.d.ts +8 -0
- package/dist/interpreter/extensions.js +155 -0
- package/dist/interpreter/generators.d.ts +2 -3
- package/dist/interpreter/generators.js +10 -10
- package/dist/interpreter/globals.d.ts +4 -12
- package/dist/interpreter/globals.js +56 -49
- package/dist/interpreter/interpreter.d.ts +34 -0
- package/dist/interpreter/{runtime.js → interpreter.js} +250 -215
- package/dist/interpreter/intrinsics.d.ts +5 -5
- package/dist/interpreter/intrinsics.js +16 -10
- package/dist/interpreter/limits.d.ts +10 -0
- package/dist/interpreter/limits.js +19 -0
- package/dist/interpreter/model.d.ts +27 -14
- package/dist/interpreter/model.js +22 -14
- package/dist/interpreter/native.d.ts +12 -13
- package/dist/interpreter/native.js +17 -16
- package/dist/interpreter/objects.d.ts +55 -48
- package/dist/interpreter/objects.js +64 -44
- package/dist/interpreter/promises.d.ts +13 -15
- package/dist/interpreter/promises.js +89 -85
- package/dist/interpreter/references.d.ts +1 -2
- package/dist/interpreter/references.js +18 -16
- package/dist/interpreter/scope.js +6 -6
- package/dist/openapi/types.d.ts +1 -1
- package/dist/stdlib/array.d.ts +3 -4
- package/dist/stdlib/array.js +115 -110
- 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 +89 -89
- package/dist/stdlib/console.d.ts +5 -3
- package/dist/stdlib/console.js +30 -37
- package/dist/stdlib/date.d.ts +2 -2
- package/dist/stdlib/date.js +35 -35
- package/dist/stdlib/json.d.ts +3 -3
- package/dist/stdlib/json.js +29 -67
- package/dist/stdlib/math.d.ts +3 -3
- package/dist/stdlib/math.js +17 -21
- package/dist/stdlib/number.d.ts +3 -3
- package/dist/stdlib/number.js +32 -36
- package/dist/stdlib/object.d.ts +5 -5
- package/dist/stdlib/object.js +59 -62
- package/dist/stdlib/regexp.d.ts +7 -8
- package/dist/stdlib/regexp.js +40 -48
- package/dist/stdlib/string.d.ts +2 -2
- package/dist/stdlib/string.js +110 -88
- package/dist/stdlib/url.d.ts +4 -6
- package/dist/stdlib/url.js +86 -90
- package/dist/stdlib/value.d.ts +3 -3
- package/dist/stdlib/value.js +26 -24
- package/dist/stdlib/web.d.ts +4 -4
- package/dist/stdlib/web.js +22 -8
- package/dist/tool-runtime.d.ts +12 -5
- package/dist/tool-runtime.js +25 -11
- package/package.json +1 -1
- package/dist/interpreter/runner.d.ts +0 -28
- 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
|
-
import {
|
|
4
|
-
import { define, defineAccessor, get, getOwn, hidden, isWrapper,
|
|
3
|
+
import { invalidData, typeError } from "../interpreter/model.js";
|
|
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
|
-
throw
|
|
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
|
-
throw
|
|
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
|
-
throw
|
|
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,60 +36,60 @@ 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
|
-
throw
|
|
70
|
+
throw typeError("new Map(...) expects an iterable of [key, value] pairs or no argument.");
|
|
71
71
|
}
|
|
72
72
|
while (true) {
|
|
73
73
|
const step = yield* cursor.next;
|
|
74
74
|
if (step.done)
|
|
75
75
|
return target;
|
|
76
76
|
yield* preserveConsumerError(cursor, Effect.sync(() => {
|
|
77
|
-
if (!(step.value instanceof
|
|
78
|
-
throw
|
|
77
|
+
if (!(step.value instanceof Obj)) {
|
|
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));
|
|
81
81
|
}));
|
|
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
|
-
throw
|
|
92
|
+
throw typeError("new Set(...) expects a synchronous iterable or no argument.");
|
|
93
93
|
}
|
|
94
94
|
while (true) {
|
|
95
95
|
const step = yield* cursor.next;
|
|
@@ -99,52 +99,52 @@ const constructSet = (runner, init, proto, node) => {
|
|
|
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
|
|
108
|
+
construct: (args, newTarget) => constructMap(ctx, args[0], prototypeFrom(newTarget, proto)),
|
|
109
109
|
});
|
|
110
|
-
define(map, "groupBy", groupBy(
|
|
111
|
-
const self = (thisValue, name
|
|
112
|
-
const wrap = (items) => new
|
|
113
|
-
defineAccessor(proto, "size", (thisValue) => receiver(
|
|
114
|
-
methods(
|
|
115
|
-
["get", 1, (thisValue, args
|
|
116
|
-
["has", 1, (thisValue, args
|
|
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
|
+
["get", 1, (thisValue, args) => self(thisValue, "get").map.get(args[0])],
|
|
116
|
+
["has", 1, (thisValue, args) => self(thisValue, "has").map.has(args[0])],
|
|
117
117
|
[
|
|
118
118
|
"set",
|
|
119
119
|
2,
|
|
120
|
-
(thisValue, args
|
|
121
|
-
const target = self(thisValue, "set"
|
|
120
|
+
(thisValue, args) => {
|
|
121
|
+
const target = self(thisValue, "set");
|
|
122
122
|
target.map.set(args[0], args[1]);
|
|
123
123
|
return target;
|
|
124
124
|
},
|
|
125
125
|
],
|
|
126
|
-
["delete", 1, (thisValue, args
|
|
126
|
+
["delete", 1, (thisValue, args) => self(thisValue, "delete").map.delete(args[0])],
|
|
127
127
|
[
|
|
128
128
|
"clear",
|
|
129
129
|
0,
|
|
130
|
-
(thisValue
|
|
131
|
-
self(thisValue, "clear"
|
|
130
|
+
(thisValue) => {
|
|
131
|
+
self(thisValue, "clear").map.clear();
|
|
132
132
|
return undefined;
|
|
133
133
|
},
|
|
134
134
|
],
|
|
135
|
-
["keys", 0, (thisValue
|
|
136
|
-
["values", 0, (thisValue
|
|
135
|
+
["keys", 0, (thisValue) => wrap(Array.from(self(thisValue, "keys").map.keys()))],
|
|
136
|
+
["values", 0, (thisValue) => wrap(Array.from(self(thisValue, "values").map.values()))],
|
|
137
137
|
[
|
|
138
138
|
"entries",
|
|
139
139
|
0,
|
|
140
|
-
(thisValue
|
|
140
|
+
(thisValue) => wrap(Array.from(self(thisValue, "entries").map.entries(), ([key, item]) => wrap([key, item]))),
|
|
141
141
|
],
|
|
142
142
|
[
|
|
143
143
|
"forEach",
|
|
144
144
|
1,
|
|
145
|
-
(thisValue, args
|
|
146
|
-
const target = self(thisValue, "forEach"
|
|
147
|
-
const apply = applyCollectionCallback(
|
|
145
|
+
(thisValue, args) => {
|
|
146
|
+
const target = self(thisValue, "forEach");
|
|
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,49 +155,49 @@ 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
|
|
174
|
-
throw
|
|
173
|
+
if (!(source instanceof Obj)) {
|
|
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
|
-
throw
|
|
179
|
+
throw typeError(`Set.${name} received a Set-like object with an invalid size.`);
|
|
180
180
|
}
|
|
181
181
|
const has = get(source, "has");
|
|
182
182
|
const keys = get(source, "keys");
|
|
183
183
|
if (!isSupportedCallback(has) || !isSupportedCallback(keys)) {
|
|
184
|
-
throw
|
|
184
|
+
throw typeError(`Set.${name} expects callable 'has' and 'keys' methods.`);
|
|
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
|
-
throw
|
|
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, node) => 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,55 +277,55 @@ const setOperation = (runner, target, name, source, node) => 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
|
|
286
|
+
construct: (args, newTarget) => constructSet(ctx, args[0], prototypeFrom(newTarget, proto)),
|
|
287
287
|
});
|
|
288
|
-
const self = (thisValue, name
|
|
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
|
|
293
|
+
(thisValue, args) => setOperation(ctx, self(thisValue, name), name, args[0]),
|
|
294
294
|
];
|
|
295
|
-
defineAccessor(proto, "size", (thisValue) => receiver(
|
|
296
|
-
methods(
|
|
297
|
-
["has", 1, (thisValue, args
|
|
295
|
+
defineAccessor(proto, "size", (thisValue) => receiver(SetObj, thisValue, "Set.prototype.size").set.size);
|
|
296
|
+
methods(builtins, proto, [
|
|
297
|
+
["has", 1, (thisValue, args) => self(thisValue, "has").set.has(args[0])],
|
|
298
298
|
[
|
|
299
299
|
"add",
|
|
300
300
|
1,
|
|
301
|
-
(thisValue, args
|
|
302
|
-
const target = self(thisValue, "add"
|
|
301
|
+
(thisValue, args) => {
|
|
302
|
+
const target = self(thisValue, "add");
|
|
303
303
|
target.set.add(args[0]);
|
|
304
304
|
return target;
|
|
305
305
|
},
|
|
306
306
|
],
|
|
307
|
-
["delete", 1, (thisValue, args
|
|
307
|
+
["delete", 1, (thisValue, args) => self(thisValue, "delete").set.delete(args[0])],
|
|
308
308
|
[
|
|
309
309
|
"clear",
|
|
310
310
|
0,
|
|
311
|
-
(thisValue
|
|
312
|
-
self(thisValue, "clear"
|
|
311
|
+
(thisValue) => {
|
|
312
|
+
self(thisValue, "clear").set.clear();
|
|
313
313
|
return undefined;
|
|
314
314
|
},
|
|
315
315
|
],
|
|
316
|
-
["keys", 0, (thisValue
|
|
317
|
-
["values", 0, (thisValue
|
|
316
|
+
["keys", 0, (thisValue) => wrap(Array.from(self(thisValue, "keys").set.values()))],
|
|
317
|
+
["values", 0, (thisValue) => wrap(Array.from(self(thisValue, "values").set.values()))],
|
|
318
318
|
[
|
|
319
319
|
"entries",
|
|
320
320
|
0,
|
|
321
|
-
(thisValue
|
|
321
|
+
(thisValue) => wrap(Array.from(self(thisValue, "entries").set.values(), (item) => wrap([item, item]))),
|
|
322
322
|
],
|
|
323
323
|
[
|
|
324
324
|
"forEach",
|
|
325
325
|
1,
|
|
326
|
-
(thisValue, args
|
|
327
|
-
const target = self(thisValue, "forEach"
|
|
328
|
-
const apply = applyCollectionCallback(
|
|
326
|
+
(thisValue, args) => {
|
|
327
|
+
const target = self(thisValue, "forEach");
|
|
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,6 @@
|
|
|
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;
|
|
5
|
+
/** One value as `console.log` shows it. */
|
|
6
|
+
export declare const formatValue: (value: unknown) => string;
|