@opencode/codemode 0.0.0-dev-20097 → 0.0.0-dev-20105
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/interpreter/globals.js +2 -1
- package/dist/interpreter/interpreter.js +28 -22
- package/dist/interpreter/objects.d.ts +6 -0
- package/dist/interpreter/objects.js +32 -8
- package/dist/stdlib/array.js +31 -14
- package/dist/stdlib/object.js +64 -10
- package/dist/stdlib/web.d.ts +1 -0
- package/dist/stdlib/web.js +62 -1
- package/package.json +1 -1
|
@@ -14,7 +14,7 @@ import { uriGlobal, urlGlobal, urlSearchParamsGlobal } from "../stdlib/url.js";
|
|
|
14
14
|
import { headersGlobal } from "../stdlib/headers.js";
|
|
15
15
|
import { iteratorGlobals } from "../stdlib/iterator.js";
|
|
16
16
|
import { coercion } from "../stdlib/value.js";
|
|
17
|
-
import { base64Global, cryptoGlobal } from "../stdlib/web.js";
|
|
17
|
+
import { base64Global, cryptoGlobal, structuredCloneGlobal } from "../stdlib/web.js";
|
|
18
18
|
import { ToolReference } from "../tool-runtime.js";
|
|
19
19
|
import { errorGlobal } from "./errors.js";
|
|
20
20
|
import { errorTypes } from "./intrinsics.js";
|
|
@@ -85,6 +85,7 @@ const table = {
|
|
|
85
85
|
atob: (ctx) => base64Global(ctx, "atob"),
|
|
86
86
|
btoa: (ctx) => base64Global(ctx, "btoa"),
|
|
87
87
|
crypto: (ctx) => cryptoGlobal(ctx),
|
|
88
|
+
structuredClone: (ctx) => structuredCloneGlobal(ctx),
|
|
88
89
|
...Object.fromEntries(errorTypes.map((type) => [type, (ctx) => errorGlobal(type, ctx)])),
|
|
89
90
|
};
|
|
90
91
|
/** Names bound in every program before extensions apply. */
|
|
@@ -9,7 +9,7 @@ import { globals } from "./globals.js";
|
|
|
9
9
|
import { assign, Callable, define, frozen, get, hostCursor, IteratorObj, has, hidden, hasPrototype, keys, Native, parseArrayIndex, Arr, Fn, GeneratorObj, Obj, PromiseObj, record, remove, set, coerceToNumber, coerceToString, } from "./objects.js";
|
|
10
10
|
import { preserveConsumerError } from "./callback.js";
|
|
11
11
|
import { Pending, resolvePromise, resolvePromiseValue } from "./promises.js";
|
|
12
|
-
import {
|
|
12
|
+
import { describeValue, isOpaque, rejectCircularInsertion, typeofValue } from "./references.js";
|
|
13
13
|
import { ScopeStack } from "./scope.js";
|
|
14
14
|
import { constructRegExp } from "../stdlib/regexp.js";
|
|
15
15
|
import { enumerableSource } from "../stdlib/object.js";
|
|
@@ -388,9 +388,6 @@ class Frame {
|
|
|
388
388
|
const self = this;
|
|
389
389
|
return Effect.gen(function* () {
|
|
390
390
|
const discriminant = yield* self.evaluateExpression(node.discriminant);
|
|
391
|
-
if (containsOpaqueReference(discriminant)) {
|
|
392
|
-
throw invalidData("Switch discriminants must be data values.", node);
|
|
393
|
-
}
|
|
394
391
|
self.scopes.push();
|
|
395
392
|
return yield* Effect.gen(function* () {
|
|
396
393
|
const cases = node.cases;
|
|
@@ -405,11 +402,7 @@ class Frame {
|
|
|
405
402
|
defaultIndex = index;
|
|
406
403
|
continue;
|
|
407
404
|
}
|
|
408
|
-
|
|
409
|
-
if (containsOpaqueReference(candidate)) {
|
|
410
|
-
throw invalidData("Switch case values must be data values.", test);
|
|
411
|
-
}
|
|
412
|
-
if (candidate === discriminant) {
|
|
405
|
+
if ((yield* self.evaluateExpression(test)) === discriminant) {
|
|
413
406
|
selected = index;
|
|
414
407
|
break;
|
|
415
408
|
}
|
|
@@ -1077,16 +1070,19 @@ class Frame {
|
|
|
1077
1070
|
return lhs === rhs;
|
|
1078
1071
|
if (operator === "!==")
|
|
1079
1072
|
return lhs !== rhs;
|
|
1080
|
-
if (operator === "
|
|
1073
|
+
if (operator === "==")
|
|
1074
|
+
return this.looselyEqual(lhs, rhs, node);
|
|
1075
|
+
if (operator === "!=")
|
|
1076
|
+
return !this.looselyEqual(lhs, rhs, node);
|
|
1077
|
+
if (operator === "in" && rhs instanceof Obj && !isOpaque(lhs)) {
|
|
1081
1078
|
return has(rhs, lhs !== null && typeof lhs === "object" ? coerceToString(lhs) : lhs);
|
|
1082
1079
|
}
|
|
1083
|
-
if (
|
|
1080
|
+
if (isOpaque(lhs) || isOpaque(rhs)) {
|
|
1084
1081
|
throw invalidData("Binary operators require data values.", node);
|
|
1085
1082
|
}
|
|
1086
|
-
// Addition
|
|
1087
|
-
const hint = operator === "+"
|
|
1083
|
+
// Addition uses the default hint; every other operator asks for a number.
|
|
1084
|
+
const hint = operator === "+" ? "default" : "number";
|
|
1088
1085
|
const coerceOperand = (operand) => (operand instanceof Obj ? operand.toPrimitive(hint) : operand);
|
|
1089
|
-
const bothObjects = lhs !== null && typeof lhs === "object" && rhs !== null && typeof rhs === "object";
|
|
1090
1086
|
const l = coerceOperand(lhs);
|
|
1091
1087
|
const r = coerceOperand(rhs);
|
|
1092
1088
|
switch (operator) {
|
|
@@ -1106,10 +1102,6 @@ class Frame {
|
|
|
1106
1102
|
return l % r;
|
|
1107
1103
|
case "**":
|
|
1108
1104
|
return l ** r;
|
|
1109
|
-
case "==":
|
|
1110
|
-
return bothObjects ? lhs === rhs : l == r;
|
|
1111
|
-
case "!=":
|
|
1112
|
-
return bothObjects ? lhs !== rhs : l != r;
|
|
1113
1105
|
case "<":
|
|
1114
1106
|
return l < r;
|
|
1115
1107
|
case "<=":
|
|
@@ -1139,6 +1131,22 @@ class Frame {
|
|
|
1139
1131
|
throw typeError(`Unsupported binary operator '${operator}'.`, node);
|
|
1140
1132
|
}
|
|
1141
1133
|
}
|
|
1134
|
+
// IsLooselyEqual: objects (including functions and tool references) compare by identity, and only a
|
|
1135
|
+
// data object facing a non-nullish primitive needs to coerce, so an opaque value is rejected only there.
|
|
1136
|
+
looselyEqual(lhs, rhs, node) {
|
|
1137
|
+
const lhsObject = lhs !== null && typeof lhs === "object";
|
|
1138
|
+
const rhsObject = rhs !== null && typeof rhs === "object";
|
|
1139
|
+
if (lhsObject === rhsObject)
|
|
1140
|
+
return lhsObject ? lhs === rhs : lhs == rhs;
|
|
1141
|
+
const object = lhsObject ? lhs : rhs;
|
|
1142
|
+
const primitive = lhsObject ? rhs : lhs;
|
|
1143
|
+
if (primitive === null || primitive === undefined)
|
|
1144
|
+
return false;
|
|
1145
|
+
if (!(object instanceof Obj) || isOpaque(object)) {
|
|
1146
|
+
throw invalidData("Binary operators require data values.", node);
|
|
1147
|
+
}
|
|
1148
|
+
return object.toPrimitive("default") == primitive;
|
|
1149
|
+
}
|
|
1142
1150
|
evaluateLogicalExpression(node) {
|
|
1143
1151
|
const operator = node.operator;
|
|
1144
1152
|
return Effect.flatMap(this.evaluateExpression(node.left), (left) => {
|
|
@@ -1167,7 +1175,7 @@ class Frame {
|
|
|
1167
1175
|
return !value;
|
|
1168
1176
|
if (operator === "void")
|
|
1169
1177
|
return undefined;
|
|
1170
|
-
if (
|
|
1178
|
+
if (isOpaque(value)) {
|
|
1171
1179
|
throw invalidData("Unary operators require data values.", node);
|
|
1172
1180
|
}
|
|
1173
1181
|
const operand = value instanceof Obj ? value.toPrimitive("number") : value;
|
|
@@ -1257,7 +1265,7 @@ class Frame {
|
|
|
1257
1265
|
// CodeMode numeric coercion, not host Number(): null-prototype data objects would make
|
|
1258
1266
|
// the host throw during ToPrimitive, and opaque runtime references must reject clearly.
|
|
1259
1267
|
const operand = (current) => {
|
|
1260
|
-
if (
|
|
1268
|
+
if (isOpaque(current)) {
|
|
1261
1269
|
throw invalidData(`'${operator}' requires a data value.`, argument);
|
|
1262
1270
|
}
|
|
1263
1271
|
return coerceToNumber(current);
|
|
@@ -1841,8 +1849,6 @@ class Frame {
|
|
|
1841
1849
|
})();
|
|
1842
1850
|
if (written)
|
|
1843
1851
|
return;
|
|
1844
|
-
if (target instanceof Arr && key === "length")
|
|
1845
|
-
throw rangeError("Invalid array length", node);
|
|
1846
1852
|
throw typeError(`Cannot assign to read only property '${String(key)}'.`, node);
|
|
1847
1853
|
}
|
|
1848
1854
|
// ToPropertyKey: anything else becomes its string form, so `counts[row.category]` works when the field is null.
|
|
@@ -38,6 +38,8 @@ export declare const frozen: Attributes;
|
|
|
38
38
|
export declare class Obj {
|
|
39
39
|
proto: Obj | null;
|
|
40
40
|
readonly props: Map<string | symbol, Slot>;
|
|
41
|
+
/** [[Extensible]]: cleared by `Object.preventExtensions`, `seal`, and `freeze`. */
|
|
42
|
+
extensible: boolean;
|
|
41
43
|
constructor(proto: Obj | null);
|
|
42
44
|
/** The class name `Object.prototype.toString` reports: `[object Map]`. */
|
|
43
45
|
readonly tag: string;
|
|
@@ -59,6 +61,8 @@ export declare class Obj {
|
|
|
59
61
|
export declare class Arr extends Obj {
|
|
60
62
|
readonly items: Array<Value>;
|
|
61
63
|
readonly tag = "Array";
|
|
64
|
+
/** The attributes every live element shares; `seal` and `freeze` narrow them since elements have no slots. */
|
|
65
|
+
elements: Attributes;
|
|
62
66
|
constructor(proto: Obj, items?: Array<Value>);
|
|
63
67
|
get describe(): string;
|
|
64
68
|
toString(): string;
|
|
@@ -232,6 +236,8 @@ export declare const has: (target: Obj, key: PropertyKey) => boolean;
|
|
|
232
236
|
export declare const hasPrototype: (value: Value, proto: Obj) => boolean;
|
|
233
237
|
/** [[Set]]: an inherited setter or read-only property decides before an own data property is created. */
|
|
234
238
|
export declare const set: (target: Obj, key: PropertyKey, value: Value) => boolean;
|
|
239
|
+
/** Creating a property on a non-extensible object is the one [[Set]] failure with its own message. */
|
|
240
|
+
export declare const rejectAddition: (target: Obj, key: string | symbol | number) => void;
|
|
235
241
|
/** [[DefineOwnProperty]] for a data property, ignoring the chain. */
|
|
236
242
|
export declare const define: (target: Obj, key: PropertyKey, value: Value, attrs?: Attributes) => void;
|
|
237
243
|
export declare const defineAccessor: (target: Obj, key: PropertyKey, get: Getter | undefined, set?: Setter) => void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { ToolReference } from "../tool-runtime.js";
|
|
3
3
|
import { checkArrayLength } from "./limits.js";
|
|
4
|
-
import { AsyncIteratorSymbol, IteratorSymbol, } from "./model.js";
|
|
4
|
+
import { AsyncIteratorSymbol, IteratorSymbol, rangeError, typeError, } from "./model.js";
|
|
5
5
|
/** Ordinary assignment: writable, enumerable, configurable. */
|
|
6
6
|
export const data = { writable: true, enumerable: true, configurable: true };
|
|
7
7
|
/** Built-in methods and `constructor`: writable and configurable but hidden from enumeration. */
|
|
@@ -17,6 +17,8 @@ export const frozen = { writable: false, enumerable: false, configurable: false
|
|
|
17
17
|
export class Obj {
|
|
18
18
|
proto;
|
|
19
19
|
props = new Map();
|
|
20
|
+
/** [[Extensible]]: cleared by `Object.preventExtensions`, `seal`, and `freeze`. */
|
|
21
|
+
extensible = true;
|
|
20
22
|
constructor(proto) {
|
|
21
23
|
this.proto = proto;
|
|
22
24
|
}
|
|
@@ -60,6 +62,8 @@ export class Obj {
|
|
|
60
62
|
export class Arr extends Obj {
|
|
61
63
|
items;
|
|
62
64
|
tag = "Array";
|
|
65
|
+
/** The attributes every live element shares; `seal` and `freeze` narrow them since elements have no slots. */
|
|
66
|
+
elements = data;
|
|
63
67
|
constructor(proto, items = []) {
|
|
64
68
|
super(proto);
|
|
65
69
|
this.items = items;
|
|
@@ -363,10 +367,12 @@ export const own = (target, key) => {
|
|
|
363
367
|
const at = index(target, name);
|
|
364
368
|
if (at !== undefined) {
|
|
365
369
|
const items = elements(target);
|
|
366
|
-
|
|
370
|
+
if (!(at in items))
|
|
371
|
+
return undefined;
|
|
372
|
+
return { value: items[at], ...(target instanceof Arr ? target.elements : data) };
|
|
367
373
|
}
|
|
368
374
|
if (target instanceof Arr && name === "length") {
|
|
369
|
-
return { value: target.items.length, writable:
|
|
375
|
+
return { value: target.items.length, writable: target.elements.writable, enumerable: false, configurable: false };
|
|
370
376
|
}
|
|
371
377
|
}
|
|
372
378
|
return target.props.get(name);
|
|
@@ -403,16 +409,22 @@ export const hasPrototype = (value, proto) => {
|
|
|
403
409
|
const writeElement = (target, name, value) => {
|
|
404
410
|
const at = index(target, name);
|
|
405
411
|
if (at !== undefined) {
|
|
406
|
-
if (target instanceof Bytes)
|
|
412
|
+
if (target instanceof Bytes) {
|
|
407
413
|
target.bytes[at] = typeof value === "number" ? value : Number(value);
|
|
408
|
-
|
|
409
|
-
|
|
414
|
+
return true;
|
|
415
|
+
}
|
|
416
|
+
if (!(at in target.items))
|
|
417
|
+
rejectAddition(target, at);
|
|
418
|
+
target.items[at] = value;
|
|
410
419
|
return true;
|
|
411
420
|
}
|
|
412
421
|
if (!(target instanceof Arr) || name !== "length")
|
|
413
422
|
return undefined;
|
|
414
423
|
const length = typeof value === "number" ? value : Number(value);
|
|
415
424
|
if (!Number.isInteger(length) || length < 0)
|
|
425
|
+
throw rangeError("Invalid array length");
|
|
426
|
+
// Shrinking deletes elements, which a sealed array forbids.
|
|
427
|
+
if (length < target.items.length && !target.elements.configurable)
|
|
416
428
|
return false;
|
|
417
429
|
checkArrayLength(length);
|
|
418
430
|
target.items.length = length;
|
|
@@ -448,9 +460,16 @@ export const set = (target, key, value) => {
|
|
|
448
460
|
if (written !== undefined)
|
|
449
461
|
return written;
|
|
450
462
|
}
|
|
463
|
+
rejectAddition(target, name);
|
|
451
464
|
target.props.set(name, { value, ...data });
|
|
452
465
|
return true;
|
|
453
466
|
};
|
|
467
|
+
/** Creating a property on a non-extensible object is the one [[Set]] failure with its own message. */
|
|
468
|
+
export const rejectAddition = (target, key) => {
|
|
469
|
+
if (target.extensible)
|
|
470
|
+
return;
|
|
471
|
+
throw typeError(`Cannot add property ${String(key)}, object is not extensible.`);
|
|
472
|
+
};
|
|
454
473
|
/** [[DefineOwnProperty]] for a data property, ignoring the chain. */
|
|
455
474
|
export const define = (target, key, value, attrs = data) => {
|
|
456
475
|
const name = canonical(key);
|
|
@@ -465,8 +484,13 @@ export const remove = (target, key) => {
|
|
|
465
484
|
const name = canonical(key);
|
|
466
485
|
if (isIndexed(target)) {
|
|
467
486
|
const at = index(target, name);
|
|
468
|
-
if (at !== undefined)
|
|
469
|
-
|
|
487
|
+
if (at !== undefined) {
|
|
488
|
+
if (target instanceof Bytes)
|
|
489
|
+
return !(at in target.bytes);
|
|
490
|
+
if (at in target.items && !target.elements.configurable)
|
|
491
|
+
return false;
|
|
492
|
+
return delete target.items[at];
|
|
493
|
+
}
|
|
470
494
|
if (target instanceof Arr && name === "length")
|
|
471
495
|
return false;
|
|
472
496
|
}
|
package/dist/stdlib/array.js
CHANGED
|
@@ -2,7 +2,7 @@ import { Effect } from "effect";
|
|
|
2
2
|
import { constructor, methods, prototypeFrom, receiver } from "../interpreter/native.js";
|
|
3
3
|
import { checkArrayLength, checkStringLength, MAX_ARRAY_LENGTH } from "../interpreter/limits.js";
|
|
4
4
|
import { invalidData, IteratorSymbol, rangeError, typeError } from "../interpreter/model.js";
|
|
5
|
-
import { define, get, hidden, Arr, GeneratorObj, hostIterator, Obj, PromiseObj, coerceToInteger, coerceToNumber, coerceToString, } from "../interpreter/objects.js";
|
|
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
7
|
import { applyCollectionCallback, invoke, preserveConsumerError } from "../interpreter/callback.js";
|
|
8
8
|
import { compareText } from "../tool-runtime.js";
|
|
@@ -102,6 +102,21 @@ export const arrayGlobal = (ctx) => {
|
|
|
102
102
|
["from", 1, (_, args) => arrayFrom(ctx, args)],
|
|
103
103
|
]);
|
|
104
104
|
const self = (thisValue, name) => receiver(Arr, thisValue, `Array.prototype.${name}`);
|
|
105
|
+
// A mutating method fails where its first element write, delete, or `length` write would on a frozen, sealed, or
|
|
106
|
+
// non-extensible array. `growth` is given by the methods that always write `length`, even when it is 0; holes a
|
|
107
|
+
// method would fill on a non-extensible array are not checked.
|
|
108
|
+
const mutable = (target, growth) => {
|
|
109
|
+
const length = target.items.length;
|
|
110
|
+
if ((growth ?? 0) > 0)
|
|
111
|
+
rejectAddition(target, length);
|
|
112
|
+
if ((growth ?? 0) < 0 && length > 0 && !target.elements.configurable) {
|
|
113
|
+
throw typeError(`Cannot delete property '${length - 1}'.`);
|
|
114
|
+
}
|
|
115
|
+
if (!target.elements.writable && (length > 0 || growth !== undefined)) {
|
|
116
|
+
throw typeError(`Cannot assign to read only property '${length > 0 ? 0 : "length"}'.`);
|
|
117
|
+
}
|
|
118
|
+
return target;
|
|
119
|
+
};
|
|
105
120
|
const optNumber = (value) => (value === undefined ? undefined : coerceToInteger(value));
|
|
106
121
|
methods(builtins, proto, [
|
|
107
122
|
[
|
|
@@ -169,6 +184,9 @@ export const arrayGlobal = (ctx) => {
|
|
|
169
184
|
0,
|
|
170
185
|
(thisValue) => {
|
|
171
186
|
const target = self(thisValue, "reverse");
|
|
187
|
+
// Fewer than two elements means no writes at all, so a frozen one-element array reverses fine.
|
|
188
|
+
if (target.items.length > 1)
|
|
189
|
+
mutable(target);
|
|
172
190
|
target.items.reverse();
|
|
173
191
|
return target;
|
|
174
192
|
},
|
|
@@ -177,7 +195,7 @@ export const arrayGlobal = (ctx) => {
|
|
|
177
195
|
"sort",
|
|
178
196
|
1,
|
|
179
197
|
(thisValue, args) => {
|
|
180
|
-
const target = self(thisValue, "sort");
|
|
198
|
+
const target = mutable(self(thisValue, "sort"));
|
|
181
199
|
const items = target.items;
|
|
182
200
|
const length = items.length;
|
|
183
201
|
const holeCount = Array.from({ length }, (_, index) => Object.hasOwn(items, index)).filter((o) => !o).length;
|
|
@@ -217,7 +235,7 @@ export const arrayGlobal = (ctx) => {
|
|
|
217
235
|
"push",
|
|
218
236
|
1,
|
|
219
237
|
(thisValue, args) => {
|
|
220
|
-
const target = self(thisValue, "push");
|
|
238
|
+
const target = mutable(self(thisValue, "push"), args.length);
|
|
221
239
|
// Validate all insertions before mutating to avoid partial cyclic updates.
|
|
222
240
|
for (const item of args)
|
|
223
241
|
rejectCircularInsertion(target, item, "Array.push result");
|
|
@@ -228,29 +246,28 @@ export const arrayGlobal = (ctx) => {
|
|
|
228
246
|
"unshift",
|
|
229
247
|
1,
|
|
230
248
|
(thisValue, args) => {
|
|
231
|
-
const target = self(thisValue, "unshift");
|
|
249
|
+
const target = mutable(self(thisValue, "unshift"), args.length);
|
|
232
250
|
for (const item of args)
|
|
233
251
|
rejectCircularInsertion(target, item, "Array.unshift result");
|
|
234
252
|
return target.items.unshift(...args);
|
|
235
253
|
},
|
|
236
254
|
],
|
|
237
|
-
["pop", 0, (thisValue) => self(thisValue, "pop").items.pop()],
|
|
238
|
-
["shift", 0, (thisValue) => self(thisValue, "shift").items.shift()],
|
|
255
|
+
["pop", 0, (thisValue) => mutable(self(thisValue, "pop"), -1).items.pop()],
|
|
256
|
+
["shift", 0, (thisValue) => mutable(self(thisValue, "shift"), -1).items.shift()],
|
|
239
257
|
[
|
|
240
258
|
"splice",
|
|
241
259
|
2,
|
|
242
260
|
(thisValue, args) => {
|
|
243
261
|
const target = self(thisValue, "splice");
|
|
244
|
-
|
|
245
|
-
return wrap(target.items.splice(0, 0));
|
|
262
|
+
const length = target.items.length;
|
|
246
263
|
const start = optNumber(args[0]) ?? 0;
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
const deleteCount = optNumber(args[1]) ?? 0;
|
|
264
|
+
const from = start < 0 ? Math.max(length + start, 0) : Math.min(start, length);
|
|
265
|
+
const deleteCount = args.length === 1 ? length - from : Math.min(Math.max(optNumber(args[1]) ?? 0, 0), length - from);
|
|
250
266
|
const inserted = args.slice(2);
|
|
251
267
|
for (const item of inserted)
|
|
252
268
|
rejectCircularInsertion(target, item, "Array.splice result");
|
|
253
|
-
|
|
269
|
+
mutable(target, inserted.length - deleteCount);
|
|
270
|
+
return wrap(target.items.splice(from, deleteCount, ...inserted));
|
|
254
271
|
},
|
|
255
272
|
],
|
|
256
273
|
[
|
|
@@ -272,7 +289,7 @@ export const arrayGlobal = (ctx) => {
|
|
|
272
289
|
"fill",
|
|
273
290
|
1,
|
|
274
291
|
(thisValue, args) => {
|
|
275
|
-
const target = self(thisValue, "fill");
|
|
292
|
+
const target = mutable(self(thisValue, "fill"));
|
|
276
293
|
rejectCircularInsertion(target, args[0], "Array.fill result");
|
|
277
294
|
target.items.fill(args[0], optNumber(args[1]), optNumber(args[2]));
|
|
278
295
|
return target;
|
|
@@ -282,7 +299,7 @@ export const arrayGlobal = (ctx) => {
|
|
|
282
299
|
"copyWithin",
|
|
283
300
|
2,
|
|
284
301
|
(thisValue, args) => {
|
|
285
|
-
const target = self(thisValue, "copyWithin");
|
|
302
|
+
const target = mutable(self(thisValue, "copyWithin"));
|
|
286
303
|
target.items.copyWithin(optNumber(args[0]) ?? 0, optNumber(args[1]) ?? 0, optNumber(args[2]));
|
|
287
304
|
return target;
|
|
288
305
|
},
|
package/dist/stdlib/object.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { constructor, methods, receiver } from "../interpreter/native.js";
|
|
3
|
-
import { AsyncIteratorSymbol, invalidData, IteratorSymbol,
|
|
4
|
-
import { define, entries, enumerableKeys, getOwn, hasOwn, hasPrototype, hidden, keys, own, Arr, Obj, PromiseObj, set, coerceToString, } from "../interpreter/objects.js";
|
|
3
|
+
import { AsyncIteratorSymbol, invalidData, IteratorSymbol, typeError } from "../interpreter/model.js";
|
|
4
|
+
import { define, entries, enumerableKeys, getOwn, hasOwn, hasPrototype, hidden, keys, own, ownKeys, Arr, Bytes, Obj, PromiseObj, set, coerceToString, } from "../interpreter/objects.js";
|
|
5
|
+
import { primitivePrototype } from "../interpreter/intrinsics.js";
|
|
5
6
|
import { containsOpaqueReference, describeValue, rejectCircularInsertion } from "../interpreter/references.js";
|
|
6
7
|
import { invoke, preserveConsumerError } from "../interpreter/callback.js";
|
|
7
8
|
import { ToolReference } from "../tool-runtime.js";
|
|
@@ -37,8 +38,6 @@ export const objectAssign = (ctx, args) => {
|
|
|
37
38
|
for (const key of enumerableKeys(from)) {
|
|
38
39
|
rejectCircularInsertion(target, getOwn(from, key), "Object.assign result", seen);
|
|
39
40
|
if (!set(target, key, getOwn(from, key))) {
|
|
40
|
-
if (target instanceof Arr && key === "length")
|
|
41
|
-
throw rangeError("Invalid array length");
|
|
42
41
|
throw typeError(`Cannot assign to read only property '${String(key)}'.`);
|
|
43
42
|
}
|
|
44
43
|
}
|
|
@@ -81,6 +80,38 @@ const classTag = (value) => {
|
|
|
81
80
|
return "Object";
|
|
82
81
|
};
|
|
83
82
|
const propertyKey = (value) => value === AsyncIteratorSymbol || value === IteratorSymbol ? value : coerceToString(value);
|
|
83
|
+
// SetIntegrityLevel: primitives pass through. A typed array's bytes cannot carry attributes, so JS throws after
|
|
84
|
+
// already making it non-extensible.
|
|
85
|
+
const restrict = (level, value) => {
|
|
86
|
+
if (!(value instanceof Obj))
|
|
87
|
+
return value;
|
|
88
|
+
value.extensible = false;
|
|
89
|
+
if (level === "preventExtensions")
|
|
90
|
+
return value;
|
|
91
|
+
if (value instanceof Bytes && value.bytes.length > 0) {
|
|
92
|
+
throw typeError(`Cannot ${level} array buffer views with elements.`);
|
|
93
|
+
}
|
|
94
|
+
for (const slot of value.props.values()) {
|
|
95
|
+
slot.configurable = false;
|
|
96
|
+
if (level === "freeze" && "value" in slot)
|
|
97
|
+
slot.writable = false;
|
|
98
|
+
}
|
|
99
|
+
if (value instanceof Arr)
|
|
100
|
+
value.elements = { writable: level === "seal", enumerable: true, configurable: false };
|
|
101
|
+
return value;
|
|
102
|
+
};
|
|
103
|
+
// TestIntegrityLevel: array elements and `length` answer through `own`, so a non-extensible empty array is sealed
|
|
104
|
+
// but not frozen, as in JS.
|
|
105
|
+
const integrity = (value, frozen) => {
|
|
106
|
+
if (!(value instanceof Obj))
|
|
107
|
+
return true;
|
|
108
|
+
if (value.extensible)
|
|
109
|
+
return false;
|
|
110
|
+
return ownKeys(value).every((key) => {
|
|
111
|
+
const slot = own(value, key);
|
|
112
|
+
return slot !== undefined && !slot.configurable && !(frozen && "value" in slot && slot.writable);
|
|
113
|
+
});
|
|
114
|
+
};
|
|
84
115
|
// Object constructs identically with or without new, like JS. Only `keys` copies its result into the
|
|
85
116
|
// program; `values`, `entries`, `assign`, and `fromEntries` hand back the program's own values.
|
|
86
117
|
export const objectGlobal = (ctx) => {
|
|
@@ -118,18 +149,41 @@ export const objectGlobal = (ctx) => {
|
|
|
118
149
|
(_, args) => new Arr(builtins.Array, entries(enumerableSource(ctx, "Object.entries(...)", args[0])).map((entry) => new Arr(builtins.Array, entry))),
|
|
119
150
|
],
|
|
120
151
|
["hasOwn", 2, (_, args) => hasOwn(enumerableSource(ctx, "Object.hasOwn(...)", args[0]), propertyKey(args[1]))],
|
|
152
|
+
["is", 2, (_, args) => Object.is(args[0], args[1])],
|
|
153
|
+
["assign", 2, (_, args) => objectAssign(ctx, args)],
|
|
154
|
+
["fromEntries", 1, (_, args) => objectFromEntries(ctx, args[0])],
|
|
155
|
+
["freeze", 1, (_, args) => restrict("freeze", args[0])],
|
|
156
|
+
["seal", 1, (_, args) => restrict("seal", args[0])],
|
|
157
|
+
["preventExtensions", 1, (_, args) => restrict("preventExtensions", args[0])],
|
|
158
|
+
["isFrozen", 1, (_, args) => integrity(args[0], true)],
|
|
159
|
+
["isSealed", 1, (_, args) => integrity(args[0], false)],
|
|
160
|
+
["isExtensible", 1, (_, args) => args[0] instanceof Obj && args[0].extensible],
|
|
121
161
|
[
|
|
122
|
-
"
|
|
162
|
+
"getPrototypeOf",
|
|
163
|
+
1,
|
|
164
|
+
(_, args) => {
|
|
165
|
+
if (args[0] instanceof Obj)
|
|
166
|
+
return args[0].proto;
|
|
167
|
+
const proto = primitivePrototype(builtins, args[0]);
|
|
168
|
+
if (proto === undefined) {
|
|
169
|
+
throw typeError(`Object.getPrototypeOf cannot convert ${describeValue(args[0])} to an object.`);
|
|
170
|
+
}
|
|
171
|
+
return proto;
|
|
172
|
+
},
|
|
173
|
+
],
|
|
174
|
+
[
|
|
175
|
+
"create",
|
|
123
176
|
2,
|
|
124
177
|
(_, args) => {
|
|
125
|
-
if (
|
|
126
|
-
throw
|
|
178
|
+
if (args[0] !== null && !(args[0] instanceof Obj)) {
|
|
179
|
+
throw typeError("Object prototype may only be an Object or null.");
|
|
180
|
+
}
|
|
181
|
+
if (args[1] !== undefined) {
|
|
182
|
+
throw typeError("Object.create property descriptors are not supported; assign the fields after creating the object.");
|
|
127
183
|
}
|
|
128
|
-
return
|
|
184
|
+
return new Obj(args[0]);
|
|
129
185
|
},
|
|
130
186
|
],
|
|
131
|
-
["assign", 2, (_, args) => objectAssign(ctx, args)],
|
|
132
|
-
["fromEntries", 1, (_, args) => objectFromEntries(ctx, args[0])],
|
|
133
187
|
]);
|
|
134
188
|
define(object, "groupBy", groupBy(ctx, "Object"), hidden);
|
|
135
189
|
methods(builtins, builtins.Object, [
|
package/dist/stdlib/web.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Obj } from "../interpreter/objects.js";
|
|
2
2
|
import type { Interpreter } from "../interpreter/interpreter.js";
|
|
3
3
|
export declare const base64Global: <R>(ctx: Interpreter<R>, name: "atob" | "btoa") => import("../interpreter/objects.js").Native<R>;
|
|
4
|
+
export declare const structuredCloneGlobal: <R>(ctx: Interpreter<R>) => import("../interpreter/objects.js").Native<R>;
|
|
4
5
|
export declare const cryptoGlobal: <R>(ctx: Interpreter<R>) => Obj;
|
package/dist/stdlib/web.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { fn, methods } from "../interpreter/native.js";
|
|
2
2
|
import { typeError } from "../interpreter/model.js";
|
|
3
|
-
import { Bytes, Obj, coerceToString } from "../interpreter/objects.js";
|
|
3
|
+
import { define, entries, get, getOwn, hasOwn, hidden, isRuntimeReference, Arr, Bytes, DateObj, ErrorObj, MapObj, Obj, RegExpObj, SetObj, coerceToString, } from "../interpreter/objects.js";
|
|
4
|
+
import { createErrorValue, isErrorType } from "../interpreter/intrinsics.js";
|
|
4
5
|
import { describeValue } from "../interpreter/references.js";
|
|
6
|
+
import { ToolReference } from "../tool-runtime.js";
|
|
5
7
|
// WebIDL DOMString conversion: a missing argument is a TypeError, anything else stringifies. Invalid input is a
|
|
6
8
|
// TypeError as well; browsers throw a DOMException named InvalidCharacterError, which CodeMode does not have.
|
|
7
9
|
export const base64Global = (ctx, name) => fn(ctx.builtins, name, 1, (_, args) => {
|
|
@@ -15,6 +17,65 @@ export const base64Global = (ctx, name) => fn(ctx.builtins, name, 1, (_, args) =
|
|
|
15
17
|
throw typeError("The string contains invalid characters.");
|
|
16
18
|
}
|
|
17
19
|
});
|
|
20
|
+
// HTML structured clone over CodeMode's data kinds. Shared references survive through the memo; prototypes and
|
|
21
|
+
// frozen state do not, as in JS. Without a DOMException, DataCloneError is a TypeError carrying that prefix.
|
|
22
|
+
export const structuredCloneGlobal = (ctx) => fn(ctx.builtins, "structuredClone", 1, (_, args) => {
|
|
23
|
+
if (args.length === 0)
|
|
24
|
+
throw typeError("structuredClone requires 1 argument");
|
|
25
|
+
const builtins = ctx.builtins;
|
|
26
|
+
const memo = new Map();
|
|
27
|
+
const clone = (value) => {
|
|
28
|
+
if (typeof value === "symbol" || value instanceof ToolReference) {
|
|
29
|
+
throw typeError(`DataCloneError: ${describeValue(value)} could not be cloned.`);
|
|
30
|
+
}
|
|
31
|
+
if (!(value instanceof Obj))
|
|
32
|
+
return value;
|
|
33
|
+
const seen = memo.get(value);
|
|
34
|
+
if (seen !== undefined)
|
|
35
|
+
return seen;
|
|
36
|
+
const remember = (copy) => {
|
|
37
|
+
memo.set(value, copy);
|
|
38
|
+
return copy;
|
|
39
|
+
};
|
|
40
|
+
if (value instanceof MapObj) {
|
|
41
|
+
const copy = remember(new MapObj(builtins.Map));
|
|
42
|
+
for (const [key, item] of value.map)
|
|
43
|
+
copy.map.set(clone(key), clone(item));
|
|
44
|
+
return copy;
|
|
45
|
+
}
|
|
46
|
+
if (value instanceof SetObj) {
|
|
47
|
+
const copy = remember(new SetObj(builtins.Set));
|
|
48
|
+
for (const item of value.set)
|
|
49
|
+
copy.set.add(clone(item));
|
|
50
|
+
return copy;
|
|
51
|
+
}
|
|
52
|
+
if (value instanceof DateObj)
|
|
53
|
+
return remember(new DateObj(builtins.Date, value.time));
|
|
54
|
+
if (value instanceof RegExpObj) {
|
|
55
|
+
return remember(new RegExpObj(builtins.RegExp, value.regex.source, value.regex.flags));
|
|
56
|
+
}
|
|
57
|
+
if (value instanceof Bytes)
|
|
58
|
+
return remember(new Bytes(builtins.Uint8Array, new Uint8Array(value.bytes)));
|
|
59
|
+
if (value instanceof ErrorObj) {
|
|
60
|
+
const name = get(value, "name");
|
|
61
|
+
const message = get(value, "message");
|
|
62
|
+
const copy = remember(createErrorValue(builtins[typeof name === "string" && isErrorType(name) ? name : "Error"], message === undefined ? undefined : coerceToString(message)));
|
|
63
|
+
const stack = getOwn(value, "stack");
|
|
64
|
+
if (typeof stack === "string")
|
|
65
|
+
define(copy, "stack", stack, hidden);
|
|
66
|
+
if (hasOwn(value, "cause"))
|
|
67
|
+
define(copy, "cause", clone(getOwn(value, "cause")), hidden);
|
|
68
|
+
return copy;
|
|
69
|
+
}
|
|
70
|
+
if (isRuntimeReference(value))
|
|
71
|
+
throw typeError(`DataCloneError: ${describeValue(value)} could not be cloned.`);
|
|
72
|
+
const copy = remember(value instanceof Arr ? new Arr(builtins.Array, new Array(value.items.length)) : new Obj(builtins.Object));
|
|
73
|
+
for (const [key, item] of entries(value))
|
|
74
|
+
define(copy, key, clone(item));
|
|
75
|
+
return copy;
|
|
76
|
+
};
|
|
77
|
+
return clone(args[0]);
|
|
78
|
+
});
|
|
18
79
|
export const cryptoGlobal = (ctx) => {
|
|
19
80
|
const object = new Obj(ctx.builtins.Object);
|
|
20
81
|
methods(ctx.builtins, object, [
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "@opencode/codemode",
|
|
4
|
-
"version": "0.0.0-dev-
|
|
4
|
+
"version": "0.0.0-dev-20105",
|
|
5
5
|
"description": "Effect-native confined code execution over schema-described tools",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|