@opencode/codemode 2.0.3 → 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
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { checkArrayLength } from "./limits.js";
|
|
2
|
+
import { AsyncIteratorSymbol, IteratorSymbol, } from "./model.js";
|
|
2
3
|
/** Ordinary assignment: writable, enumerable, configurable. */
|
|
3
4
|
export const data = { writable: true, enumerable: true, configurable: true };
|
|
4
5
|
/** Built-in methods and `constructor`: writable and configurable but hidden from enumeration. */
|
|
@@ -8,14 +9,14 @@ export const readonly = { writable: false, enumerable: false, configurable: true
|
|
|
8
9
|
/** Constants such as `Math.PI` and a constructor's `prototype`. */
|
|
9
10
|
export const frozen = { writable: false, enumerable: false, configurable: false };
|
|
10
11
|
/** An object owned by the program: own properties plus a prototype link. */
|
|
11
|
-
export class
|
|
12
|
+
export class Obj {
|
|
12
13
|
proto;
|
|
13
14
|
props = new Map();
|
|
14
15
|
constructor(proto) {
|
|
15
16
|
this.proto = proto;
|
|
16
17
|
}
|
|
17
18
|
}
|
|
18
|
-
export class
|
|
19
|
+
export class Arr extends Obj {
|
|
19
20
|
items;
|
|
20
21
|
constructor(proto, items = []) {
|
|
21
22
|
super(proto);
|
|
@@ -23,16 +24,18 @@ export class ProgramArray extends ProgramObject {
|
|
|
23
24
|
}
|
|
24
25
|
}
|
|
25
26
|
/** An object with the [[ErrorData]] slot: what `Error.prototype.toString` and the host boundary recognize as an error. */
|
|
26
|
-
export class
|
|
27
|
+
export class ErrorObj extends Obj {
|
|
28
|
+
/** The interpreter failure this error materialized from, so rethrowing it keeps the diagnostic kind and location. */
|
|
29
|
+
host;
|
|
27
30
|
}
|
|
28
|
-
export class Callable extends
|
|
31
|
+
export class Callable extends Obj {
|
|
29
32
|
constructor(proto, name, length) {
|
|
30
33
|
super(proto);
|
|
31
34
|
define(this, "length", length, readonly);
|
|
32
35
|
define(this, "name", name, readonly);
|
|
33
36
|
}
|
|
34
37
|
}
|
|
35
|
-
export class
|
|
38
|
+
export class Fn extends Callable {
|
|
36
39
|
parameters;
|
|
37
40
|
body;
|
|
38
41
|
capturedScopes;
|
|
@@ -48,7 +51,7 @@ export class ProgramFunction extends Callable {
|
|
|
48
51
|
this.generator = generator;
|
|
49
52
|
}
|
|
50
53
|
}
|
|
51
|
-
export class
|
|
54
|
+
export class Native extends Callable {
|
|
52
55
|
call;
|
|
53
56
|
construct;
|
|
54
57
|
callback;
|
|
@@ -59,14 +62,14 @@ export class NativeFunction extends Callable {
|
|
|
59
62
|
this.callback = options.callback ?? true;
|
|
60
63
|
}
|
|
61
64
|
}
|
|
62
|
-
export class
|
|
65
|
+
export class PromiseObj extends Obj {
|
|
63
66
|
fiber;
|
|
64
67
|
constructor(proto, fiber) {
|
|
65
68
|
super(proto);
|
|
66
69
|
this.fiber = fiber;
|
|
67
70
|
}
|
|
68
71
|
}
|
|
69
|
-
export class
|
|
72
|
+
export class GeneratorObj extends Obj {
|
|
70
73
|
asynchronous;
|
|
71
74
|
request;
|
|
72
75
|
constructor(proto, asynchronous, request) {
|
|
@@ -75,70 +78,82 @@ export class ProgramGenerator extends ProgramObject {
|
|
|
75
78
|
this.request = request;
|
|
76
79
|
}
|
|
77
80
|
}
|
|
78
|
-
export class
|
|
81
|
+
export class DateObj extends Obj {
|
|
79
82
|
time;
|
|
80
83
|
constructor(proto, time) {
|
|
81
84
|
super(proto);
|
|
82
85
|
this.time = time;
|
|
83
86
|
}
|
|
84
87
|
}
|
|
85
|
-
export class
|
|
88
|
+
export class RegExpObj extends Obj {
|
|
86
89
|
regex;
|
|
87
90
|
constructor(proto, pattern, flags) {
|
|
88
91
|
super(proto);
|
|
89
92
|
this.regex = new RegExp(pattern, flags);
|
|
90
|
-
define(this, "lastIndex", 0, { writable: true, enumerable: false, configurable: false });
|
|
91
93
|
}
|
|
92
94
|
}
|
|
93
|
-
export class
|
|
95
|
+
export class MapObj extends Obj {
|
|
94
96
|
map = new Map();
|
|
95
97
|
}
|
|
96
|
-
export class
|
|
98
|
+
export class SetObj extends Obj {
|
|
97
99
|
set = new Set();
|
|
98
100
|
}
|
|
99
|
-
export class
|
|
101
|
+
export class URLSearchParamsObj extends Obj {
|
|
100
102
|
params;
|
|
101
103
|
constructor(proto, params) {
|
|
102
104
|
super(proto);
|
|
103
105
|
this.params = params;
|
|
104
106
|
}
|
|
105
107
|
}
|
|
106
|
-
export class
|
|
108
|
+
export class URLObj extends Obj {
|
|
107
109
|
url;
|
|
108
110
|
searchParams;
|
|
109
111
|
constructor(proto, searchParamsProto, url) {
|
|
110
112
|
super(proto);
|
|
111
113
|
this.url = url;
|
|
112
|
-
this.searchParams = new
|
|
114
|
+
this.searchParams = new URLSearchParamsObj(searchParamsProto, url.searchParams);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/** A `Uint8Array`: the host array does the byte clamping and ignores out-of-range writes, as JS does. */
|
|
118
|
+
export class Bytes extends Obj {
|
|
119
|
+
bytes;
|
|
120
|
+
constructor(proto, bytes) {
|
|
121
|
+
super(proto);
|
|
122
|
+
this.bytes = bytes;
|
|
113
123
|
}
|
|
114
124
|
}
|
|
115
125
|
/** Built-in objects that wrap a host value; data-like, but never plain data. */
|
|
116
|
-
export const isWrapper = (value) => value instanceof
|
|
117
|
-
value instanceof
|
|
118
|
-
value instanceof
|
|
119
|
-
value instanceof
|
|
120
|
-
value instanceof
|
|
121
|
-
value instanceof
|
|
122
|
-
|
|
126
|
+
export const isWrapper = (value) => value instanceof DateObj ||
|
|
127
|
+
value instanceof RegExpObj ||
|
|
128
|
+
value instanceof MapObj ||
|
|
129
|
+
value instanceof SetObj ||
|
|
130
|
+
value instanceof URLObj ||
|
|
131
|
+
value instanceof URLSearchParamsObj ||
|
|
132
|
+
value instanceof Bytes;
|
|
133
|
+
const MAX_ARRAY_INDEX = 4_294_967_295;
|
|
123
134
|
export const parseArrayIndex = (key) => {
|
|
124
135
|
const property = String(key);
|
|
125
136
|
if (!/^(0|[1-9]\d*)$/.test(property))
|
|
126
137
|
return undefined;
|
|
127
138
|
const index = Number(property);
|
|
128
|
-
return index <
|
|
139
|
+
return index < MAX_ARRAY_INDEX ? index : undefined;
|
|
129
140
|
};
|
|
130
141
|
const canonical = (key) => (typeof key === "symbol" ? key : String(key));
|
|
131
|
-
const
|
|
142
|
+
const isIndexed = (target) => target instanceof Arr || target instanceof Bytes;
|
|
143
|
+
const elements = (target) => (target instanceof Arr ? target.items : target.bytes);
|
|
144
|
+
const index = (target, key) => isIndexed(target) && typeof key === "string" ? parseArrayIndex(key) : undefined;
|
|
132
145
|
/** The own property under `key`, including an array's live indexes and `length`. */
|
|
133
146
|
export const own = (target, key) => {
|
|
134
147
|
const name = canonical(key);
|
|
135
|
-
if (target
|
|
148
|
+
if (isIndexed(target)) {
|
|
136
149
|
const at = index(target, name);
|
|
137
150
|
if (at !== undefined) {
|
|
138
|
-
|
|
151
|
+
const items = elements(target);
|
|
152
|
+
return at in items ? { value: items[at], ...data } : undefined;
|
|
139
153
|
}
|
|
140
|
-
if (name === "length")
|
|
154
|
+
if (target instanceof Arr && name === "length") {
|
|
141
155
|
return { value: target.items.length, writable: true, enumerable: false, configurable: false };
|
|
156
|
+
}
|
|
142
157
|
}
|
|
143
158
|
return target.props.get(name);
|
|
144
159
|
};
|
|
@@ -165,23 +180,27 @@ export const has = (target, key) => {
|
|
|
165
180
|
return false;
|
|
166
181
|
};
|
|
167
182
|
export const hasPrototype = (value, proto) => {
|
|
168
|
-
for (let current = value instanceof
|
|
183
|
+
for (let current = value instanceof Obj ? value.proto : null; current !== null; current = current.proto) {
|
|
169
184
|
if (current === proto)
|
|
170
185
|
return true;
|
|
171
186
|
}
|
|
172
187
|
return false;
|
|
173
188
|
};
|
|
174
|
-
const
|
|
189
|
+
const writeElement = (target, name, value) => {
|
|
175
190
|
const at = index(target, name);
|
|
176
191
|
if (at !== undefined) {
|
|
177
|
-
target
|
|
192
|
+
if (target instanceof Bytes)
|
|
193
|
+
target.bytes[at] = typeof value === "number" ? value : Number(value);
|
|
194
|
+
else
|
|
195
|
+
target.items[at] = value;
|
|
178
196
|
return true;
|
|
179
197
|
}
|
|
180
|
-
if (name !== "length")
|
|
198
|
+
if (!(target instanceof Arr) || name !== "length")
|
|
181
199
|
return undefined;
|
|
182
200
|
const length = typeof value === "number" ? value : Number(value);
|
|
183
|
-
if (!Number.isInteger(length) || length < 0
|
|
201
|
+
if (!Number.isInteger(length) || length < 0)
|
|
184
202
|
return false;
|
|
203
|
+
checkArrayLength(length);
|
|
185
204
|
target.items.length = length;
|
|
186
205
|
return true;
|
|
187
206
|
};
|
|
@@ -202,16 +221,16 @@ export const set = (target, key, value) => {
|
|
|
202
221
|
return false;
|
|
203
222
|
if (current !== target)
|
|
204
223
|
break;
|
|
205
|
-
if (target
|
|
206
|
-
const written =
|
|
224
|
+
if (isIndexed(target)) {
|
|
225
|
+
const written = writeElement(target, name, value);
|
|
207
226
|
if (written !== undefined)
|
|
208
227
|
return written;
|
|
209
228
|
}
|
|
210
229
|
slot.value = value;
|
|
211
230
|
return true;
|
|
212
231
|
}
|
|
213
|
-
if (target
|
|
214
|
-
const written =
|
|
232
|
+
if (isIndexed(target)) {
|
|
233
|
+
const written = writeElement(target, name, value);
|
|
215
234
|
if (written !== undefined)
|
|
216
235
|
return written;
|
|
217
236
|
}
|
|
@@ -221,7 +240,7 @@ export const set = (target, key, value) => {
|
|
|
221
240
|
/** [[DefineOwnProperty]] for a data property, ignoring the chain. */
|
|
222
241
|
export const define = (target, key, value, attrs = data) => {
|
|
223
242
|
const name = canonical(key);
|
|
224
|
-
if (target
|
|
243
|
+
if (isIndexed(target) && writeElement(target, name, value) !== undefined)
|
|
225
244
|
return;
|
|
226
245
|
target.props.set(name, { value, ...attrs });
|
|
227
246
|
};
|
|
@@ -230,11 +249,11 @@ export const defineAccessor = (target, key, get, set) => {
|
|
|
230
249
|
};
|
|
231
250
|
export const remove = (target, key) => {
|
|
232
251
|
const name = canonical(key);
|
|
233
|
-
if (target
|
|
252
|
+
if (isIndexed(target)) {
|
|
234
253
|
const at = index(target, name);
|
|
235
254
|
if (at !== undefined)
|
|
236
|
-
return delete target.items[at];
|
|
237
|
-
if (name === "length")
|
|
255
|
+
return target instanceof Bytes ? !(at in target.bytes) : delete target.items[at];
|
|
256
|
+
if (target instanceof Arr && name === "length")
|
|
238
257
|
return false;
|
|
239
258
|
}
|
|
240
259
|
const slot = target.props.get(name);
|
|
@@ -250,7 +269,8 @@ export const ownKeys = (target) => {
|
|
|
250
269
|
const strings = [...target.props.keys()].filter((key) => typeof key === "string");
|
|
251
270
|
const symbols = [...target.props.keys()].filter((key) => typeof key === "symbol");
|
|
252
271
|
return [
|
|
253
|
-
...(target
|
|
272
|
+
...(isIndexed(target) ? Object.keys(elements(target)) : []),
|
|
273
|
+
...(target instanceof Arr ? ["length"] : []),
|
|
254
274
|
...strings.filter((key) => parseArrayIndex(key) !== undefined).sort((a, b) => Number(a) - Number(b)),
|
|
255
275
|
...strings.filter((key) => parseArrayIndex(key) === undefined),
|
|
256
276
|
...symbols,
|
|
@@ -264,7 +284,7 @@ export const keys = (target) => ownKeys(target).filter((key) => typeof key === "
|
|
|
264
284
|
/** Own enumerable string entries: `Object.entries` and serialization. */
|
|
265
285
|
export const entries = (target) => keys(target).map((key) => [key, getOwn(target, key)]);
|
|
266
286
|
export const record = (proto, fields) => {
|
|
267
|
-
const target = new
|
|
287
|
+
const target = new Obj(proto);
|
|
268
288
|
for (const [key, value] of Object.entries(fields))
|
|
269
289
|
define(target, key, value);
|
|
270
290
|
return target;
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { Effect, Exit, Scope } from "effect";
|
|
2
2
|
import type { Diagnostic } from "../codemode.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
export declare class PromiseRuntime<R> {
|
|
3
|
+
import { Obj, PromiseObj } from "./objects.js";
|
|
4
|
+
import type { Interpreter } from "./interpreter.js";
|
|
5
|
+
export declare class Pending<R> {
|
|
7
6
|
private readonly scope;
|
|
8
7
|
private readonly proto;
|
|
9
8
|
private readonly active;
|
|
@@ -11,20 +10,19 @@ export declare class PromiseRuntime<R> {
|
|
|
11
10
|
private readonly observed;
|
|
12
11
|
private readonly failures;
|
|
13
12
|
private nextID;
|
|
14
|
-
constructor(scope: Scope.Scope, proto:
|
|
13
|
+
constructor(scope: Scope.Scope, proto: Obj);
|
|
15
14
|
createWithSelf(body: (self: {
|
|
16
|
-
promise?:
|
|
17
|
-
}) => Effect.Effect<unknown, unknown, R>): Effect.Effect<
|
|
18
|
-
create(effect: Effect.Effect<unknown, unknown, R>): Effect.Effect<
|
|
19
|
-
markObserved(promise:
|
|
20
|
-
await(promise:
|
|
15
|
+
promise?: PromiseObj;
|
|
16
|
+
}) => Effect.Effect<unknown, unknown, R>): Effect.Effect<PromiseObj, never, R>;
|
|
17
|
+
create(effect: Effect.Effect<unknown, unknown, R>): Effect.Effect<PromiseObj, never, R>;
|
|
18
|
+
markObserved(promise: PromiseObj): void;
|
|
19
|
+
await(promise: PromiseObj): Effect.Effect<Exit.Exit<unknown, unknown>>;
|
|
21
20
|
fork(effect: Effect.Effect<unknown, unknown, R>): Effect.Effect<void, never, R>;
|
|
22
21
|
diagnostics(): Array<Diagnostic>;
|
|
23
22
|
interrupt(): Effect.Effect<Array<Diagnostic>>;
|
|
24
23
|
}
|
|
25
|
-
export declare const
|
|
26
|
-
|
|
27
|
-
promise?: ProgramPromise;
|
|
24
|
+
export declare const resolvePromiseValue: <R>(ctx: Interpreter<R>, value: unknown, own?: {
|
|
25
|
+
promise?: PromiseObj;
|
|
28
26
|
}) => Effect.Effect<unknown, unknown, R>;
|
|
29
|
-
export declare const resolvePromise: <R>(
|
|
30
|
-
export declare const promiseGlobal: <R>(
|
|
27
|
+
export declare const resolvePromise: <R>(ctx: Interpreter<R>, value: unknown) => Effect.Effect<PromiseObj, never, R>;
|
|
28
|
+
export declare const promiseGlobal: <R>(ctx: Interpreter<R>) => import("./objects.js").Native<R>;
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { Cause, Deferred, Effect, Exit, Fiber, Scope } from "effect";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { MAX_PENDING_PROMISES } from "./limits.js";
|
|
3
|
+
import { CallSite, Throw, rangeError, typeError } from "./model.js";
|
|
4
|
+
import { Callable, define, get, hidden, Arr, Fn, Obj, PromiseObj, record } from "./objects.js";
|
|
4
5
|
import { constructor, fn, methods, native, receiver, requiresNew } from "./native.js";
|
|
5
|
-
import {
|
|
6
|
+
import { createAggregateErrorValue, locate, materialize, normalizeError } from "./errors.js";
|
|
6
7
|
import { typeofValue } from "./references.js";
|
|
7
|
-
import { applyCollectionCallback, isSupportedCallback } from "./
|
|
8
|
+
import { applyCollectionCallback, isSupportedCallback } from "./callback.js";
|
|
8
9
|
// A `resolve`/`reject` handed to an executor or thenable: calling it settles the capability.
|
|
9
|
-
const capability = (
|
|
10
|
+
const capability = (ctx, name, settle) => fn(ctx.builtins, name, 1, (_, args) => {
|
|
10
11
|
settle(args[0]);
|
|
11
12
|
return undefined;
|
|
12
13
|
});
|
|
13
14
|
// Observation only controls rejection reporting; program completion interrupts all promise work.
|
|
14
|
-
export class
|
|
15
|
+
export class Pending {
|
|
15
16
|
scope;
|
|
16
17
|
proto;
|
|
17
18
|
active = new Set();
|
|
@@ -32,11 +33,15 @@ export class PromiseRuntime {
|
|
|
32
33
|
});
|
|
33
34
|
}
|
|
34
35
|
create(effect) {
|
|
35
|
-
return Effect.
|
|
36
|
+
return Effect.flatMap(CallSite, (site) => {
|
|
37
|
+
if (this.active.size >= MAX_PENDING_PROMISES) {
|
|
38
|
+
throw rangeError(`Too many pending promises (limit ${MAX_PENDING_PROMISES}); await promises before creating more.`);
|
|
39
|
+
}
|
|
36
40
|
// Allocate before forking so reruns get distinct IDs and diagnostics retain creation order.
|
|
37
41
|
const id = this.nextID++;
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
const body = Effect.catchDefect(effect, (defect) => Effect.die(locate(defect, site.node)));
|
|
43
|
+
return Effect.map(Effect.forkIn(body, this.scope, { startImmediately: true }), (fiber) => {
|
|
44
|
+
const promise = new PromiseObj(this.proto, fiber);
|
|
40
45
|
this.active.add(promise);
|
|
41
46
|
this.ids.set(promise, id);
|
|
42
47
|
fiber.addObserver((exit) => {
|
|
@@ -83,13 +88,13 @@ export class PromiseRuntime {
|
|
|
83
88
|
});
|
|
84
89
|
}
|
|
85
90
|
}
|
|
86
|
-
export const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
if (value instanceof
|
|
91
|
-
return
|
|
92
|
-
if (!(value instanceof
|
|
91
|
+
export const resolvePromiseValue = (ctx, value, own) => {
|
|
92
|
+
if (own?.promise !== undefined && value === own.promise) {
|
|
93
|
+
return Effect.die(typeError("Chaining cycle detected: a promise cannot resolve with itself."));
|
|
94
|
+
}
|
|
95
|
+
if (value instanceof PromiseObj)
|
|
96
|
+
return ctx.await(value);
|
|
97
|
+
if (!(value instanceof Obj))
|
|
93
98
|
return Effect.succeed(value);
|
|
94
99
|
const then = get(value, "then");
|
|
95
100
|
if (typeofValue(then) !== "function")
|
|
@@ -98,102 +103,101 @@ export const resolvePromiseValue = (runner, value, node, own) => {
|
|
|
98
103
|
// Promise resolution invokes a thenable's method in a later job.
|
|
99
104
|
yield* Effect.yieldNow;
|
|
100
105
|
const deferred = Deferred.makeUnsafe();
|
|
101
|
-
const resolve = capability(
|
|
102
|
-
const reject = capability(
|
|
103
|
-
const executed = yield* Effect.exit(
|
|
106
|
+
const resolve = capability(ctx, "resolve", (result) => Deferred.doneUnsafe(deferred, Exit.succeed(result)));
|
|
107
|
+
const reject = capability(ctx, "reject", (reason) => Deferred.doneUnsafe(deferred, Exit.fail(new Throw(reason))));
|
|
108
|
+
const executed = yield* Effect.exit(ctx.call(then, value, [resolve, reject]));
|
|
104
109
|
if (!Exit.isSuccess(executed)) {
|
|
105
110
|
if (Cause.hasInterruptsOnly(executed.cause))
|
|
106
111
|
return yield* Effect.failCause(executed.cause);
|
|
107
112
|
Deferred.doneUnsafe(deferred, Exit.fail(Cause.squash(executed.cause)));
|
|
108
113
|
}
|
|
109
|
-
return yield* resolvePromiseValue(
|
|
114
|
+
return yield* resolvePromiseValue(ctx, yield* Deferred.await(deferred), own);
|
|
110
115
|
});
|
|
111
116
|
};
|
|
112
|
-
export const resolvePromise = (
|
|
113
|
-
if (value instanceof
|
|
117
|
+
export const resolvePromise = (ctx, value) => {
|
|
118
|
+
if (value instanceof PromiseObj)
|
|
114
119
|
return Effect.succeed(value);
|
|
115
|
-
return
|
|
120
|
+
return ctx.pending.createWithSelf((self) => resolvePromiseValue(ctx, value, self));
|
|
116
121
|
};
|
|
117
122
|
const promiseStatics = ["all", "allSettled", "race", "any", "resolve", "reject"];
|
|
118
|
-
const invokePromiseMethod = (
|
|
123
|
+
const invokePromiseMethod = (ctx, name, args) => {
|
|
119
124
|
if (name === "resolve") {
|
|
120
|
-
return resolvePromise(
|
|
125
|
+
return resolvePromise(ctx, args[0]);
|
|
121
126
|
}
|
|
122
127
|
if (name === "reject") {
|
|
123
|
-
return
|
|
128
|
+
return ctx.pending.create(Effect.fail(new Throw(args[0])));
|
|
124
129
|
}
|
|
125
|
-
return
|
|
126
|
-
const cursor = yield*
|
|
127
|
-
if (cursor === undefined)
|
|
128
|
-
throw
|
|
129
|
-
}
|
|
130
|
+
return ctx.pending.create(Effect.gen(function* () {
|
|
131
|
+
const cursor = yield* ctx.iterate(args[0]);
|
|
132
|
+
if (cursor === undefined)
|
|
133
|
+
throw typeError(`Promise.${name} expects an array or other synchronous iterable.`);
|
|
130
134
|
const items = [];
|
|
131
135
|
while (true) {
|
|
132
136
|
const step = yield* cursor.next;
|
|
133
137
|
if (step.done)
|
|
134
138
|
break;
|
|
135
|
-
const item = yield* resolvePromise(
|
|
136
|
-
|
|
139
|
+
const item = yield* resolvePromise(ctx, step.value);
|
|
140
|
+
ctx.pending.markObserved(item);
|
|
137
141
|
items.push(item);
|
|
138
142
|
}
|
|
139
143
|
if (name === "all") {
|
|
140
|
-
return new
|
|
144
|
+
return new Arr(ctx.builtins.Array, yield* settleAfterTurn(Effect.all(items.map((item) => Effect.flatten(ctx.pending.await(item))), { concurrency: "unbounded" })));
|
|
141
145
|
}
|
|
142
146
|
if (name === "allSettled") {
|
|
143
147
|
const outcomes = [];
|
|
144
148
|
for (const item of items) {
|
|
145
|
-
const exit = yield*
|
|
149
|
+
const exit = yield* ctx.pending.await(item);
|
|
146
150
|
if (Exit.isSuccess(exit)) {
|
|
147
|
-
outcomes.push(record(
|
|
151
|
+
outcomes.push(record(ctx.builtins.Object, { status: "fulfilled", value: exit.value }));
|
|
148
152
|
continue;
|
|
149
153
|
}
|
|
150
154
|
if (Cause.hasInterruptsOnly(exit.cause))
|
|
151
155
|
return yield* Effect.failCause(exit.cause);
|
|
152
|
-
outcomes.push(record(
|
|
156
|
+
outcomes.push(record(ctx.builtins.Object, {
|
|
153
157
|
status: "rejected",
|
|
154
|
-
reason:
|
|
158
|
+
reason: materialize(ctx, Cause.squash(exit.cause)),
|
|
155
159
|
}));
|
|
156
160
|
}
|
|
157
161
|
yield* Effect.yieldNow;
|
|
158
|
-
return new
|
|
162
|
+
return new Arr(ctx.builtins.Array, outcomes);
|
|
159
163
|
}
|
|
160
164
|
if (name === "race") {
|
|
161
165
|
if (items.length === 0) {
|
|
162
|
-
throw
|
|
166
|
+
throw typeError("Promise.race([]) would never settle; provide at least one promise or value.");
|
|
163
167
|
}
|
|
164
|
-
return yield* settleAfterTurn(Effect.flatten(Effect.raceAll(items.map((item) =>
|
|
168
|
+
return yield* settleAfterTurn(Effect.flatten(Effect.raceAll(items.map((item) => ctx.pending.await(item)))));
|
|
165
169
|
}
|
|
166
|
-
const flipped = items.map((item) => Effect.flatMap(
|
|
170
|
+
const flipped = items.map((item) => Effect.flatMap(ctx.pending.await(item), (exit) => {
|
|
167
171
|
if (Exit.isSuccess(exit))
|
|
168
172
|
return Effect.fail(new PromiseAnyFulfilled(exit.value));
|
|
169
173
|
if (Cause.hasInterruptsOnly(exit.cause))
|
|
170
174
|
return Effect.failCause(exit.cause);
|
|
171
|
-
return Effect.succeed(
|
|
175
|
+
return Effect.succeed(materialize(ctx, Cause.squash(exit.cause)));
|
|
172
176
|
}));
|
|
173
|
-
return yield* settleAfterTurn(Effect.all(flipped, { concurrency: "unbounded" }).pipe(Effect.flatMap((reasons) => Effect.fail(new
|
|
177
|
+
return yield* settleAfterTurn(Effect.all(flipped, { concurrency: "unbounded" }).pipe(Effect.flatMap((reasons) => Effect.fail(new Throw(createAggregateErrorValue(ctx, reasons, "All promises were rejected")))), Effect.catch((error) => error instanceof PromiseAnyFulfilled ? Effect.succeed(error.value) : Effect.fail(error))));
|
|
174
178
|
}));
|
|
175
179
|
};
|
|
176
|
-
const instanceMethod = (
|
|
180
|
+
const instanceMethod = (ctx, name, thisValue, args) => {
|
|
177
181
|
const method = `Promise.prototype.${name}`;
|
|
178
|
-
const promise = receiver(
|
|
179
|
-
|
|
182
|
+
const promise = receiver(PromiseObj, thisValue, method);
|
|
183
|
+
ctx.pending.markObserved(promise);
|
|
180
184
|
if (name === "finally") {
|
|
181
|
-
return chainFinally(
|
|
185
|
+
return chainFinally(ctx, promise, reactionHandler(args[0], method), method);
|
|
182
186
|
}
|
|
183
|
-
const onFulfilled = name === "then" ? reactionHandler(args[0], method
|
|
184
|
-
const onRejected = reactionHandler(name === "then" ? args[1] : args[0], method
|
|
185
|
-
return chainReaction(
|
|
187
|
+
const onFulfilled = name === "then" ? reactionHandler(args[0], method) : undefined;
|
|
188
|
+
const onRejected = reactionHandler(name === "then" ? args[1] : args[0], method);
|
|
189
|
+
return chainReaction(ctx, promise, onFulfilled, onRejected, method);
|
|
186
190
|
};
|
|
187
|
-
const constructPromise = (
|
|
188
|
-
if (!(executor instanceof
|
|
189
|
-
throw
|
|
191
|
+
const constructPromise = (ctx, executor) => {
|
|
192
|
+
if (!(executor instanceof Fn)) {
|
|
193
|
+
throw typeError("new Promise(...) expects an executor function (e.g. new Promise((resolve, reject) => { ... })).");
|
|
190
194
|
}
|
|
191
195
|
return Effect.gen(function* () {
|
|
192
196
|
const deferred = Deferred.makeUnsafe();
|
|
193
|
-
const promise = yield*
|
|
194
|
-
const resolve = capability(
|
|
195
|
-
const reject = capability(
|
|
196
|
-
const executed = yield* Effect.exit(
|
|
197
|
+
const promise = yield* ctx.pending.createWithSelf((self) => Effect.flatMap(Deferred.await(deferred), (value) => resolvePromiseValue(ctx, value, self)));
|
|
198
|
+
const resolve = capability(ctx, "resolve", (value) => Deferred.doneUnsafe(deferred, Exit.succeed(value)));
|
|
199
|
+
const reject = capability(ctx, "reject", (value) => Deferred.doneUnsafe(deferred, Exit.fail(new Throw(value))));
|
|
200
|
+
const executed = yield* Effect.exit(ctx.call(executor, undefined, [resolve, reject]));
|
|
197
201
|
if (!Exit.isSuccess(executed)) {
|
|
198
202
|
if (Cause.hasInterruptsOnly(executed.cause))
|
|
199
203
|
return yield* Effect.failCause(executed.cause);
|
|
@@ -210,67 +214,67 @@ class PromiseAnyFulfilled {
|
|
|
210
214
|
this.value = value;
|
|
211
215
|
}
|
|
212
216
|
}
|
|
213
|
-
const reactionHandler = (value, method
|
|
217
|
+
const reactionHandler = (value, method) => {
|
|
214
218
|
if (isSupportedCallback(value))
|
|
215
219
|
return value;
|
|
216
220
|
if (typeofValue(value) === "function") {
|
|
217
|
-
throw
|
|
221
|
+
throw typeError(`${method} cannot use this callable as a handler; wrap it in an arrow function, e.g. (value) => tools.ns.tool(value).`);
|
|
218
222
|
}
|
|
219
223
|
return undefined;
|
|
220
224
|
};
|
|
221
225
|
// Teardown bypasses handlers; settled reactions yield once so handlers never run inline.
|
|
222
|
-
const reactionExit = (
|
|
223
|
-
const exit = yield*
|
|
226
|
+
const reactionExit = (ctx, source) => Effect.gen(function* () {
|
|
227
|
+
const exit = yield* ctx.pending.await(source);
|
|
224
228
|
if (!Exit.isSuccess(exit) && Cause.hasInterruptsOnly(exit.cause))
|
|
225
229
|
return yield* Effect.failCause(exit.cause);
|
|
226
230
|
yield* Effect.yieldNow;
|
|
227
231
|
return exit;
|
|
228
232
|
});
|
|
229
|
-
const chainReaction = (
|
|
230
|
-
return
|
|
231
|
-
const exit = yield* reactionExit(
|
|
233
|
+
const chainReaction = (ctx, source, onFulfilled, onRejected, method) => {
|
|
234
|
+
return ctx.pending.createWithSelf((self) => Effect.gen(function* () {
|
|
235
|
+
const exit = yield* reactionExit(ctx, source);
|
|
232
236
|
const handler = Exit.isSuccess(exit) ? onFulfilled : onRejected;
|
|
233
237
|
if (handler === undefined)
|
|
234
238
|
return yield* exit;
|
|
235
|
-
const input = Exit.isSuccess(exit) ? exit.value :
|
|
236
|
-
const result = yield* applyCollectionCallback(
|
|
237
|
-
return yield* resolvePromiseValue(
|
|
239
|
+
const input = Exit.isSuccess(exit) ? exit.value : materialize(ctx, Cause.squash(exit.cause));
|
|
240
|
+
const result = yield* applyCollectionCallback(ctx, handler, method)([input]);
|
|
241
|
+
return yield* resolvePromiseValue(ctx, result, self);
|
|
238
242
|
}));
|
|
239
243
|
};
|
|
240
|
-
const chainFinally = (
|
|
241
|
-
const exit = yield* reactionExit(
|
|
244
|
+
const chainFinally = (ctx, source, cleanup, method) => ctx.pending.create(Effect.gen(function* () {
|
|
245
|
+
const exit = yield* reactionExit(ctx, source);
|
|
242
246
|
if (cleanup !== undefined) {
|
|
243
|
-
const result = yield* applyCollectionCallback(
|
|
244
|
-
const intermediate = yield*
|
|
245
|
-
yield*
|
|
247
|
+
const result = yield* applyCollectionCallback(ctx, cleanup, method)([]);
|
|
248
|
+
const intermediate = yield* ctx.pending.create(Effect.gen(function* () {
|
|
249
|
+
yield* ctx.await(yield* resolvePromise(ctx, result));
|
|
246
250
|
return yield* exit;
|
|
247
251
|
}));
|
|
248
|
-
return yield*
|
|
252
|
+
return yield* ctx.await(intermediate);
|
|
249
253
|
}
|
|
250
254
|
return yield* exit;
|
|
251
255
|
}));
|
|
252
|
-
export const promiseGlobal = (
|
|
253
|
-
const
|
|
254
|
-
const proto =
|
|
255
|
-
const promise = constructor(
|
|
256
|
+
export const promiseGlobal = (ctx) => {
|
|
257
|
+
const builtins = ctx.builtins;
|
|
258
|
+
const proto = builtins.Promise;
|
|
259
|
+
const promise = constructor(builtins, proto, {
|
|
256
260
|
name: "Promise",
|
|
257
261
|
length: 1,
|
|
258
262
|
call: requiresNew("Promise"),
|
|
259
|
-
construct: (args
|
|
263
|
+
construct: (args) => constructPromise(ctx, args[0]),
|
|
260
264
|
});
|
|
261
265
|
// Combinators are not callbacks: `[p].map(Promise.resolve)` must ask for an arrow function.
|
|
262
266
|
for (const name of promiseStatics) {
|
|
263
|
-
define(promise, name, native(
|
|
267
|
+
define(promise, name, native(builtins, {
|
|
264
268
|
name,
|
|
265
269
|
length: 1,
|
|
266
|
-
call: (_, args
|
|
270
|
+
call: (_, args) => invokePromiseMethod(ctx, name, args),
|
|
267
271
|
callback: false,
|
|
268
272
|
}), hidden);
|
|
269
273
|
}
|
|
270
|
-
methods(
|
|
271
|
-
["then", 2, (thisValue, args
|
|
272
|
-
["catch", 1, (thisValue, args
|
|
273
|
-
["finally", 1, (thisValue, args
|
|
274
|
+
methods(builtins, proto, [
|
|
275
|
+
["then", 2, (thisValue, args) => instanceMethod(ctx, "then", thisValue, args)],
|
|
276
|
+
["catch", 1, (thisValue, args) => instanceMethod(ctx, "catch", thisValue, args)],
|
|
277
|
+
["finally", 1, (thisValue, args) => instanceMethod(ctx, "finally", thisValue, args)],
|
|
274
278
|
]);
|
|
275
279
|
return promise;
|
|
276
280
|
};
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { type AstNode } from "./model.js";
|
|
2
1
|
/** Values that cannot cross the data boundary. */
|
|
3
2
|
export declare const isRuntimeReference: (value: unknown) => boolean;
|
|
4
3
|
export declare const containsRuntimeReference: (value: unknown) => boolean;
|
|
5
4
|
export declare const containsOpaqueReference: (value: unknown) => boolean;
|
|
6
|
-
export declare const rejectCircularInsertion: (container: object, value: unknown, label: string,
|
|
5
|
+
export declare const rejectCircularInsertion: (container: object, value: unknown, label: string, seen?: Set<object>) => void;
|
|
7
6
|
export declare const describeValue: (value: unknown) => string;
|
|
8
7
|
export declare const typeofValue: (value: unknown) => string;
|