@opencode/codemode 2.0.11 → 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.
Files changed (50) hide show
  1. package/dist/data.d.ts +5 -4
  2. package/dist/interpreter/callback.d.ts +11 -14
  3. package/dist/interpreter/callback.js +23 -7
  4. package/dist/interpreter/errors.d.ts +3 -3
  5. package/dist/interpreter/errors.js +2 -2
  6. package/dist/interpreter/execute.d.ts +2 -1
  7. package/dist/interpreter/extensions.d.ts +2 -1
  8. package/dist/interpreter/extensions.js +7 -35
  9. package/dist/interpreter/globals.d.ts +2 -1
  10. package/dist/interpreter/globals.js +1 -1
  11. package/dist/interpreter/interpreter.d.ts +9 -20
  12. package/dist/interpreter/interpreter.js +124 -122
  13. package/dist/interpreter/intrinsics.d.ts +4 -2
  14. package/dist/interpreter/intrinsics.js +12 -0
  15. package/dist/interpreter/model.d.ts +7 -8
  16. package/dist/interpreter/model.js +3 -3
  17. package/dist/interpreter/native.d.ts +5 -5
  18. package/dist/interpreter/objects.d.ts +148 -47
  19. package/dist/interpreter/objects.js +224 -26
  20. package/dist/interpreter/promises.d.ts +7 -7
  21. package/dist/interpreter/promises.js +32 -11
  22. package/dist/interpreter/references.d.ts +8 -7
  23. package/dist/interpreter/references.js +10 -46
  24. package/dist/interpreter/scope.d.ts +5 -4
  25. package/dist/stdlib/array.d.ts +2 -1
  26. package/dist/stdlib/array.js +37 -52
  27. package/dist/stdlib/bytes.js +14 -24
  28. package/dist/stdlib/collections.js +52 -30
  29. package/dist/stdlib/console.d.ts +2 -2
  30. package/dist/stdlib/console.js +6 -50
  31. package/dist/stdlib/date.js +6 -2
  32. package/dist/stdlib/headers.js +10 -22
  33. package/dist/stdlib/iterator.d.ts +1 -1
  34. package/dist/stdlib/iterator.js +294 -6
  35. package/dist/stdlib/json.js +3 -5
  36. package/dist/stdlib/math.js +5 -17
  37. package/dist/stdlib/number.js +9 -21
  38. package/dist/stdlib/object.d.ts +3 -4
  39. package/dist/stdlib/object.js +7 -18
  40. package/dist/stdlib/regexp.d.ts +3 -3
  41. package/dist/stdlib/regexp.js +1 -2
  42. package/dist/stdlib/string.js +12 -20
  43. package/dist/stdlib/url.d.ts +2 -1
  44. package/dist/stdlib/url.js +6 -16
  45. package/dist/stdlib/value.d.ts +0 -3
  46. package/dist/stdlib/value.js +2 -74
  47. package/dist/stdlib/web.js +1 -2
  48. package/dist/tool-runtime.d.ts +2 -0
  49. package/dist/tool-runtime.js +39 -27
  50. 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, isWrapper, Arr, IteratorObj, MapObj, Obj, PromiseObj, SetObj, } from "../interpreter/objects.js";
5
- import { describeValue, isRuntimeReference } from "../interpreter/references.js";
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("[object Promise]");
10
- if (!isWrapper(value) && isRuntimeReference(value)) {
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("new Map(...) expects an iterable of [key, value] pairs or no argument.");
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("new Set(...) expects a synchronous iterable or no argument.");
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])],
@@ -123,6 +122,31 @@ export const mapGlobal = (ctx) => {
123
122
  return target;
124
123
  },
125
124
  ],
125
+ [
126
+ "getOrInsert",
127
+ 2,
128
+ (thisValue, args) => {
129
+ const target = self(thisValue, "getOrInsert").map;
130
+ if (!target.has(args[0]))
131
+ target.set(args[0], args[1]);
132
+ return target.get(args[0]);
133
+ },
134
+ ],
135
+ [
136
+ "getOrInsertComputed",
137
+ 2,
138
+ (thisValue, args) => {
139
+ const target = self(thisValue, "getOrInsertComputed").map;
140
+ const apply = applyCollectionCallback(ctx, args[1], "Map.getOrInsertComputed");
141
+ if (target.has(args[0]))
142
+ return target.get(args[0]);
143
+ // The callback sees the stored key (-0 is +0) and its result wins over anything it inserted itself.
144
+ return Effect.map(apply([args[0] === 0 ? 0 : args[0]]), (value) => {
145
+ target.set(args[0], value);
146
+ return value;
147
+ });
148
+ },
149
+ ],
126
150
  ["delete", 1, (thisValue, args) => self(thisValue, "delete").map.delete(args[0])],
127
151
  [
128
152
  "clear",
@@ -132,15 +156,9 @@ export const mapGlobal = (ctx) => {
132
156
  return undefined;
133
157
  },
134
158
  ],
135
- ["keys", 0, (thisValue) => new IteratorObj(builtins.Iterator, self(thisValue, "keys").map.keys())],
136
- ["values", 0, (thisValue) => new IteratorObj(builtins.Iterator, self(thisValue, "values").map.values())],
137
- [
138
- "entries",
139
- 0,
140
- (thisValue) => new IteratorObj(builtins.Iterator, self(thisValue, "entries")
141
- .map.entries()
142
- .map(([key, item]) => wrap([key, item]))),
143
- ],
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))],
144
162
  [
145
163
  "forEach",
146
164
  1,
@@ -148,7 +166,7 @@ export const mapGlobal = (ctx) => {
148
166
  const target = self(thisValue, "forEach");
149
167
  const apply = applyCollectionCallback(ctx, args[0], "Map.forEach");
150
168
  return Effect.gen(function* () {
151
- for (const [key, item] of Array.from(target.map.entries()))
169
+ for (const [key, item] of target.map.entries())
152
170
  yield* apply([item, key, target]);
153
171
  return undefined;
154
172
  });
@@ -189,12 +207,16 @@ const loadSetRecord = (ctx, source, name) => {
189
207
  return {
190
208
  size: Math.max(Math.trunc(size), 0),
191
209
  has: (item) => Effect.map(ctx.call(has, source, [item]), Boolean),
192
- keys: () => Effect.flatMap(ctx.call(keys, source, []), (result) => {
193
- if (result instanceof IteratorObj)
194
- return Effect.succeed(result.iterator);
195
- if (result instanceof Arr)
196
- return Effect.succeed(result.items);
197
- throw typeError(`Set.${name} expected 'keys' to return an iterator.`);
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
+ }
198
220
  }),
199
221
  };
200
222
  });
@@ -318,12 +340,12 @@ export const setGlobal = (ctx) => {
318
340
  return undefined;
319
341
  },
320
342
  ],
321
- ["keys", 0, (thisValue) => new IteratorObj(builtins.Iterator, self(thisValue, "keys").set.values())],
322
- ["values", 0, (thisValue) => new IteratorObj(builtins.Iterator, self(thisValue, "values").set.values())],
343
+ ["keys", 0, (thisValue) => hostIterator(builtins, self(thisValue, "keys").set.values())],
344
+ ["values", 0, (thisValue) => hostIterator(builtins, self(thisValue, "values").set.values())],
323
345
  [
324
346
  "entries",
325
347
  0,
326
- (thisValue) => new IteratorObj(builtins.Iterator, self(thisValue, "entries")
348
+ (thisValue) => hostIterator(builtins, self(thisValue, "entries")
327
349
  .set.values()
328
350
  .map((item) => wrap([item, item]))),
329
351
  ],
@@ -334,7 +356,7 @@ export const setGlobal = (ctx) => {
334
356
  const target = self(thisValue, "forEach");
335
357
  const apply = applyCollectionCallback(ctx, args[0], "Set.forEach");
336
358
  return Effect.gen(function* () {
337
- for (const item of Array.from(target.set.values()))
359
+ for (const item of target.set.values())
338
360
  yield* apply([item, item, target]);
339
361
  return undefined;
340
362
  });
@@ -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: unknown) => string;
6
+ export declare const formatValue: (value: Value) => string;
@@ -1,7 +1,7 @@
1
1
  import { methods } from "../interpreter/native.js";
2
- import { entries, get, Arr, Bytes, DateObj, MapObj, Obj, PromiseObj, RegExpObj, SetObj, URLObj, URLSearchParamsObj, HeadersObj, } from "../interpreter/objects.js";
3
- import { containsOpaqueReference, isRuntimeReference } from "../interpreter/references.js";
4
- import { coerceToString } from "./value.js";
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 (typeof value === "number" || typeof value === "boolean")
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
- if (value instanceof Arr)
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";
@@ -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()));
@@ -92,6 +91,11 @@ export const dateGlobal = (ctx) => {
92
91
  ["toTimeString", 0, (thisValue) => new Date(self(thisValue, "toTimeString").time).toTimeString()],
93
92
  ["toUTCString", 0, (thisValue) => new Date(self(thisValue, "toUTCString").time).toUTCString()],
94
93
  ["toGMTString", 0, (thisValue) => new Date(self(thisValue, "toGMTString").time).toUTCString()],
94
+ ...["toLocaleString", "toLocaleDateString", "toLocaleTimeString"].map((name) => [
95
+ name,
96
+ 0,
97
+ (thisValue) => new Date(self(thisValue, name).time)[name]("en-US", { timeZone: "UTC" }),
98
+ ]),
95
99
  ...getters.map((name) => [name, 0, (thisValue) => new Date(self(thisValue, name).time)[name]()]),
96
100
  ...setters.map(([name, length]) => [
97
101
  name,
@@ -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, IteratorObj, Obj } from "../interpreter/objects.js";
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
- return attempt(() => target.append(arg(args, 0), arg(args, 1)));
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
- return attempt(() => target.delete(arg(args, 0)));
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
- return attempt(() => target.set(arg(args, 0), arg(args, 1)));
91
+ attempt(() => target.set(arg(args, 0), arg(args, 1)));
92
+ return undefined;
92
93
  },
93
94
  ],
94
- // Iterator.from because Bun's Headers typings predate iterator helpers; the runtime iterators already have them.
95
- [
96
- "keys",
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>) => void;
2
+ export declare const iteratorGlobals: <R>(ctx: Interpreter<R>) => import("../interpreter/objects.js").Native<R>;
@@ -1,17 +1,305 @@
1
- import { methods, receiver } from "../interpreter/native.js";
2
- import { IteratorObj, record } from "../interpreter/objects.js";
3
- // Every built-in collection iterator shares the Iterator prototype; JS gives each collection its own, which is only
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
- methods(builtins, builtins.Iterator, [
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 step = receiver(IteratorObj, thisValue, "Iterator.prototype.next").iterator.next();
13
- return record(builtins.Object, { value: step.value, done: Boolean(step.done) });
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
  };