@opencode/codemode 2.0.12 → 2.0.13
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
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { constructor, fn, methods, prototypeFrom, receiver, requiresNew } from "../interpreter/native.js";
|
|
3
3
|
import { invalidData, IteratorSymbol, typeError } from "../interpreter/model.js";
|
|
4
|
-
import { define, defineAccessor, get, getOwn, hidden,
|
|
5
|
-
import { describeValue,
|
|
4
|
+
import { define, defineAccessor, get, getOwn, hidden, Arr, coerceToString, hostCursor, hostIterator, MapObj, Obj, PromiseObj, SetObj, } from "../interpreter/objects.js";
|
|
5
|
+
import { describeValue, isOpaque } from "../interpreter/references.js";
|
|
6
6
|
import { applyCollectionCallback, isSupportedCallback, preserveConsumerError, toPrimitiveNumber, toPrimitiveString, } from "../interpreter/callback.js";
|
|
7
7
|
const coerceGroupByPropertyKey = (ctx, value) => {
|
|
8
8
|
if (value instanceof PromiseObj)
|
|
9
|
-
return Effect.succeed(
|
|
10
|
-
if (
|
|
9
|
+
return Effect.succeed(coerceToString(value));
|
|
10
|
+
if (isOpaque(value)) {
|
|
11
11
|
throw invalidData(`Object.groupBy callback must return a data value, received ${describeValue(value)}.`);
|
|
12
12
|
}
|
|
13
13
|
return toPrimitiveString(ctx, value);
|
|
@@ -33,7 +33,7 @@ export const groupBy = (ctx, namespace) => fn(ctx.builtins, "groupBy", 2, (_, ar
|
|
|
33
33
|
if (step.done)
|
|
34
34
|
return result;
|
|
35
35
|
const item = step.value;
|
|
36
|
-
const key = yield* preserveConsumerError(cursor, apply([item, index]));
|
|
36
|
+
const key = yield* preserveConsumerError(cursor.close, apply([item, index]));
|
|
37
37
|
const group = result.map.get(key);
|
|
38
38
|
if (group === undefined)
|
|
39
39
|
result.map.set(key, new Arr(builtins.Array, [item]));
|
|
@@ -50,7 +50,7 @@ export const groupBy = (ctx, namespace) => fn(ctx.builtins, "groupBy", 2, (_, ar
|
|
|
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(ctx, value)));
|
|
53
|
+
const key = yield* preserveConsumerError(cursor.close, Effect.flatMap(apply([item, index]), (value) => coerceGroupByPropertyKey(ctx, value)));
|
|
54
54
|
const group = getOwn(result, key);
|
|
55
55
|
if (group === undefined)
|
|
56
56
|
define(result, key, new Arr(builtins.Array, [item]));
|
|
@@ -67,13 +67,13 @@ const constructMap = (ctx, init, proto) => {
|
|
|
67
67
|
return Effect.gen(function* () {
|
|
68
68
|
const cursor = yield* ctx.iterate(init);
|
|
69
69
|
if (cursor === undefined) {
|
|
70
|
-
throw typeError(
|
|
70
|
+
throw typeError(`new Map(...) expects an iterable of [key, value] pairs, received ${describeValue(init)}.`);
|
|
71
71
|
}
|
|
72
72
|
while (true) {
|
|
73
73
|
const step = yield* cursor.next;
|
|
74
74
|
if (step.done)
|
|
75
75
|
return target;
|
|
76
|
-
yield* preserveConsumerError(cursor, Effect.sync(() => {
|
|
76
|
+
yield* preserveConsumerError(cursor.close, Effect.sync(() => {
|
|
77
77
|
if (!(step.value instanceof Obj)) {
|
|
78
78
|
throw typeError("new Map(...) expects [key, value] pairs as entry objects.");
|
|
79
79
|
}
|
|
@@ -89,7 +89,7 @@ const constructSet = (ctx, init, proto) => {
|
|
|
89
89
|
return Effect.gen(function* () {
|
|
90
90
|
const cursor = yield* ctx.iterate(init);
|
|
91
91
|
if (cursor === undefined) {
|
|
92
|
-
throw typeError(
|
|
92
|
+
throw typeError(`new Set(...) expects a synchronous iterable, received ${describeValue(init)}.`);
|
|
93
93
|
}
|
|
94
94
|
while (true) {
|
|
95
95
|
const step = yield* cursor.next;
|
|
@@ -109,7 +109,6 @@ export const mapGlobal = (ctx) => {
|
|
|
109
109
|
});
|
|
110
110
|
define(map, "groupBy", groupBy(ctx, "Map"), hidden);
|
|
111
111
|
const self = (thisValue, name) => receiver(MapObj, thisValue, `Map.prototype.${name}`);
|
|
112
|
-
const wrap = (items) => new Arr(builtins.Array, items);
|
|
113
112
|
defineAccessor(proto, "size", (thisValue) => receiver(MapObj, thisValue, "Map.prototype.size").map.size);
|
|
114
113
|
methods(builtins, proto, [
|
|
115
114
|
["get", 1, (thisValue, args) => self(thisValue, "get").map.get(args[0])],
|
|
@@ -157,15 +156,9 @@ export const mapGlobal = (ctx) => {
|
|
|
157
156
|
return undefined;
|
|
158
157
|
},
|
|
159
158
|
],
|
|
160
|
-
["keys", 0, (thisValue) =>
|
|
161
|
-
["values", 0, (thisValue) =>
|
|
162
|
-
[
|
|
163
|
-
"entries",
|
|
164
|
-
0,
|
|
165
|
-
(thisValue) => new IteratorObj(builtins.Iterator, self(thisValue, "entries")
|
|
166
|
-
.map.entries()
|
|
167
|
-
.map(([key, item]) => wrap([key, item]))),
|
|
168
|
-
],
|
|
159
|
+
["keys", 0, (thisValue) => hostIterator(builtins, self(thisValue, "keys").map.keys())],
|
|
160
|
+
["values", 0, (thisValue) => hostIterator(builtins, self(thisValue, "values").map.values())],
|
|
161
|
+
["entries", 0, (thisValue) => hostIterator(builtins, self(thisValue, "entries").iterator(builtins))],
|
|
169
162
|
[
|
|
170
163
|
"forEach",
|
|
171
164
|
1,
|
|
@@ -173,7 +166,7 @@ export const mapGlobal = (ctx) => {
|
|
|
173
166
|
const target = self(thisValue, "forEach");
|
|
174
167
|
const apply = applyCollectionCallback(ctx, args[0], "Map.forEach");
|
|
175
168
|
return Effect.gen(function* () {
|
|
176
|
-
for (const [key, item] of
|
|
169
|
+
for (const [key, item] of target.map.entries())
|
|
177
170
|
yield* apply([item, key, target]);
|
|
178
171
|
return undefined;
|
|
179
172
|
});
|
|
@@ -214,12 +207,16 @@ const loadSetRecord = (ctx, source, name) => {
|
|
|
214
207
|
return {
|
|
215
208
|
size: Math.max(Math.trunc(size), 0),
|
|
216
209
|
has: (item) => Effect.map(ctx.call(has, source, [item]), Boolean),
|
|
217
|
-
keys: () => Effect.
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
210
|
+
keys: () => Effect.gen(function* () {
|
|
211
|
+
const result = yield* ctx.call(keys, source, []);
|
|
212
|
+
const cursor = result instanceof Arr ? hostCursor(result.items.values()) : ctx.iterateDirect(result);
|
|
213
|
+
const items = [];
|
|
214
|
+
while (true) {
|
|
215
|
+
const step = yield* cursor.next;
|
|
216
|
+
if (step.done)
|
|
217
|
+
return items;
|
|
218
|
+
items.push(step.value);
|
|
219
|
+
}
|
|
223
220
|
}),
|
|
224
221
|
};
|
|
225
222
|
});
|
|
@@ -343,12 +340,12 @@ export const setGlobal = (ctx) => {
|
|
|
343
340
|
return undefined;
|
|
344
341
|
},
|
|
345
342
|
],
|
|
346
|
-
["keys", 0, (thisValue) =>
|
|
347
|
-
["values", 0, (thisValue) =>
|
|
343
|
+
["keys", 0, (thisValue) => hostIterator(builtins, self(thisValue, "keys").set.values())],
|
|
344
|
+
["values", 0, (thisValue) => hostIterator(builtins, self(thisValue, "values").set.values())],
|
|
348
345
|
[
|
|
349
346
|
"entries",
|
|
350
347
|
0,
|
|
351
|
-
(thisValue) =>
|
|
348
|
+
(thisValue) => hostIterator(builtins, self(thisValue, "entries")
|
|
352
349
|
.set.values()
|
|
353
350
|
.map((item) => wrap([item, item]))),
|
|
354
351
|
],
|
|
@@ -359,7 +356,7 @@ export const setGlobal = (ctx) => {
|
|
|
359
356
|
const target = self(thisValue, "forEach");
|
|
360
357
|
const apply = applyCollectionCallback(ctx, args[0], "Set.forEach");
|
|
361
358
|
return Effect.gen(function* () {
|
|
362
|
-
for (const item of
|
|
359
|
+
for (const item of target.set.values())
|
|
363
360
|
yield* apply([item, item, target]);
|
|
364
361
|
return undefined;
|
|
365
362
|
});
|
package/dist/stdlib/console.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Obj } from "../interpreter/objects.js";
|
|
1
|
+
import { Obj, type Value } from "../interpreter/objects.js";
|
|
2
2
|
import type { Interpreter } from "../interpreter/interpreter.js";
|
|
3
3
|
/** Captured console: every method appends one formatted line to `logs`. */
|
|
4
4
|
export declare const consoleGlobal: <R>(ctx: Interpreter<R>) => Obj;
|
|
5
5
|
/** One value as `console.log` shows it. */
|
|
6
|
-
export declare const formatValue: (value:
|
|
6
|
+
export declare const formatValue: (value: Value) => string;
|
package/dist/stdlib/console.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { methods } from "../interpreter/native.js";
|
|
2
|
-
import { entries, get, Arr,
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { entries, get, Arr, Obj } from "../interpreter/objects.js";
|
|
3
|
+
import { ToolReference } from "../tool-runtime.js";
|
|
4
|
+
import { containsOpaqueReference } from "../interpreter/references.js";
|
|
5
5
|
const consoleMethods = ["log", "info", "debug", "warn", "error", "dir", "table"];
|
|
6
6
|
/** Captured console: every method appends one formatted line to `logs`. */
|
|
7
7
|
export const consoleGlobal = (ctx) => {
|
|
@@ -39,64 +39,20 @@ const formatConsoleValue = (value, seen, depth) => {
|
|
|
39
39
|
return "null";
|
|
40
40
|
if (typeof value === "string")
|
|
41
41
|
return JSON.stringify(value);
|
|
42
|
-
if (
|
|
43
|
-
return String(value);
|
|
44
|
-
if (typeof value !== "object")
|
|
45
|
-
return String(value);
|
|
46
|
-
if (value instanceof PromiseObj)
|
|
47
|
-
return "[Promise (await it to get its value)]";
|
|
48
|
-
if (value instanceof DateObj)
|
|
49
|
-
return coerceToString(value);
|
|
50
|
-
if (value instanceof RegExpObj)
|
|
51
|
-
return coerceToString(value);
|
|
52
|
-
if (value instanceof URLObj)
|
|
53
|
-
return coerceToString(value);
|
|
54
|
-
if (value instanceof URLSearchParamsObj)
|
|
55
|
-
return coerceToString(value);
|
|
56
|
-
if (value instanceof HeadersObj)
|
|
57
|
-
return `Headers ${JSON.stringify(Object.fromEntries(value.headers))}`;
|
|
58
|
-
if (value instanceof Bytes)
|
|
59
|
-
return `Uint8Array(${value.bytes.length}) [${value.bytes.join(",")}]`;
|
|
42
|
+
if (!(value instanceof Obj))
|
|
43
|
+
return value instanceof ToolReference ? "[opaque reference]" : String(value);
|
|
60
44
|
if (depth > MAX_CONSOLE_DEPTH)
|
|
61
45
|
return "...";
|
|
62
46
|
if (seen.has(value))
|
|
63
47
|
return "[Circular]";
|
|
64
|
-
if (value instanceof MapObj) {
|
|
65
|
-
seen.add(value);
|
|
66
|
-
try {
|
|
67
|
-
const items = Array.from(value.map.entries(), ([key, item]) => `[${formatItems([key, item], seen, depth + 1)}]`);
|
|
68
|
-
return `Map(${value.map.size}) [${items.join(",")}]`;
|
|
69
|
-
}
|
|
70
|
-
finally {
|
|
71
|
-
seen.delete(value);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
if (value instanceof SetObj) {
|
|
75
|
-
seen.add(value);
|
|
76
|
-
try {
|
|
77
|
-
return `Set(${value.set.size}) [${formatItems([...value.set.values()], seen, depth + 1)}]`;
|
|
78
|
-
}
|
|
79
|
-
finally {
|
|
80
|
-
seen.delete(value);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
if (isRuntimeReference(value))
|
|
84
|
-
return "[opaque reference]";
|
|
85
48
|
seen.add(value);
|
|
86
49
|
try {
|
|
87
|
-
|
|
88
|
-
return `[${formatItems(value.items, seen, depth + 1)}]`;
|
|
89
|
-
if (!(value instanceof Obj))
|
|
90
|
-
return "[object Object]";
|
|
91
|
-
return `{${entries(value)
|
|
92
|
-
.map(([key, item]) => `${JSON.stringify(key)}:${formatConsoleValue(item, seen, depth + 1)}`)
|
|
93
|
-
.join(",")}}`;
|
|
50
|
+
return value.inspect((item) => formatConsoleValue(item, seen, depth + 1));
|
|
94
51
|
}
|
|
95
52
|
finally {
|
|
96
53
|
seen.delete(value);
|
|
97
54
|
}
|
|
98
55
|
};
|
|
99
|
-
const formatItems = (items, seen, depth) => items.map((item) => formatConsoleValue(item, seen, depth)).join(",");
|
|
100
56
|
const formatConsoleTable = (value, columnsArgument) => {
|
|
101
57
|
if (value === undefined)
|
|
102
58
|
return "undefined";
|
package/dist/stdlib/date.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { constructor, methods, prototypeFrom, receiver } from "../interpreter/native.js";
|
|
3
3
|
import { rangeError } from "../interpreter/model.js";
|
|
4
|
-
import { DateObj, Obj } from "../interpreter/objects.js";
|
|
4
|
+
import { DateObj, Obj, coerceToNumber, coerceToString } from "../interpreter/objects.js";
|
|
5
5
|
import { toPrimitive, toPrimitiveNumber } from "../interpreter/callback.js";
|
|
6
|
-
import { coerceToNumber, coerceToString } from "./value.js";
|
|
7
6
|
const constructDate = (ctx, args, proto) => {
|
|
8
7
|
if (args.length === 0)
|
|
9
8
|
return Effect.succeed(new DateObj(proto, Date.now()));
|
package/dist/stdlib/headers.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { constructor, methods, prototypeFrom, receiver, requiresNew } from "../interpreter/native.js";
|
|
3
3
|
import { IteratorSymbol, typeError } from "../interpreter/model.js";
|
|
4
|
-
import { define, entries, get, hidden, Arr, HeadersObj,
|
|
4
|
+
import { define, entries, get, hidden, Arr, HeadersObj, hostIterator, Obj, coerceToString, isRuntimeReference, } from "../interpreter/objects.js";
|
|
5
5
|
import { applyCollectionCallback } from "../interpreter/callback.js";
|
|
6
|
-
import { isRuntimeReference } from "../interpreter/references.js";
|
|
7
|
-
import { coerceToString } from "./value.js";
|
|
8
6
|
import { readPairs } from "./url.js";
|
|
9
7
|
// The host validates header names and values and throws its own TypeError; the program gets one of its own.
|
|
10
8
|
const attempt = (run) => {
|
|
@@ -51,7 +49,8 @@ export const headersGlobal = (ctx) => {
|
|
|
51
49
|
(thisValue, args) => {
|
|
52
50
|
requireArgs("append", args, 2);
|
|
53
51
|
const target = self(thisValue, "append").headers;
|
|
54
|
-
|
|
52
|
+
attempt(() => target.append(arg(args, 0), arg(args, 1)));
|
|
53
|
+
return undefined;
|
|
55
54
|
},
|
|
56
55
|
],
|
|
57
56
|
[
|
|
@@ -60,7 +59,8 @@ export const headersGlobal = (ctx) => {
|
|
|
60
59
|
(thisValue, args) => {
|
|
61
60
|
requireArgs("delete", args, 1);
|
|
62
61
|
const target = self(thisValue, "delete").headers;
|
|
63
|
-
|
|
62
|
+
attempt(() => target.delete(arg(args, 0)));
|
|
63
|
+
return undefined;
|
|
64
64
|
},
|
|
65
65
|
],
|
|
66
66
|
[
|
|
@@ -88,25 +88,13 @@ export const headersGlobal = (ctx) => {
|
|
|
88
88
|
(thisValue, args) => {
|
|
89
89
|
requireArgs("set", args, 2);
|
|
90
90
|
const target = self(thisValue, "set").headers;
|
|
91
|
-
|
|
91
|
+
attempt(() => target.set(arg(args, 0), arg(args, 1)));
|
|
92
|
+
return undefined;
|
|
92
93
|
},
|
|
93
94
|
],
|
|
94
|
-
|
|
95
|
-
[
|
|
96
|
-
|
|
97
|
-
0,
|
|
98
|
-
(thisValue) => new IteratorObj(builtins.Iterator, Iterator.from(self(thisValue, "keys").headers.keys())),
|
|
99
|
-
],
|
|
100
|
-
[
|
|
101
|
-
"values",
|
|
102
|
-
0,
|
|
103
|
-
(thisValue) => new IteratorObj(builtins.Iterator, Iterator.from(self(thisValue, "values").headers.values())),
|
|
104
|
-
],
|
|
105
|
-
[
|
|
106
|
-
"entries",
|
|
107
|
-
0,
|
|
108
|
-
(thisValue) => new IteratorObj(builtins.Iterator, Iterator.from(self(thisValue, "entries").headers.entries()).map(([key, value]) => wrap([key, value]))),
|
|
109
|
-
],
|
|
95
|
+
["keys", 0, (thisValue) => hostIterator(builtins, self(thisValue, "keys").headers.keys())],
|
|
96
|
+
["values", 0, (thisValue) => hostIterator(builtins, self(thisValue, "values").headers.values())],
|
|
97
|
+
["entries", 0, (thisValue) => hostIterator(builtins, self(thisValue, "entries").iterator(builtins))],
|
|
110
98
|
[
|
|
111
99
|
"forEach",
|
|
112
100
|
1,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { Interpreter } from "../interpreter/interpreter.js";
|
|
2
|
-
export declare const iteratorGlobals: <R>(ctx: Interpreter<R>) =>
|
|
2
|
+
export declare const iteratorGlobals: <R>(ctx: Interpreter<R>) => import("../interpreter/objects.js").Native<R>;
|
package/dist/stdlib/iterator.js
CHANGED
|
@@ -1,17 +1,305 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { Cause, Effect, Exit } from "effect";
|
|
2
|
+
import { applyCollectionCallback } from "../interpreter/callback.js";
|
|
3
|
+
import { rangeError, typeError } from "../interpreter/model.js";
|
|
4
|
+
import { constructor, fn, methods, receiver, requiresNew } from "../interpreter/native.js";
|
|
5
|
+
import { Arr, coerceToNumber, define, hasPrototype, hidden, IteratorObj, Obj, record, } from "../interpreter/objects.js";
|
|
6
|
+
import { describeValue } from "../interpreter/references.js";
|
|
7
|
+
const finished = { done: true, value: undefined };
|
|
8
|
+
// Every built-in iterator and helper shares the Iterator prototype; JS gives each collection its own, which is only
|
|
4
9
|
// observable through getPrototypeOf.
|
|
5
10
|
export const iteratorGlobals = (ctx) => {
|
|
6
11
|
const builtins = ctx.builtins;
|
|
7
|
-
|
|
12
|
+
const proto = builtins.Iterator;
|
|
13
|
+
const method = (name) => `Iterator.prototype.${name}`;
|
|
14
|
+
// A step that runs program code: when it throws, close the source first, as IteratorClose does.
|
|
15
|
+
const guarded = (source, body) => Effect.flatMap(Effect.exit(body), (exit) => {
|
|
16
|
+
if (Exit.isSuccess(exit))
|
|
17
|
+
return Effect.succeed(exit.value);
|
|
18
|
+
if (Cause.hasInterruptsOnly(exit.cause))
|
|
19
|
+
return Effect.failCause(exit.cause);
|
|
20
|
+
return Effect.andThen(Effect.exit(source.close), Effect.failCause(exit.cause));
|
|
21
|
+
});
|
|
22
|
+
// A lazy helper: `pull` advances it once. Once it reports done, throws, or is closed, it stays done. A callback
|
|
23
|
+
// that re-enters its own helper is a TypeError, as for a running generator.
|
|
24
|
+
const helper = (source, pull, close = source.close) => {
|
|
25
|
+
let done = false;
|
|
26
|
+
let running = false;
|
|
27
|
+
const enter = () => {
|
|
28
|
+
if (running)
|
|
29
|
+
throw typeError("Iterator helper is already running.");
|
|
30
|
+
running = true;
|
|
31
|
+
};
|
|
32
|
+
return new IteratorObj(builtins.IteratorHelper, {
|
|
33
|
+
next: Effect.suspend(() => {
|
|
34
|
+
if (done)
|
|
35
|
+
return Effect.succeed(finished);
|
|
36
|
+
enter();
|
|
37
|
+
return Effect.flatMap(Effect.exit(pull), (exit) => {
|
|
38
|
+
running = false;
|
|
39
|
+
done = Exit.isSuccess(exit) ? exit.value.done : true;
|
|
40
|
+
return exit;
|
|
41
|
+
});
|
|
42
|
+
}),
|
|
43
|
+
close: Effect.suspend(() => {
|
|
44
|
+
if (done)
|
|
45
|
+
return Effect.void;
|
|
46
|
+
enter();
|
|
47
|
+
done = true;
|
|
48
|
+
return Effect.ensuring(close, Effect.sync(() => {
|
|
49
|
+
running = false;
|
|
50
|
+
}));
|
|
51
|
+
}),
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
// GetIteratorFlattenable: an iterable by `[Symbol.iterator]`, otherwise the object itself as an iterator.
|
|
55
|
+
const flattenable = (value, name, strings) => Effect.gen(function* () {
|
|
56
|
+
if (typeof value === "string" ? !strings : !(value instanceof Obj)) {
|
|
57
|
+
throw typeError(`${name} expects an iterable or iterator, received ${describeValue(value)}.`);
|
|
58
|
+
}
|
|
59
|
+
return (yield* ctx.iterate(value)) ?? ctx.iterateDirect(value);
|
|
60
|
+
});
|
|
61
|
+
const limit = (value, name) => {
|
|
62
|
+
const count = Math.trunc(coerceToNumber(value));
|
|
63
|
+
if (Number.isNaN(count) || count < 0) {
|
|
64
|
+
throw rangeError(`${method(name)} expects a non-negative count, received ${count}.`);
|
|
65
|
+
}
|
|
66
|
+
return count;
|
|
67
|
+
};
|
|
68
|
+
methods(builtins, proto, [
|
|
8
69
|
[
|
|
9
70
|
"next",
|
|
10
71
|
0,
|
|
72
|
+
(thisValue) => Effect.map(receiver(IteratorObj, thisValue, method("next")).cursor.next, (step) => record(builtins.Object, { value: step.value, done: step.done })),
|
|
73
|
+
],
|
|
74
|
+
[
|
|
75
|
+
"map",
|
|
76
|
+
1,
|
|
77
|
+
(thisValue, args) => {
|
|
78
|
+
const source = ctx.iterateDirect(thisValue);
|
|
79
|
+
const apply = applyCollectionCallback(ctx, args[0], method("map"));
|
|
80
|
+
let counter = 0;
|
|
81
|
+
return helper(source, Effect.gen(function* () {
|
|
82
|
+
const step = yield* source.next;
|
|
83
|
+
if (step.done)
|
|
84
|
+
return finished;
|
|
85
|
+
return { done: false, value: yield* guarded(source, apply([step.value, counter++])) };
|
|
86
|
+
}));
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
[
|
|
90
|
+
"filter",
|
|
91
|
+
1,
|
|
92
|
+
(thisValue, args) => {
|
|
93
|
+
const source = ctx.iterateDirect(thisValue);
|
|
94
|
+
const apply = applyCollectionCallback(ctx, args[0], method("filter"));
|
|
95
|
+
let counter = 0;
|
|
96
|
+
return helper(source, Effect.gen(function* () {
|
|
97
|
+
while (true) {
|
|
98
|
+
const step = yield* source.next;
|
|
99
|
+
if (step.done)
|
|
100
|
+
return finished;
|
|
101
|
+
if (yield* guarded(source, apply([step.value, counter++])))
|
|
102
|
+
return step;
|
|
103
|
+
}
|
|
104
|
+
}));
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
[
|
|
108
|
+
"take",
|
|
109
|
+
1,
|
|
110
|
+
(thisValue, args) => {
|
|
111
|
+
const source = ctx.iterateDirect(thisValue);
|
|
112
|
+
let remaining = limit(args[0], "take");
|
|
113
|
+
return helper(source, Effect.gen(function* () {
|
|
114
|
+
if (remaining === 0) {
|
|
115
|
+
yield* source.close;
|
|
116
|
+
return finished;
|
|
117
|
+
}
|
|
118
|
+
remaining -= 1;
|
|
119
|
+
return yield* source.next;
|
|
120
|
+
}));
|
|
121
|
+
},
|
|
122
|
+
],
|
|
123
|
+
[
|
|
124
|
+
"drop",
|
|
125
|
+
1,
|
|
126
|
+
(thisValue, args) => {
|
|
127
|
+
const source = ctx.iterateDirect(thisValue);
|
|
128
|
+
let remaining = limit(args[0], "drop");
|
|
129
|
+
return helper(source, Effect.gen(function* () {
|
|
130
|
+
while (remaining > 0) {
|
|
131
|
+
remaining -= 1;
|
|
132
|
+
const step = yield* source.next;
|
|
133
|
+
if (step.done)
|
|
134
|
+
return finished;
|
|
135
|
+
}
|
|
136
|
+
return yield* source.next;
|
|
137
|
+
}));
|
|
138
|
+
},
|
|
139
|
+
],
|
|
140
|
+
[
|
|
141
|
+
"flatMap",
|
|
142
|
+
1,
|
|
143
|
+
(thisValue, args) => {
|
|
144
|
+
const source = ctx.iterateDirect(thisValue);
|
|
145
|
+
const apply = applyCollectionCallback(ctx, args[0], method("flatMap"));
|
|
146
|
+
let counter = 0;
|
|
147
|
+
let inner;
|
|
148
|
+
return helper(source, Effect.gen(function* () {
|
|
149
|
+
while (true) {
|
|
150
|
+
if (inner !== undefined) {
|
|
151
|
+
const step = yield* guarded(source, inner.next);
|
|
152
|
+
if (!step.done)
|
|
153
|
+
return step;
|
|
154
|
+
inner = undefined;
|
|
155
|
+
}
|
|
156
|
+
const step = yield* source.next;
|
|
157
|
+
if (step.done)
|
|
158
|
+
return finished;
|
|
159
|
+
inner = yield* guarded(source, Effect.flatMap(apply([step.value, counter++]), (mapped) => flattenable(mapped, method("flatMap"), false)));
|
|
160
|
+
}
|
|
161
|
+
}), Effect.suspend(() => (inner === undefined ? source.close : Effect.andThen(inner.close, source.close))));
|
|
162
|
+
},
|
|
163
|
+
],
|
|
164
|
+
[
|
|
165
|
+
"reduce",
|
|
166
|
+
1,
|
|
167
|
+
(thisValue, args) => {
|
|
168
|
+
const source = ctx.iterateDirect(thisValue);
|
|
169
|
+
const apply = applyCollectionCallback(ctx, args[0], method("reduce"));
|
|
170
|
+
return Effect.gen(function* () {
|
|
171
|
+
let counter = 0;
|
|
172
|
+
let accumulator = args[1];
|
|
173
|
+
if (args.length < 2) {
|
|
174
|
+
const first = yield* source.next;
|
|
175
|
+
if (first.done)
|
|
176
|
+
throw typeError("Iterator.prototype.reduce of an empty iterator with no initial value.");
|
|
177
|
+
accumulator = first.value;
|
|
178
|
+
counter = 1;
|
|
179
|
+
}
|
|
180
|
+
while (true) {
|
|
181
|
+
const step = yield* source.next;
|
|
182
|
+
if (step.done)
|
|
183
|
+
return accumulator;
|
|
184
|
+
accumulator = yield* guarded(source, apply([accumulator, step.value, counter++]));
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
[
|
|
190
|
+
"toArray",
|
|
191
|
+
0,
|
|
11
192
|
(thisValue) => {
|
|
12
|
-
const
|
|
13
|
-
return
|
|
193
|
+
const source = ctx.iterateDirect(thisValue);
|
|
194
|
+
return Effect.gen(function* () {
|
|
195
|
+
const items = [];
|
|
196
|
+
while (true) {
|
|
197
|
+
const step = yield* source.next;
|
|
198
|
+
if (step.done)
|
|
199
|
+
return new Arr(builtins.Array, items);
|
|
200
|
+
items.push(step.value);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
},
|
|
204
|
+
],
|
|
205
|
+
[
|
|
206
|
+
"forEach",
|
|
207
|
+
1,
|
|
208
|
+
(thisValue, args) => {
|
|
209
|
+
const source = ctx.iterateDirect(thisValue);
|
|
210
|
+
const apply = applyCollectionCallback(ctx, args[0], method("forEach"));
|
|
211
|
+
return Effect.gen(function* () {
|
|
212
|
+
let counter = 0;
|
|
213
|
+
while (true) {
|
|
214
|
+
const step = yield* source.next;
|
|
215
|
+
if (step.done)
|
|
216
|
+
return undefined;
|
|
217
|
+
yield* guarded(source, apply([step.value, counter++]));
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
},
|
|
221
|
+
],
|
|
222
|
+
[
|
|
223
|
+
"some",
|
|
224
|
+
1,
|
|
225
|
+
(thisValue, args) => {
|
|
226
|
+
const source = ctx.iterateDirect(thisValue);
|
|
227
|
+
const apply = applyCollectionCallback(ctx, args[0], method("some"));
|
|
228
|
+
return Effect.gen(function* () {
|
|
229
|
+
let counter = 0;
|
|
230
|
+
while (true) {
|
|
231
|
+
const step = yield* source.next;
|
|
232
|
+
if (step.done)
|
|
233
|
+
return false;
|
|
234
|
+
if (yield* guarded(source, apply([step.value, counter++]))) {
|
|
235
|
+
yield* source.close;
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
},
|
|
241
|
+
],
|
|
242
|
+
[
|
|
243
|
+
"every",
|
|
244
|
+
1,
|
|
245
|
+
(thisValue, args) => {
|
|
246
|
+
const source = ctx.iterateDirect(thisValue);
|
|
247
|
+
const apply = applyCollectionCallback(ctx, args[0], method("every"));
|
|
248
|
+
return Effect.gen(function* () {
|
|
249
|
+
let counter = 0;
|
|
250
|
+
while (true) {
|
|
251
|
+
const step = yield* source.next;
|
|
252
|
+
if (step.done)
|
|
253
|
+
return true;
|
|
254
|
+
if (!(yield* guarded(source, apply([step.value, counter++])))) {
|
|
255
|
+
yield* source.close;
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
},
|
|
261
|
+
],
|
|
262
|
+
[
|
|
263
|
+
"find",
|
|
264
|
+
1,
|
|
265
|
+
(thisValue, args) => {
|
|
266
|
+
const source = ctx.iterateDirect(thisValue);
|
|
267
|
+
const apply = applyCollectionCallback(ctx, args[0], method("find"));
|
|
268
|
+
return Effect.gen(function* () {
|
|
269
|
+
let counter = 0;
|
|
270
|
+
while (true) {
|
|
271
|
+
const step = yield* source.next;
|
|
272
|
+
if (step.done)
|
|
273
|
+
return undefined;
|
|
274
|
+
if (yield* guarded(source, apply([step.value, counter++]))) {
|
|
275
|
+
yield* source.close;
|
|
276
|
+
return step.value;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
});
|
|
14
280
|
},
|
|
15
281
|
],
|
|
16
282
|
]);
|
|
283
|
+
// Helpers and `Iterator.from` wrappers can be closed; collection iterators, as in JS, cannot.
|
|
284
|
+
methods(builtins, builtins.IteratorHelper, [
|
|
285
|
+
[
|
|
286
|
+
"return",
|
|
287
|
+
0,
|
|
288
|
+
(thisValue) => Effect.map(receiver(IteratorObj, thisValue, "Iterator.prototype.return").cursor.close, () => record(builtins.Object, { value: undefined, done: true })),
|
|
289
|
+
],
|
|
290
|
+
]);
|
|
291
|
+
const iterator = constructor(builtins, proto, {
|
|
292
|
+
name: "Iterator",
|
|
293
|
+
length: 0,
|
|
294
|
+
call: requiresNew("Iterator"),
|
|
295
|
+
construct: () => Effect.sync(() => {
|
|
296
|
+
throw typeError("Iterator is abstract; use Iterator.from(...) or a built-in iterator.");
|
|
297
|
+
}),
|
|
298
|
+
});
|
|
299
|
+
define(iterator, "from", fn(builtins, "from", 1, (_, args) => Effect.gen(function* () {
|
|
300
|
+
if (args[0] instanceof Obj && hasPrototype(args[0], proto))
|
|
301
|
+
return args[0];
|
|
302
|
+
return new IteratorObj(builtins.IteratorHelper, yield* flattenable(args[0], "Iterator.from", true));
|
|
303
|
+
})), hidden);
|
|
304
|
+
return iterator;
|
|
17
305
|
};
|
package/dist/stdlib/json.js
CHANGED
|
@@ -2,10 +2,10 @@ import { Effect } from "effect";
|
|
|
2
2
|
import { methods } from "../interpreter/native.js";
|
|
3
3
|
import { applyCollectionCallback } from "../interpreter/callback.js";
|
|
4
4
|
import { checkStringLength } from "../interpreter/limits.js";
|
|
5
|
-
import { syntaxError
|
|
5
|
+
import { syntaxError } from "../interpreter/model.js";
|
|
6
6
|
import { typeofValue } from "../interpreter/references.js";
|
|
7
7
|
import { fromJson, toJson } from "../data.js";
|
|
8
|
-
import { get, keys, Arr, Obj, record, remove, set } from "../interpreter/objects.js";
|
|
8
|
+
import { get, keys, Arr, Obj, coerceToString, record, remove, set } from "../interpreter/objects.js";
|
|
9
9
|
export const jsonGlobal = (ctx) => {
|
|
10
10
|
const json = new Obj(ctx.builtins.Object);
|
|
11
11
|
methods(ctx.builtins, json, [
|
|
@@ -15,9 +15,7 @@ export const jsonGlobal = (ctx) => {
|
|
|
15
15
|
return json;
|
|
16
16
|
};
|
|
17
17
|
const parse = (ctx, args) => {
|
|
18
|
-
const text = args[0];
|
|
19
|
-
if (typeof text !== "string")
|
|
20
|
-
throw typeError("JSON.parse expects a string.");
|
|
18
|
+
const text = coerceToString(args[0]);
|
|
21
19
|
const parsed = (() => {
|
|
22
20
|
try {
|
|
23
21
|
return fromJson(ctx, JSON.parse(text));
|