@opencode/codemode 2.0.16 → 2.0.17
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 +2 -2
- package/dist/data.js +1 -1
- package/dist/interpreter/callback.d.ts +10 -3
- package/dist/interpreter/callback.js +17 -4
- package/dist/interpreter/errors.js +8 -4
- package/dist/interpreter/globals.d.ts +1 -1
- package/dist/interpreter/globals.js +36 -2
- package/dist/interpreter/interpreter.js +212 -111
- package/dist/interpreter/intrinsics.d.ts +1 -1
- package/dist/interpreter/intrinsics.js +4 -0
- package/dist/interpreter/model.d.ts +1 -1
- package/dist/interpreter/model.js +1 -1
- package/dist/interpreter/objects.d.ts +23 -1
- package/dist/interpreter/objects.js +36 -1
- package/dist/stdlib/array.js +18 -13
- package/dist/stdlib/collections.d.ts +2 -0
- package/dist/stdlib/collections.js +130 -3
- package/dist/stdlib/date.js +10 -3
- package/dist/stdlib/headers.js +1 -1
- package/dist/stdlib/json.js +1 -1
- package/dist/stdlib/math.js +18 -14
- package/dist/stdlib/number.js +23 -34
- package/dist/stdlib/string.js +98 -72
- package/dist/stdlib/url.js +1 -1
- package/dist/stdlib/value.d.ts +2 -1
- package/dist/stdlib/value.js +14 -11
- package/dist/stdlib/web.js +3 -2
- package/package.json +1 -1
|
@@ -84,6 +84,7 @@ export declare abstract class Opaque extends Obj {
|
|
|
84
84
|
inspect(): string;
|
|
85
85
|
}
|
|
86
86
|
export declare abstract class Callable extends Opaque {
|
|
87
|
+
readonly length: number;
|
|
87
88
|
readonly tag = "Function";
|
|
88
89
|
constructor(proto: Obj, name: string, length: number);
|
|
89
90
|
get describe(): string;
|
|
@@ -94,7 +95,17 @@ export declare class Fn extends Callable {
|
|
|
94
95
|
readonly capturedScopes: Array<Map<string, Binding>>;
|
|
95
96
|
readonly async: boolean;
|
|
96
97
|
readonly generator: boolean;
|
|
97
|
-
|
|
98
|
+
/** Arrows have no `this` or `arguments` of their own; they read the enclosing function's. */
|
|
99
|
+
readonly arrow: boolean;
|
|
100
|
+
constructor(proto: Obj, name: string, parameters: ReadonlyArray<Pattern>, body: BlockStatement | Expression, capturedScopes: Array<Map<string, Binding>>, async: boolean, generator: boolean,
|
|
101
|
+
/** Arrows have no `this` or `arguments` of their own; they read the enclosing function's. */
|
|
102
|
+
arrow: boolean);
|
|
103
|
+
}
|
|
104
|
+
/** The strict `arguments` object: an ordinary object with indexed own properties and a hidden `length`. */
|
|
105
|
+
export declare class Arguments extends Obj {
|
|
106
|
+
readonly tag = "Arguments";
|
|
107
|
+
constructor(proto: Obj, args: Array<Value>);
|
|
108
|
+
iterator(): ArrayIterator<Value>;
|
|
98
109
|
}
|
|
99
110
|
export type NativeCall<R> = (thisValue: Value, args: Array<Value>) => Effect.Effect<Value, unknown, R>;
|
|
100
111
|
export type NativeConstruct<R> = (args: Array<Value>, newTarget: Callable) => Effect.Effect<Value, unknown, R>;
|
|
@@ -181,6 +192,17 @@ export declare class SetObj extends Wrapper {
|
|
|
181
192
|
toHost(item: (value: Value) => unknown): Set<unknown>;
|
|
182
193
|
iterator(): SetIterator<Value>;
|
|
183
194
|
}
|
|
195
|
+
/** Keys are program objects, so a host WeakMap gives the same lifetime rule as JavaScript without any bookkeeping. */
|
|
196
|
+
export declare class WeakMapObj extends Wrapper {
|
|
197
|
+
readonly tag = "WeakMap";
|
|
198
|
+
readonly map: WeakMap<Obj, Value>;
|
|
199
|
+
inspect(): string;
|
|
200
|
+
}
|
|
201
|
+
export declare class WeakSetObj extends Wrapper {
|
|
202
|
+
readonly tag = "WeakSet";
|
|
203
|
+
readonly set: WeakSet<Obj>;
|
|
204
|
+
inspect(): string;
|
|
205
|
+
}
|
|
184
206
|
export declare class URLSearchParamsObj extends Wrapper {
|
|
185
207
|
readonly params: URLSearchParams;
|
|
186
208
|
readonly tag = "URLSearchParams";
|
|
@@ -112,9 +112,11 @@ export class Opaque extends Obj {
|
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
export class Callable extends Opaque {
|
|
115
|
+
length;
|
|
115
116
|
tag = "Function";
|
|
116
117
|
constructor(proto, name, length) {
|
|
117
118
|
super(proto);
|
|
119
|
+
this.length = length;
|
|
118
120
|
define(this, "length", length, readonly);
|
|
119
121
|
define(this, "name", name, readonly);
|
|
120
122
|
}
|
|
@@ -128,7 +130,10 @@ export class Fn extends Callable {
|
|
|
128
130
|
capturedScopes;
|
|
129
131
|
async;
|
|
130
132
|
generator;
|
|
131
|
-
|
|
133
|
+
arrow;
|
|
134
|
+
constructor(proto, name, parameters, body, capturedScopes, async, generator,
|
|
135
|
+
/** Arrows have no `this` or `arguments` of their own; they read the enclosing function's. */
|
|
136
|
+
arrow) {
|
|
132
137
|
const optional = parameters.findIndex((p) => p.type === "AssignmentPattern" || p.type === "RestElement");
|
|
133
138
|
super(proto, name, optional === -1 ? parameters.length : optional);
|
|
134
139
|
this.parameters = parameters;
|
|
@@ -136,6 +141,21 @@ export class Fn extends Callable {
|
|
|
136
141
|
this.capturedScopes = capturedScopes;
|
|
137
142
|
this.async = async;
|
|
138
143
|
this.generator = generator;
|
|
144
|
+
this.arrow = arrow;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/** The strict `arguments` object: an ordinary object with indexed own properties and a hidden `length`. */
|
|
148
|
+
export class Arguments extends Obj {
|
|
149
|
+
tag = "Arguments";
|
|
150
|
+
constructor(proto, args) {
|
|
151
|
+
super(proto);
|
|
152
|
+
args.forEach((arg, index) => define(this, String(index), arg));
|
|
153
|
+
define(this, "length", args.length, hidden);
|
|
154
|
+
}
|
|
155
|
+
iterator() {
|
|
156
|
+
return keys(this)
|
|
157
|
+
.map((key) => get(this, key))
|
|
158
|
+
.values();
|
|
139
159
|
}
|
|
140
160
|
}
|
|
141
161
|
export class Native extends Callable {
|
|
@@ -261,6 +281,21 @@ export class SetObj extends Wrapper {
|
|
|
261
281
|
return this.set.values();
|
|
262
282
|
}
|
|
263
283
|
}
|
|
284
|
+
/** Keys are program objects, so a host WeakMap gives the same lifetime rule as JavaScript without any bookkeeping. */
|
|
285
|
+
export class WeakMapObj extends Wrapper {
|
|
286
|
+
tag = "WeakMap";
|
|
287
|
+
map = new WeakMap();
|
|
288
|
+
inspect() {
|
|
289
|
+
return "WeakMap { <items unknown> }";
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
export class WeakSetObj extends Wrapper {
|
|
293
|
+
tag = "WeakSet";
|
|
294
|
+
set = new WeakSet();
|
|
295
|
+
inspect() {
|
|
296
|
+
return "WeakSet { <items unknown> }";
|
|
297
|
+
}
|
|
298
|
+
}
|
|
264
299
|
export class URLSearchParamsObj extends Wrapper {
|
|
265
300
|
params;
|
|
266
301
|
tag = "URLSearchParams";
|
package/dist/stdlib/array.js
CHANGED
|
@@ -4,7 +4,7 @@ import { checkArrayLength, checkStringLength, MAX_ARRAY_LENGTH } from "../interp
|
|
|
4
4
|
import { invalidData, IteratorSymbol, rangeError, typeError } from "../interpreter/model.js";
|
|
5
5
|
import { define, get, hidden, Arr, GeneratorObj, hostIterator, Obj, PromiseObj, coerceToInteger, coerceToNumber, coerceToString, rejectAddition, } from "../interpreter/objects.js";
|
|
6
6
|
import { describeValue, rejectCircularInsertion } from "../interpreter/references.js";
|
|
7
|
-
import { applyCollectionCallback, invoke, preserveConsumerError } from "../interpreter/callback.js";
|
|
7
|
+
import { applyCollectionCallback, invoke, preserveConsumerError, withPrimitives } from "../interpreter/callback.js";
|
|
8
8
|
import { compareText } from "../tool-runtime.js";
|
|
9
9
|
const arrayLikeSource = (source) => {
|
|
10
10
|
// JS would treat a promise as an empty array-like; that would hide a missing `await`.
|
|
@@ -29,7 +29,7 @@ const arrayFrom = (ctx, args) => {
|
|
|
29
29
|
const values = [];
|
|
30
30
|
for (let index = 0; index < arrayLike.length; index += 1) {
|
|
31
31
|
const item = get(arrayLike.source, index);
|
|
32
|
-
values.push(apply === undefined ? item : yield* apply([item, index]));
|
|
32
|
+
values.push(apply === undefined ? item : yield* apply([item, index], args[2]));
|
|
33
33
|
}
|
|
34
34
|
return new Arr(proto, values);
|
|
35
35
|
}
|
|
@@ -39,7 +39,9 @@ const arrayFrom = (ctx, args) => {
|
|
|
39
39
|
const step = yield* cursor.next;
|
|
40
40
|
if (step.done)
|
|
41
41
|
return new Arr(proto, values);
|
|
42
|
-
values.push(apply === undefined
|
|
42
|
+
values.push(apply === undefined
|
|
43
|
+
? step.value
|
|
44
|
+
: yield* preserveConsumerError(cursor.close, apply([step.value, index], args[2])));
|
|
43
45
|
index += 1;
|
|
44
46
|
}
|
|
45
47
|
});
|
|
@@ -123,19 +125,19 @@ export const arrayGlobal = (ctx) => {
|
|
|
123
125
|
"join",
|
|
124
126
|
1,
|
|
125
127
|
(thisValue, args) => {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
128
|
+
// .map would keep holes, which Effect.forEach would then hand to the body as undefined.
|
|
129
|
+
const parts = Array.from(self(thisValue, "join").items, (item) => item ?? "");
|
|
130
|
+
return withPrimitives(ctx, "string", [args[0] === undefined ? "," : args[0], ...parts], ([separator, ...items]) => {
|
|
131
|
+
const joined = items.map(coerceToString).join(coerceToString(separator));
|
|
132
|
+
checkStringLength(joined.length);
|
|
133
|
+
return joined;
|
|
134
|
+
});
|
|
131
135
|
},
|
|
132
136
|
],
|
|
133
137
|
[
|
|
134
138
|
"toString",
|
|
135
139
|
0,
|
|
136
|
-
(thisValue) => self(thisValue, "toString")
|
|
137
|
-
.items.map((item) => coerceToString(item ?? ""))
|
|
138
|
-
.join(","),
|
|
140
|
+
(thisValue) => withPrimitives(ctx, "string", Array.from(self(thisValue, "toString").items, (item) => item ?? ""), (items) => items.map(coerceToString).join(",")),
|
|
139
141
|
],
|
|
140
142
|
[
|
|
141
143
|
"includes",
|
|
@@ -332,7 +334,7 @@ export const arrayGlobal = (ctx) => {
|
|
|
332
334
|
for (let index = 0; index < length; index += 1) {
|
|
333
335
|
if (!(index in target.items))
|
|
334
336
|
continue;
|
|
335
|
-
const mapped = yield* apply([target.items[index], index, target]);
|
|
337
|
+
const mapped = yield* apply([target.items[index], index, target], args[1]);
|
|
336
338
|
if (mapped instanceof Arr)
|
|
337
339
|
values.push(...mapped.items);
|
|
338
340
|
else
|
|
@@ -357,7 +359,10 @@ export const callbackMethods = (ctx, label, self, elements, wrap) => {
|
|
|
357
359
|
length,
|
|
358
360
|
(thisValue, args) => {
|
|
359
361
|
const target = self(thisValue, name);
|
|
360
|
-
|
|
362
|
+
const call = applyCollectionCallback(ctx, args[0], `${label}.${name}`);
|
|
363
|
+
// reduce and reduceRight take an initial value where the others take a thisArg.
|
|
364
|
+
const thisArg = name.startsWith("reduce") ? undefined : args[1];
|
|
365
|
+
return body(elements(target), target, (callbackArgs) => call(callbackArgs, thisArg), args);
|
|
361
366
|
},
|
|
362
367
|
];
|
|
363
368
|
return [
|
|
@@ -3,3 +3,5 @@ import type { Interpreter } from "../interpreter/interpreter.js";
|
|
|
3
3
|
export declare const groupBy: <R>(ctx: Interpreter<R>, namespace: "Map" | "Object") => import("../interpreter/objects.js").Native<R>;
|
|
4
4
|
export declare const mapGlobal: <R>(ctx: Interpreter<R>) => import("../interpreter/objects.js").Native<R>;
|
|
5
5
|
export declare const setGlobal: <R>(ctx: Interpreter<R>) => import("../interpreter/objects.js").Native<R>;
|
|
6
|
+
export declare const weakMapGlobal: <R>(ctx: Interpreter<R>) => import("../interpreter/objects.js").Native<R>;
|
|
7
|
+
export declare const weakSetGlobal: <R>(ctx: Interpreter<R>) => import("../interpreter/objects.js").Native<R>;
|
|
@@ -1,7 +1,7 @@
|
|
|
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, Arr, coerceToString, hostCursor, hostIterator, MapObj, Obj, PromiseObj, SetObj, } from "../interpreter/objects.js";
|
|
4
|
+
import { define, defineAccessor, get, getOwn, hidden, Arr, coerceToString, hostCursor, hostIterator, MapObj, Obj, PromiseObj, SetObj, WeakMapObj, WeakSetObj, } from "../interpreter/objects.js";
|
|
5
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) => {
|
|
@@ -167,7 +167,7 @@ export const mapGlobal = (ctx) => {
|
|
|
167
167
|
const apply = applyCollectionCallback(ctx, args[0], "Map.forEach");
|
|
168
168
|
return Effect.gen(function* () {
|
|
169
169
|
for (const [key, item] of target.map.entries())
|
|
170
|
-
yield* apply([item, key, target]);
|
|
170
|
+
yield* apply([item, key, target], args[1]);
|
|
171
171
|
return undefined;
|
|
172
172
|
});
|
|
173
173
|
},
|
|
@@ -357,7 +357,7 @@ export const setGlobal = (ctx) => {
|
|
|
357
357
|
const apply = applyCollectionCallback(ctx, args[0], "Set.forEach");
|
|
358
358
|
return Effect.gen(function* () {
|
|
359
359
|
for (const item of target.set.values())
|
|
360
|
-
yield* apply([item, item, target]);
|
|
360
|
+
yield* apply([item, item, target], args[1]);
|
|
361
361
|
return undefined;
|
|
362
362
|
});
|
|
363
363
|
},
|
|
@@ -373,3 +373,130 @@ export const setGlobal = (ctx) => {
|
|
|
373
373
|
define(proto, IteratorSymbol, get(proto, "values"), hidden);
|
|
374
374
|
return set;
|
|
375
375
|
};
|
|
376
|
+
// CanBeHeldWeakly: only program objects; tool references are rebuilt on every access, so they could never be found again.
|
|
377
|
+
const weakKey = (value, label) => {
|
|
378
|
+
if (value instanceof Obj)
|
|
379
|
+
return value;
|
|
380
|
+
throw typeError(`Invalid value used ${label}: ${describeValue(value)} cannot be held weakly.`);
|
|
381
|
+
};
|
|
382
|
+
export const weakMapGlobal = (ctx) => {
|
|
383
|
+
const builtins = ctx.builtins;
|
|
384
|
+
const proto = builtins.WeakMap;
|
|
385
|
+
const weakMap = constructor(builtins, proto, {
|
|
386
|
+
name: "WeakMap",
|
|
387
|
+
call: requiresNew("WeakMap"),
|
|
388
|
+
construct: (args, newTarget) => {
|
|
389
|
+
const target = new WeakMapObj(prototypeFrom(newTarget, proto));
|
|
390
|
+
if (args[0] === undefined || args[0] === null)
|
|
391
|
+
return Effect.succeed(target);
|
|
392
|
+
return Effect.gen(function* () {
|
|
393
|
+
const cursor = yield* ctx.iterate(args[0]);
|
|
394
|
+
if (cursor === undefined) {
|
|
395
|
+
throw typeError(`new WeakMap(...) expects an iterable of [key, value] pairs, received ${describeValue(args[0])}.`);
|
|
396
|
+
}
|
|
397
|
+
while (true) {
|
|
398
|
+
const step = yield* cursor.next;
|
|
399
|
+
if (step.done)
|
|
400
|
+
return target;
|
|
401
|
+
yield* preserveConsumerError(cursor.close, Effect.sync(() => {
|
|
402
|
+
if (!(step.value instanceof Obj)) {
|
|
403
|
+
throw typeError("new WeakMap(...) expects [key, value] pairs as entry objects.");
|
|
404
|
+
}
|
|
405
|
+
target.map.set(weakKey(getOwn(step.value, 0), "as weak map key"), getOwn(step.value, 1));
|
|
406
|
+
}));
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
},
|
|
410
|
+
});
|
|
411
|
+
const self = (thisValue, name) => receiver(WeakMapObj, thisValue, `WeakMap.prototype.${name}`).map;
|
|
412
|
+
// Lookups pass any key through: the host collection answers false for a non-object, as the spec requires.
|
|
413
|
+
const key = (value) => weakKey(value, "as weak map key");
|
|
414
|
+
methods(builtins, proto, [
|
|
415
|
+
[
|
|
416
|
+
"get",
|
|
417
|
+
1,
|
|
418
|
+
(thisValue, args) => {
|
|
419
|
+
const target = self(thisValue, "get");
|
|
420
|
+
return args[0] instanceof Obj ? target.get(args[0]) : undefined;
|
|
421
|
+
},
|
|
422
|
+
],
|
|
423
|
+
["has", 1, (thisValue, args) => self(thisValue, "has").has(args[0])],
|
|
424
|
+
["delete", 1, (thisValue, args) => self(thisValue, "delete").delete(args[0])],
|
|
425
|
+
[
|
|
426
|
+
"set",
|
|
427
|
+
2,
|
|
428
|
+
(thisValue, args) => {
|
|
429
|
+
self(thisValue, "set").set(key(args[0]), args[1]);
|
|
430
|
+
return thisValue;
|
|
431
|
+
},
|
|
432
|
+
],
|
|
433
|
+
[
|
|
434
|
+
"getOrInsert",
|
|
435
|
+
2,
|
|
436
|
+
(thisValue, args) => {
|
|
437
|
+
const target = self(thisValue, "getOrInsert");
|
|
438
|
+
const k = key(args[0]);
|
|
439
|
+
if (!target.has(k))
|
|
440
|
+
target.set(k, args[1]);
|
|
441
|
+
return target.get(k);
|
|
442
|
+
},
|
|
443
|
+
],
|
|
444
|
+
[
|
|
445
|
+
"getOrInsertComputed",
|
|
446
|
+
2,
|
|
447
|
+
(thisValue, args) => {
|
|
448
|
+
const target = self(thisValue, "getOrInsertComputed");
|
|
449
|
+
const k = key(args[0]);
|
|
450
|
+
const apply = applyCollectionCallback(ctx, args[1], "WeakMap.getOrInsertComputed");
|
|
451
|
+
if (target.has(k))
|
|
452
|
+
return target.get(k);
|
|
453
|
+
return Effect.map(apply([k]), (value) => {
|
|
454
|
+
target.set(k, value);
|
|
455
|
+
return value;
|
|
456
|
+
});
|
|
457
|
+
},
|
|
458
|
+
],
|
|
459
|
+
]);
|
|
460
|
+
return weakMap;
|
|
461
|
+
};
|
|
462
|
+
export const weakSetGlobal = (ctx) => {
|
|
463
|
+
const builtins = ctx.builtins;
|
|
464
|
+
const proto = builtins.WeakSet;
|
|
465
|
+
const weakSet = constructor(builtins, proto, {
|
|
466
|
+
name: "WeakSet",
|
|
467
|
+
call: requiresNew("WeakSet"),
|
|
468
|
+
construct: (args, newTarget) => {
|
|
469
|
+
const target = new WeakSetObj(prototypeFrom(newTarget, proto));
|
|
470
|
+
if (args[0] === undefined || args[0] === null)
|
|
471
|
+
return Effect.succeed(target);
|
|
472
|
+
return Effect.gen(function* () {
|
|
473
|
+
const cursor = yield* ctx.iterate(args[0]);
|
|
474
|
+
if (cursor === undefined) {
|
|
475
|
+
throw typeError(`new WeakSet(...) expects a synchronous iterable, received ${describeValue(args[0])}.`);
|
|
476
|
+
}
|
|
477
|
+
while (true) {
|
|
478
|
+
const step = yield* cursor.next;
|
|
479
|
+
if (step.done)
|
|
480
|
+
return target;
|
|
481
|
+
yield* preserveConsumerError(cursor.close, Effect.sync(() => {
|
|
482
|
+
target.set.add(weakKey(step.value, "in weak set"));
|
|
483
|
+
}));
|
|
484
|
+
}
|
|
485
|
+
});
|
|
486
|
+
},
|
|
487
|
+
});
|
|
488
|
+
const self = (thisValue, name) => receiver(WeakSetObj, thisValue, `WeakSet.prototype.${name}`).set;
|
|
489
|
+
methods(builtins, proto, [
|
|
490
|
+
["has", 1, (thisValue, args) => self(thisValue, "has").has(args[0])],
|
|
491
|
+
["delete", 1, (thisValue, args) => self(thisValue, "delete").delete(args[0])],
|
|
492
|
+
[
|
|
493
|
+
"add",
|
|
494
|
+
1,
|
|
495
|
+
(thisValue, args) => {
|
|
496
|
+
self(thisValue, "add").add(weakKey(args[0], "in weak set"));
|
|
497
|
+
return thisValue;
|
|
498
|
+
},
|
|
499
|
+
],
|
|
500
|
+
]);
|
|
501
|
+
return weakSet;
|
|
502
|
+
};
|
package/dist/stdlib/date.js
CHANGED
|
@@ -14,8 +14,8 @@ const constructDate = (ctx, args, proto) => {
|
|
|
14
14
|
? new DateObj(proto, Date.parse(value))
|
|
15
15
|
: new DateObj(proto, new Date(coerceToNumber(value)).getTime()));
|
|
16
16
|
}
|
|
17
|
-
|
|
18
|
-
return Effect.
|
|
17
|
+
// The spec converts at most seven components, in order, so extra arguments never run program code.
|
|
18
|
+
return Effect.map(Effect.forEach(args.slice(0, 7), (arg) => toPrimitiveNumber(ctx, arg), { concurrency: 1 }), (parts) => new DateObj(proto, new Date(...parts).getTime()));
|
|
19
19
|
};
|
|
20
20
|
const getters = [
|
|
21
21
|
"getFullYear",
|
|
@@ -66,7 +66,11 @@ export const dateGlobal = (ctx) => {
|
|
|
66
66
|
methods(builtins, date, [
|
|
67
67
|
["now", 0, () => Date.now()],
|
|
68
68
|
["parse", 1, (_, args) => Date.parse(coerceToString(args[0]))],
|
|
69
|
-
[
|
|
69
|
+
[
|
|
70
|
+
"UTC",
|
|
71
|
+
7,
|
|
72
|
+
(_, args) => Effect.map(Effect.forEach(args.slice(0, 7), (arg) => toPrimitiveNumber(ctx, arg), { concurrency: 1 }), (parts) => Date.UTC(...parts)),
|
|
73
|
+
],
|
|
70
74
|
]);
|
|
71
75
|
const self = (thisValue, name) => receiver(DateObj, thisValue, `Date.prototype.${name}`);
|
|
72
76
|
const iso = (value) => {
|
|
@@ -107,6 +111,9 @@ export const dateGlobal = (ctx) => {
|
|
|
107
111
|
return Effect.map(Effect.forEach(args.slice(0, length), (arg) => toPrimitiveNumber(ctx, arg), {
|
|
108
112
|
concurrency: 1,
|
|
109
113
|
}), (values) => {
|
|
114
|
+
// Every setter but setTime and setFullYear leaves an invalid Date untouched and answers NaN.
|
|
115
|
+
if (Number.isNaN(hosted.getTime()) && name !== "setTime" && !name.endsWith("FullYear"))
|
|
116
|
+
return NaN;
|
|
110
117
|
target.time = hosted[name](...values);
|
|
111
118
|
return target.time;
|
|
112
119
|
});
|
package/dist/stdlib/headers.js
CHANGED
|
@@ -104,7 +104,7 @@ export const headersGlobal = (ctx) => {
|
|
|
104
104
|
const apply = applyCollectionCallback(ctx, args[0], "Headers.forEach");
|
|
105
105
|
return Effect.gen(function* () {
|
|
106
106
|
for (const [key, value] of Array.from(target.headers.entries()))
|
|
107
|
-
yield* apply([value, key, target]);
|
|
107
|
+
yield* apply([value, key, target], args[1]);
|
|
108
108
|
return undefined;
|
|
109
109
|
});
|
|
110
110
|
},
|
package/dist/stdlib/json.js
CHANGED
package/dist/stdlib/math.js
CHANGED
|
@@ -2,23 +2,27 @@ import { Effect } from "effect";
|
|
|
2
2
|
import { constants, methods } from "../interpreter/native.js";
|
|
3
3
|
import { typeError } from "../interpreter/model.js";
|
|
4
4
|
import { Obj, coerceToNumber } from "../interpreter/objects.js";
|
|
5
|
-
import { preserveConsumerError } from "../interpreter/callback.js";
|
|
6
|
-
// Validate only the arguments a method consumes; like JS, extras are ignored
|
|
7
|
-
// (so built-ins work as callbacks receiving (element, index, array)).
|
|
8
|
-
const unary = (name, op) => [name, 1, (_, args) => op(coerceToNumber(args[0]))];
|
|
9
|
-
const binary = (name, op) => [
|
|
10
|
-
name,
|
|
11
|
-
2,
|
|
12
|
-
(_, args) => op(coerceToNumber(args[0]), coerceToNumber(args[1])),
|
|
13
|
-
];
|
|
14
|
-
const variadic = (name, op) => [
|
|
15
|
-
name,
|
|
16
|
-
2,
|
|
17
|
-
(_, args) => op(...args.map(coerceToNumber)),
|
|
18
|
-
];
|
|
5
|
+
import { preserveConsumerError, withPrimitives } from "../interpreter/callback.js";
|
|
19
6
|
export const mathGlobal = (ctx) => {
|
|
20
7
|
const builtins = ctx.builtins;
|
|
21
8
|
const math = new Obj(builtins.Object);
|
|
9
|
+
// Convert only the arguments a method consumes; like JS, extras are ignored
|
|
10
|
+
// (so built-ins work as callbacks receiving (element, index, array)).
|
|
11
|
+
const unary = (name, op) => [
|
|
12
|
+
name,
|
|
13
|
+
1,
|
|
14
|
+
(_, args) => withPrimitives(ctx, "number", [args[0]], ([a]) => op(coerceToNumber(a))),
|
|
15
|
+
];
|
|
16
|
+
const binary = (name, op) => [
|
|
17
|
+
name,
|
|
18
|
+
2,
|
|
19
|
+
(_, args) => withPrimitives(ctx, "number", [args[0], args[1]], ([a, b]) => op(coerceToNumber(a), coerceToNumber(b))),
|
|
20
|
+
];
|
|
21
|
+
const variadic = (name, op) => [
|
|
22
|
+
name,
|
|
23
|
+
2,
|
|
24
|
+
(_, args) => withPrimitives(ctx, "number", args, (values) => op(...values.map(coerceToNumber))),
|
|
25
|
+
];
|
|
22
26
|
constants(math, {
|
|
23
27
|
PI: Math.PI,
|
|
24
28
|
E: Math.E,
|
package/dist/stdlib/number.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { constructor, constants, methods } from "../interpreter/native.js";
|
|
2
|
-
import { coerceToNumber
|
|
2
|
+
import { coerceToNumber } from "../interpreter/objects.js";
|
|
3
3
|
import { rangeError, typeError } from "../interpreter/model.js";
|
|
4
|
-
import {
|
|
4
|
+
import { withPrimitives } from "../interpreter/callback.js";
|
|
5
|
+
import { coerce, coercion } from "./value.js";
|
|
5
6
|
export const numberGlobal = (ctx) => {
|
|
6
7
|
const builtins = ctx.builtins;
|
|
7
8
|
const number = constructor(builtins, builtins.Number, {
|
|
@@ -24,46 +25,34 @@ export const numberGlobal = (ctx) => {
|
|
|
24
25
|
["isFinite", 1, (_, args) => Number.isFinite(args[0])],
|
|
25
26
|
["isNaN", 1, (_, args) => Number.isNaN(args[0])],
|
|
26
27
|
["isSafeInteger", 1, (_, args) => Number.isSafeInteger(args[0])],
|
|
27
|
-
[
|
|
28
|
-
|
|
29
|
-
2,
|
|
30
|
-
(_, args) => {
|
|
31
|
-
return parseInt(coerceToString(args[0]), coerceToNumber(args[1]));
|
|
32
|
-
},
|
|
33
|
-
],
|
|
34
|
-
["parseFloat", 1, (_, args) => parseFloat(coerceToString(args[0]))],
|
|
28
|
+
["parseInt", 2, (_, args) => coerce(ctx, "parseInt", args)],
|
|
29
|
+
["parseFloat", 1, (_, args) => coerce(ctx, "parseFloat", args)],
|
|
35
30
|
]);
|
|
36
31
|
const self = (thisValue, name) => {
|
|
37
32
|
if (typeof thisValue === "number")
|
|
38
33
|
return thisValue;
|
|
39
34
|
throw typeError(`Number.prototype.${name} requires that 'this' be a Number.`);
|
|
40
35
|
};
|
|
41
|
-
|
|
36
|
+
// The receiver is checked first, then the one argument converts through ToPrimitive with the number hint.
|
|
37
|
+
const formatting = (name, op) => [
|
|
38
|
+
name,
|
|
39
|
+
1,
|
|
40
|
+
(thisValue, args) => {
|
|
41
|
+
const value = self(thisValue, name);
|
|
42
|
+
return withPrimitives(ctx, "number", [args[0]], ([digits]) => op(value, digits === undefined ? undefined : coerceToNumber(digits)));
|
|
43
|
+
},
|
|
44
|
+
];
|
|
42
45
|
methods(builtins, builtins.Number, [
|
|
43
|
-
|
|
46
|
+
formatting("toFixed", (value, digits) => value.toFixed(digits)),
|
|
44
47
|
["toLocaleString", 0, (thisValue) => self(thisValue, "toLocaleString").toLocaleString("en-US")],
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
},
|
|
54
|
-
],
|
|
55
|
-
[
|
|
56
|
-
"toString",
|
|
57
|
-
1,
|
|
58
|
-
(thisValue, args) => {
|
|
59
|
-
const value = self(thisValue, "toString");
|
|
60
|
-
const radix = optNum(args[0]);
|
|
61
|
-
if (radix !== undefined && (radix < 2 || radix > 36)) {
|
|
62
|
-
throw rangeError("Number.toString radix must be between 2 and 36.");
|
|
63
|
-
}
|
|
64
|
-
return value.toString(radix);
|
|
65
|
-
},
|
|
66
|
-
],
|
|
48
|
+
formatting("toExponential", (value, digits) => value.toExponential(digits)),
|
|
49
|
+
formatting("toPrecision", (value, digits) => (digits === undefined ? value.toString() : value.toPrecision(digits))),
|
|
50
|
+
formatting("toString", (value, radix) => {
|
|
51
|
+
if (radix !== undefined && (radix < 2 || radix > 36)) {
|
|
52
|
+
throw rangeError("Number.toString radix must be between 2 and 36.");
|
|
53
|
+
}
|
|
54
|
+
return value.toString(radix);
|
|
55
|
+
}),
|
|
67
56
|
["valueOf", 0, (thisValue) => self(thisValue, "valueOf")],
|
|
68
57
|
]);
|
|
69
58
|
return number;
|