@opencode/codemode 2.0.15 → 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 +38 -3
- package/dist/interpreter/interpreter.js +229 -122
- 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 +29 -1
- package/dist/interpreter/objects.js +68 -9
- package/dist/stdlib/array.d.ts +7 -1
- package/dist/stdlib/array.js +93 -54
- package/dist/stdlib/bytes.js +19 -1
- 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/object.js +64 -10
- 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.d.ts +1 -0
- package/dist/stdlib/web.js +63 -1
- package/package.json +1 -1
package/dist/stdlib/string.js
CHANGED
|
@@ -4,7 +4,7 @@ import { checkArrayLength, checkStringLength } from "../interpreter/limits.js";
|
|
|
4
4
|
import { invalidData, IteratorSymbol, rangeError, typeError } from "../interpreter/model.js";
|
|
5
5
|
import { define, get, hidden, Arr, hostIterator, Obj, RegExpObj, record, coerceToInteger, coerceToNumber, coerceToString, } from "../interpreter/objects.js";
|
|
6
6
|
import { containsOpaqueReference, typeofValue } from "../interpreter/references.js";
|
|
7
|
-
import { applyCollectionCallback, isSupportedCallback, toPrimitiveString } from "../interpreter/callback.js";
|
|
7
|
+
import { applyCollectionCallback, isSupportedCallback, toPrimitiveString, withPrimitives, } from "../interpreter/callback.js";
|
|
8
8
|
import { matchToValue, toHostRegex } from "./regexp.js";
|
|
9
9
|
import { coercion } from "./value.js";
|
|
10
10
|
// console is intercepted by the interpreter before reaching here.
|
|
@@ -111,28 +111,50 @@ export const stringGlobal = (ctx) => {
|
|
|
111
111
|
const num = (name, args, index) => coerceToNumber(requireDataArgument(name, index, args[index]));
|
|
112
112
|
const optNum = (name, args, index) => args[index] === undefined ? undefined : num(name, args, index);
|
|
113
113
|
const optStr = (name, args, index) => args[index] === undefined ? undefined : str(name, args, index);
|
|
114
|
-
|
|
114
|
+
// ToPrimitive in spec order: the receiver, then the arguments the method consumes, one hint per position; the
|
|
115
|
+
// rest pass through as they are.
|
|
116
|
+
const simple = (name, length, op, hints = []) => [
|
|
117
|
+
name,
|
|
118
|
+
length,
|
|
119
|
+
(thisValue, args) => {
|
|
120
|
+
if (thisValue === null || thisValue === undefined) {
|
|
121
|
+
throw typeError(`String.prototype.${name} called on null or undefined.`);
|
|
122
|
+
}
|
|
123
|
+
return withPrimitives(ctx, ["string", ...hints], [thisValue, ...args.slice(0, hints.length)], ([value, ...primitives]) => op(coerceToString(value), [...primitives, ...args.slice(hints.length)]));
|
|
124
|
+
},
|
|
125
|
+
];
|
|
126
|
+
// includes, startsWith, and endsWith reject a RegExp before converting their search string and position.
|
|
127
|
+
const searching = (name, op) => simple(name, 1, (value, args) => {
|
|
115
128
|
if (args[0] instanceof RegExpObj) {
|
|
116
129
|
throw typeError(`String.${name} cannot take a regular expression; use regex.test(string) or String.search instead.`);
|
|
117
130
|
}
|
|
118
|
-
|
|
119
|
-
|
|
131
|
+
return withPrimitives(ctx, ["string", "number"], args.slice(0, 2), (primitives) => op(value, str(name, primitives, 0), optNum(name, primitives, 1)));
|
|
132
|
+
});
|
|
133
|
+
// match, matchAll, and search read a RegExp as is and convert anything else to its pattern text.
|
|
134
|
+
const withPattern = (args, op) => args[0] instanceof RegExpObj ? op(args[0]) : withPrimitives(ctx, "string", [args[0]], ([text]) => op(text));
|
|
120
135
|
const replace = (name) => simple(name, 2, (value, args) => {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
+
const pattern = args[0];
|
|
137
|
+
const replacer = args[1];
|
|
138
|
+
// A RegExp pattern is used as is; a plain one converts to its search string, then a non-callable replacement.
|
|
139
|
+
return withPrimitives(ctx, "string", [pattern instanceof RegExpObj ? undefined : pattern, isSupportedCallback(replacer) ? undefined : replacer], ([search, replacement]) => {
|
|
140
|
+
if (isSupportedCallback(replacer)) {
|
|
141
|
+
return replaceWithCallback(ctx, value, name, [pattern instanceof RegExpObj ? pattern : search, replacer]);
|
|
142
|
+
}
|
|
143
|
+
if (typeofValue(replacer) === "function") {
|
|
144
|
+
throw typeError(`String.${name} cannot use this callable as a replacer; wrap it in an arrow function, e.g. (match) => tools.ns.tool(match).`);
|
|
145
|
+
}
|
|
146
|
+
const primitives = [search, replacement];
|
|
147
|
+
if (pattern instanceof RegExpObj) {
|
|
148
|
+
const regex = pattern.regex;
|
|
149
|
+
const text = str(name, primitives, 1);
|
|
150
|
+
if (name === "replaceAll")
|
|
151
|
+
replaceAllNeedsGlobal(regex);
|
|
152
|
+
return name === "replace" ? value.replace(regex, text) : value.replaceAll(regex, text);
|
|
153
|
+
}
|
|
154
|
+
if (name === "replace")
|
|
155
|
+
return value.replace(str(name, primitives, 0), str(name, primitives, 1));
|
|
156
|
+
return value.replaceAll(str(name, primitives, 0), str(name, primitives, 1));
|
|
157
|
+
});
|
|
136
158
|
});
|
|
137
159
|
methods(builtins, builtins.String, [
|
|
138
160
|
simple("toString", 0, (value) => value),
|
|
@@ -147,7 +169,7 @@ export const stringGlobal = (ctx) => {
|
|
|
147
169
|
simple("trimEnd", 0, (value) => value.trimEnd()),
|
|
148
170
|
simple("trimRight", 0, (value) => value.trimEnd()),
|
|
149
171
|
// Locale/options are deliberately unsupported; comparison uses the host default locale.
|
|
150
|
-
simple("localeCompare", 1, (value, args) => value.localeCompare(str("localeCompare", args, 0))),
|
|
172
|
+
simple("localeCompare", 1, (value, args) => value.localeCompare(str("localeCompare", args, 0)), ["string"]),
|
|
151
173
|
simple("normalize", 0, (value, args) => {
|
|
152
174
|
const form = optStr("normalize", args, 0);
|
|
153
175
|
try {
|
|
@@ -156,61 +178,62 @@ export const stringGlobal = (ctx) => {
|
|
|
156
178
|
catch {
|
|
157
179
|
throw rangeError(`String.normalize expects the form "NFC", "NFD", "NFKC", or "NFKD" (got ${JSON.stringify(form)}).`);
|
|
158
180
|
}
|
|
159
|
-
}),
|
|
181
|
+
}, ["string"]),
|
|
160
182
|
simple("split", 2, (value, args) => {
|
|
161
|
-
const
|
|
162
|
-
//
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
return value.includes(str("includes", args, 0), optNum("includes", args, 1));
|
|
183
|
+
const separator = args[0];
|
|
184
|
+
// A RegExp separator is used as is; the limit converts before a plain separator does, as in the spec.
|
|
185
|
+
return withPrimitives(ctx, ["number", "string"], [args[1], separator instanceof RegExpObj ? undefined : separator], ([limit, pattern]) => {
|
|
186
|
+
const wrap = (parts) => new Arr(builtins.Array, parts);
|
|
187
|
+
// Native: an undefined separator returns the whole string, not a split on "undefined",
|
|
188
|
+
// unless the limit truncates to zero.
|
|
189
|
+
const requestedLimit = args[1] === undefined ? undefined : num("split", [pattern, limit], 1);
|
|
190
|
+
if (separator === undefined) {
|
|
191
|
+
return wrap(requestedLimit !== undefined && requestedLimit >>> 0 === 0 ? [] : [value]);
|
|
192
|
+
}
|
|
193
|
+
const parts = separator instanceof RegExpObj
|
|
194
|
+
? value.split(separator.regex, requestedLimit)
|
|
195
|
+
: value.split(str("split", [pattern], 0), requestedLimit === undefined ? undefined : requestedLimit >>> 0);
|
|
196
|
+
checkArrayLength(parts.length);
|
|
197
|
+
return wrap(parts);
|
|
198
|
+
});
|
|
178
199
|
}),
|
|
179
|
-
simple("
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
200
|
+
simple("slice", 2, (value, args) => value.slice(optNum("slice", args, 0), optNum("slice", args, 1)), [
|
|
201
|
+
"number",
|
|
202
|
+
"number",
|
|
203
|
+
]),
|
|
204
|
+
searching("includes", (value, search, position) => value.includes(search, position)),
|
|
205
|
+
searching("startsWith", (value, search, position) => value.startsWith(search, position)),
|
|
206
|
+
searching("endsWith", (value, search, position) => value.endsWith(search, position)),
|
|
207
|
+
simple("indexOf", 1, (value, args) => value.indexOf(str("indexOf", args, 0), optNum("indexOf", args, 1)), [
|
|
208
|
+
"string",
|
|
209
|
+
"number",
|
|
210
|
+
]),
|
|
211
|
+
simple("lastIndexOf", 1, (value, args) => value.lastIndexOf(str("lastIndexOf", args, 0), optNum("lastIndexOf", args, 1)), ["string", "number"]),
|
|
189
212
|
replace("replace"),
|
|
190
213
|
replace("replaceAll"),
|
|
191
|
-
simple("match", 1, (value, args) => {
|
|
192
|
-
const
|
|
193
|
-
const matched = value.match(
|
|
214
|
+
simple("match", 1, (value, args) => withPattern(args, (arg) => {
|
|
215
|
+
const regex = toHostRegex(arg, "match");
|
|
216
|
+
const matched = value.match(regex);
|
|
194
217
|
if (matched === null)
|
|
195
218
|
return null;
|
|
196
219
|
// Preserve the own `index` and `groups` properties on non-global matches.
|
|
197
|
-
if (
|
|
220
|
+
if (regex.global)
|
|
198
221
|
return new Arr(builtins.Array, [...matched]);
|
|
199
222
|
return matchToValue(builtins, matched);
|
|
200
|
-
}),
|
|
201
|
-
simple("matchAll", 1, (value, args) => {
|
|
202
|
-
const
|
|
203
|
-
if (!
|
|
204
|
-
throw typeError(`String.matchAll requires a regular expression with the global (g) flag: write /${
|
|
223
|
+
})),
|
|
224
|
+
simple("matchAll", 1, (value, args) => withPattern(args, (arg) => {
|
|
225
|
+
const regex = toHostRegex(arg, "matchAll", "g");
|
|
226
|
+
if (!regex.global) {
|
|
227
|
+
throw typeError(`String.matchAll requires a regular expression with the global (g) flag: write /${regex.source}/${regex.flags}g, or use String.match for a single match.`);
|
|
205
228
|
}
|
|
206
229
|
const matches = [];
|
|
207
|
-
for (const match of value.matchAll(
|
|
230
|
+
for (const match of value.matchAll(regex)) {
|
|
208
231
|
checkArrayLength(matches.length + 1);
|
|
209
232
|
matches.push(matchToValue(builtins, match));
|
|
210
233
|
}
|
|
211
234
|
return new Arr(builtins.Array, matches);
|
|
212
|
-
}),
|
|
213
|
-
simple("search", 1, (value, args) => value.search(toHostRegex(
|
|
235
|
+
})),
|
|
236
|
+
simple("search", 1, (value, args) => withPattern(args, (arg) => value.search(toHostRegex(arg, "search")))),
|
|
214
237
|
simple("repeat", 1, (value, args) => {
|
|
215
238
|
const count = num("repeat", args, 0);
|
|
216
239
|
if (!Number.isFinite(count) || count < 0) {
|
|
@@ -218,30 +241,33 @@ export const stringGlobal = (ctx) => {
|
|
|
218
241
|
}
|
|
219
242
|
checkStringLength(value.length * count);
|
|
220
243
|
return value.repeat(count);
|
|
221
|
-
}),
|
|
244
|
+
}, ["number"]),
|
|
222
245
|
simple("padStart", 1, (value, args) => {
|
|
223
246
|
const length = num("padStart", args, 0);
|
|
224
247
|
checkStringLength(length);
|
|
225
248
|
return value.padStart(length, optStr("padStart", args, 1));
|
|
226
|
-
}),
|
|
249
|
+
}, ["number", "string"]),
|
|
227
250
|
simple("padEnd", 1, (value, args) => {
|
|
228
251
|
const length = num("padEnd", args, 0);
|
|
229
252
|
checkStringLength(length);
|
|
230
253
|
return value.padEnd(length, optStr("padEnd", args, 1));
|
|
231
|
-
}),
|
|
232
|
-
simple("charAt", 1, (value, args) => value.charAt(optNum("charAt", args, 0) ?? 0)),
|
|
233
|
-
simple("at", 1, (value, args) => value.at(optNum("at", args, 0) ?? 0)),
|
|
234
|
-
simple("substring", 2, (value, args) => value.substring(optNum("substring", args, 0) ?? 0, optNum("substring", args, 1))),
|
|
235
|
-
simple("substr", 2, (value, args) => value.substr(optNum("substr", args, 0) ?? 0, optNum("substr", args, 1))
|
|
254
|
+
}, ["number", "string"]),
|
|
255
|
+
simple("charAt", 1, (value, args) => value.charAt(optNum("charAt", args, 0) ?? 0), ["number"]),
|
|
256
|
+
simple("at", 1, (value, args) => value.at(optNum("at", args, 0) ?? 0), ["number"]),
|
|
257
|
+
simple("substring", 2, (value, args) => value.substring(optNum("substring", args, 0) ?? 0, optNum("substring", args, 1)), ["number", "number"]),
|
|
258
|
+
simple("substr", 2, (value, args) => value.substr(optNum("substr", args, 0) ?? 0, optNum("substr", args, 1)), [
|
|
259
|
+
"number",
|
|
260
|
+
"number",
|
|
261
|
+
]),
|
|
236
262
|
simple("isWellFormed", 0, (value) => value.isWellFormed()),
|
|
237
263
|
simple("toWellFormed", 0, (value) => value.toWellFormed()),
|
|
238
|
-
simple("charCodeAt", 1, (value, args) => value.charCodeAt(optNum("charCodeAt", args, 0) ?? 0)),
|
|
239
|
-
simple("codePointAt", 1, (value, args) => value.codePointAt(optNum("codePointAt", args, 0) ?? 0)),
|
|
240
|
-
simple("concat", 1, (value, args) => {
|
|
241
|
-
const joined = value.concat(...
|
|
264
|
+
simple("charCodeAt", 1, (value, args) => value.charCodeAt(optNum("charCodeAt", args, 0) ?? 0), ["number"]),
|
|
265
|
+
simple("codePointAt", 1, (value, args) => value.codePointAt(optNum("codePointAt", args, 0) ?? 0), ["number"]),
|
|
266
|
+
simple("concat", 1, (value, args) => withPrimitives(ctx, "string", args, (parts) => {
|
|
267
|
+
const joined = value.concat(...parts.map((_, index) => str("concat", parts, index)));
|
|
242
268
|
checkStringLength(joined.length);
|
|
243
269
|
return joined;
|
|
244
|
-
}),
|
|
270
|
+
})),
|
|
245
271
|
]);
|
|
246
272
|
define(builtins.String, IteratorSymbol, fn(builtins, "[Symbol.iterator]", 0, (thisValue) => hostIterator(builtins, self(thisValue, "[Symbol.iterator]")[Symbol.iterator]())), hidden);
|
|
247
273
|
return string;
|
package/dist/stdlib/url.js
CHANGED
|
@@ -246,7 +246,7 @@ export const urlSearchParamsGlobal = (ctx) => {
|
|
|
246
246
|
const apply = applyCollectionCallback(ctx, args[0], "URLSearchParams.forEach");
|
|
247
247
|
return Effect.gen(function* () {
|
|
248
248
|
for (const [key, value] of Array.from(target.params.entries()))
|
|
249
|
-
yield* apply([value, key, target]);
|
|
249
|
+
yield* apply([value, key, target], args[1]);
|
|
250
250
|
return undefined;
|
|
251
251
|
});
|
|
252
252
|
},
|
package/dist/stdlib/value.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { type Native } from "../interpreter/objects.js";
|
|
1
|
+
import { type Native, type Value } from "../interpreter/objects.js";
|
|
2
2
|
import type { Interpreter } from "../interpreter/interpreter.js";
|
|
3
3
|
export declare const compoundOperators: Set<string>;
|
|
4
4
|
export type Coercion = "Number" | "String" | "Boolean" | "parseInt" | "parseFloat" | "isFinite" | "isNaN";
|
|
5
|
+
export declare const coerce: <R>(ctx: Interpreter<R>, name: Coercion, args: Array<Value>) => Value | import("effect/Effect").Effect<Value, unknown, R>;
|
|
5
6
|
/** A global coercion function such as `Number` or `parseInt`. */
|
|
6
7
|
export declare const coercion: <R>(ctx: Interpreter<R>, name: Coercion, length?: number) => Native<R>;
|
package/dist/stdlib/value.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { fn } from "../interpreter/native.js";
|
|
2
2
|
import { coerceToNumber, coerceToString } from "../interpreter/objects.js";
|
|
3
|
+
import { withPrimitives } from "../interpreter/callback.js";
|
|
3
4
|
export const compoundOperators = new Set(["+=", "-=", "*=", "/=", "%=", "**=", "&=", "|=", "^=", "<<=", ">>=", ">>>="]);
|
|
4
|
-
const coerce = (ctx, name, args) => {
|
|
5
|
+
export const coerce = (ctx, name, args) => {
|
|
5
6
|
// Native: Number() is 0 and String() is "", unlike their undefined-argument forms; the
|
|
6
7
|
// other coercers match native through the undefined-argument path below.
|
|
7
8
|
if (args.length === 0) {
|
|
@@ -11,20 +12,22 @@ const coerce = (ctx, name, args) => {
|
|
|
11
12
|
return "";
|
|
12
13
|
}
|
|
13
14
|
const raw = args[0];
|
|
14
|
-
if (name === "Number")
|
|
15
|
-
return coerceToNumber(raw);
|
|
16
15
|
if (name === "Boolean")
|
|
17
16
|
return Boolean(raw);
|
|
18
|
-
if (name === "isFinite")
|
|
19
|
-
return Number.isFinite(coerceToNumber(raw));
|
|
20
|
-
if (name === "isNaN")
|
|
21
|
-
return Number.isNaN(coerceToNumber(raw));
|
|
22
17
|
if (name === "parseInt") {
|
|
23
|
-
return parseInt(coerceToString(
|
|
18
|
+
return withPrimitives(ctx, ["string", "number"], [raw, args[1]], ([text, radix]) => parseInt(coerceToString(text), coerceToNumber(radix)));
|
|
24
19
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
return withPrimitives(ctx, name === "String" || name === "parseFloat" ? "string" : "number", [raw], ([value]) => {
|
|
21
|
+
if (name === "Number")
|
|
22
|
+
return coerceToNumber(value);
|
|
23
|
+
if (name === "isFinite")
|
|
24
|
+
return Number.isFinite(coerceToNumber(value));
|
|
25
|
+
if (name === "isNaN")
|
|
26
|
+
return Number.isNaN(coerceToNumber(value));
|
|
27
|
+
if (name === "parseFloat")
|
|
28
|
+
return parseFloat(coerceToString(value));
|
|
29
|
+
return coerceToString(value);
|
|
30
|
+
});
|
|
28
31
|
};
|
|
29
32
|
/** A global coercion function such as `Number` or `parseInt`. */
|
|
30
33
|
export const coercion = (ctx, name, length = 1) => fn(ctx.builtins, name, length, (_, args) => coerce(ctx, name, args));
|
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, WeakMapObj, WeakSetObj, 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,66 @@ 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) || value instanceof WeakMapObj || value instanceof WeakSetObj) {
|
|
71
|
+
throw typeError(`DataCloneError: ${describeValue(value)} could not be cloned.`);
|
|
72
|
+
}
|
|
73
|
+
const copy = remember(value instanceof Arr ? new Arr(builtins.Array, new Array(value.items.length)) : new Obj(builtins.Object));
|
|
74
|
+
for (const [key, item] of entries(value))
|
|
75
|
+
define(copy, key, clone(item));
|
|
76
|
+
return copy;
|
|
77
|
+
};
|
|
78
|
+
return clone(args[0]);
|
|
79
|
+
});
|
|
18
80
|
export const cryptoGlobal = (ctx) => {
|
|
19
81
|
const object = new Obj(ctx.builtins.Object);
|
|
20
82
|
methods(ctx.builtins, object, [
|
package/package.json
CHANGED