poe-code 14.0.74 → 14.0.76

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/index.js +1283 -144
  2. package/dist/index.js.map +4 -4
  3. package/dist/metafile.json +1 -1
  4. package/package.json +1 -1
  5. package/packages/safe-js/dist/chunks/{chunk-YEZOXLY4.js → chunk-UZYQWFMY.js} +1233 -143
  6. package/packages/safe-js/dist/chunks/chunk-UZYQWFMY.js.map +7 -0
  7. package/packages/safe-js/dist/chunks/{chunk-2J6W3YGB.js → chunk-VD2AS4E4.js} +2 -2
  8. package/packages/safe-js/dist/cli.js +2 -2
  9. package/packages/safe-js/dist/core.js +1 -1
  10. package/packages/safe-js/dist/index.js +2 -2
  11. package/packages/safe-js/dist/index.js.map +1 -1
  12. package/packages/safe-js/dist/interp/bigint-operators.d.ts +3 -0
  13. package/packages/safe-js/dist/interp/bigint-operators.js +62 -0
  14. package/packages/safe-js/dist/interp/boxed.d.ts +2 -2
  15. package/packages/safe-js/dist/interp/boxed.js +4 -1
  16. package/packages/safe-js/dist/interp/globals/bigint.d.ts +2 -0
  17. package/packages/safe-js/dist/interp/globals/bigint.js +85 -0
  18. package/packages/safe-js/dist/interp/globals/console-json.js +57 -24
  19. package/packages/safe-js/dist/interp/globals/object-array.js +1 -1
  20. package/packages/safe-js/dist/interp/globals/regex.js +108 -2
  21. package/packages/safe-js/dist/interp/globals.d.ts +1 -0
  22. package/packages/safe-js/dist/interp/globals.js +2 -0
  23. package/packages/safe-js/dist/interp/host-bridge.js +2 -0
  24. package/packages/safe-js/dist/interp/interpreter.js +59 -12
  25. package/packages/safe-js/dist/interp/iteration.js +5 -2
  26. package/packages/safe-js/dist/interp/methods/number.js +1 -1
  27. package/packages/safe-js/dist/interp/methods/regex-split.d.ts +3 -0
  28. package/packages/safe-js/dist/interp/methods/regex-split.js +102 -0
  29. package/packages/safe-js/dist/interp/methods/regex.d.ts +1 -1
  30. package/packages/safe-js/dist/interp/methods/regex.js +16 -5
  31. package/packages/safe-js/dist/interp/methods/regexp-iterator.d.ts +5 -1
  32. package/packages/safe-js/dist/interp/methods/regexp-iterator.js +59 -7
  33. package/packages/safe-js/dist/interp/methods/string.js +9 -9
  34. package/packages/safe-js/dist/interp/object-model.d.ts +1 -0
  35. package/packages/safe-js/dist/interp/object-model.js +4 -1
  36. package/packages/safe-js/dist/interp/regex/compile-guard.js +26 -4
  37. package/packages/safe-js/dist/interp/regex/engine.d.ts +4 -0
  38. package/packages/safe-js/dist/interp/regex/engine.js +230 -30
  39. package/packages/safe-js/dist/interp/regex/parse.d.ts +42 -4
  40. package/packages/safe-js/dist/interp/regex/parse.js +429 -25
  41. package/packages/safe-js/dist/interp/regexp-iterator.d.ts +4 -2
  42. package/packages/safe-js/dist/interp/regexp-iterator.js +6 -1
  43. package/packages/safe-js/dist/interp/string-coercion.d.ts +1 -1
  44. package/packages/safe-js/dist/interp/string-coercion.js +8 -3
  45. package/packages/safe-js/dist/interp/values.d.ts +1 -1
  46. package/packages/safe-js/dist/interp/values.js +10 -3
  47. package/packages/safe-js/dist/lint/rules/AS-async-not-needed.js +2 -0
  48. package/packages/safe-js/dist/lint/rules/AS-missing-async.js +2 -0
  49. package/packages/safe-js/dist/lint/rules/known-globals.d.ts +1 -1
  50. package/packages/safe-js/dist/lint/rules/known-globals.js +1 -0
  51. package/packages/safe-js/dist/parse/parser.d.ts +6 -1
  52. package/packages/safe-js/dist/parse/parser.js +8 -0
  53. package/packages/safe-js/dist/parse/tokenizer.js +12 -4
  54. package/packages/safe-js/dist/parse.d.ts +1 -1
  55. package/packages/safe-js/dist/snapshot/bigint.d.ts +1 -0
  56. package/packages/safe-js/dist/snapshot/bigint.js +14 -0
  57. package/packages/safe-js/dist/snapshot/dump-format.js +12 -2
  58. package/packages/safe-js/dist/snapshot/replay-data.d.ts +6 -0
  59. package/packages/safe-js/dist/snapshot/replay-data.js +23 -5
  60. package/packages/safe-js/dist/snapshot/restore.js +10 -2
  61. package/packages/safe-js/dist/snapshot/serialize.d.ts +4 -1
  62. package/packages/safe-js/dist/snapshot/serialize.js +6 -1
  63. package/packages/safe-js/dist/snapshot/validation.js +27 -0
  64. package/packages/safe-js/dist/chunks/chunk-YEZOXLY4.js.map +0 -7
  65. /package/packages/safe-js/dist/chunks/{chunk-2J6W3YGB.js.map → chunk-VD2AS4E4.js.map} +0 -0
@@ -1,12 +1,17 @@
1
- import { createSandboxClosure, createSandboxRegex, isSandboxRegex, reconcileCompiledValues } from "../values.js";
1
+ import { createSandboxClosure, createSandboxRegex, isSandboxClosure, isSandboxRegex, reconcileCompiledValues } from "../values.js";
2
2
  import { CompileScope } from "../regex/compile-guard.js";
3
3
  import { SandboxError } from "../budget.js";
4
- import { sandboxString } from "../string-coercion.js";
4
+ import { sandboxNumber, sandboxString } from "../string-coercion.js";
5
5
  import { getSandboxPropertyDescriptor, installRegexPrototype, materializeFunctionProperties, setSandboxPrototype } from "../object-model.js";
6
6
  import { accessorAdapter, readPropertyDescriptor } from "../accessors.js";
7
7
  import { callRegexMethod, getRegexMember, regexFlagProperties, regexSearch } from "../methods/regex.js";
8
8
  import { regexMatch, regexReplace } from "../methods/string.js";
9
9
  import { invokeBuiltinClosure } from "../builtin-call.js";
10
+ import { restoreSandboxRegExpIterator } from "../regexp-iterator.js";
11
+ import { normalizeLastIndex } from "../regex/engine.js";
12
+ import { retainValues } from "../resources.js";
13
+ import { setSandboxProperty } from "../interpreter.js";
14
+ import { regexSplit } from "../methods/regex-split.js";
10
15
  export function createRegexGlobals(options) {
11
16
  const invoke = (construct) => async (args, context) => {
12
17
  const selected = options.compileOwner ?? context?.compilation?.owner;
@@ -75,7 +80,52 @@ export function createRegexGlobals(options) {
75
80
  }
76
81
  };
77
82
  const constructor = createSandboxClosure({ guest: true, sandbox: true, name: "RegExp", length: 2, call: invoke(false), construct: invoke(true) });
83
+ Object.defineProperty(materializeFunctionProperties(constructor), "escape", {
84
+ value: createSandboxClosure({ guest: true, sandbox: true, name: "escape", length: 1,
85
+ call: (args) => {
86
+ const input = args[0];
87
+ if (typeof input !== "string")
88
+ throw new TypeError("RegExp.escape requires a string.");
89
+ const allocation = {};
90
+ let escaped = "";
91
+ try {
92
+ for (const character of input) {
93
+ options.budget.visitNode();
94
+ const point = character.codePointAt(0);
95
+ let part = character;
96
+ if (escaped.length === 0 && ((point >= 48 && point <= 57) ||
97
+ (point >= 65 && point <= 90) || (point >= 97 && point <= 122))) {
98
+ part = `\\x${point.toString(16)}`;
99
+ }
100
+ else if ("^$\\.*+?()[]{}|/".includes(character)) {
101
+ part = "\\" + character;
102
+ }
103
+ else {
104
+ const control = "\f\n\r\t\v".indexOf(character);
105
+ if (control !== -1)
106
+ part = "\\" + "fnrtv"[control];
107
+ else if (",-=<>#&!%:;@~'`\"".includes(character) || character.trim() === "" ||
108
+ (point >= 0xd800 && point <= 0xdfff)) {
109
+ part = point <= 0xff ? `\\x${point.toString(16).padStart(2, "0")}`
110
+ : `\\u${point.toString(16).padStart(4, "0")}`;
111
+ }
112
+ }
113
+ options.budget.setRetainedDataUsage(allocation, escaped.length + part.length);
114
+ escaped = options.budget.allocateString(escaped + part);
115
+ }
116
+ return escaped;
117
+ }
118
+ finally {
119
+ options.budget.setRetainedDataUsage(allocation, 0);
120
+ }
121
+ }
122
+ }), writable: true, configurable: true
123
+ });
78
124
  const prototype = Object.create(null);
125
+ Object.defineProperty(materializeFunctionProperties(constructor), Symbol.species, {
126
+ get: accessorAdapter(createSandboxClosure({ sandbox: true, name: "get [Symbol.species]", length: 0,
127
+ call: (_args, context) => context?.thisValue }), "get"), configurable: true
128
+ });
79
129
  Object.defineProperty(materializeFunctionProperties(constructor), "prototype", { value: prototype, writable: false });
80
130
  Object.defineProperty(prototype, "constructor", { value: constructor, writable: true, configurable: true });
81
131
  Object.defineProperty(prototype, Symbol.search, {
@@ -93,6 +143,62 @@ export function createRegexGlobals(options) {
93
143
  call: (args, context) => regexReplace(args[0], context?.thisValue, args[1], options.budget, (closure, values) => invokeBuiltinClosure(closure, values, options.budget, context, undefined), context) }),
94
144
  writable: true, configurable: true
95
145
  });
146
+ Object.defineProperty(prototype, Symbol.matchAll, {
147
+ value: createSandboxClosure({ guest: true, sandbox: true, name: "[Symbol.matchAll]", length: 1,
148
+ call: async (args, context) => {
149
+ const target = context?.thisValue;
150
+ if (target === null || typeof target !== "object")
151
+ throw new TypeError("RegExp matchAll requires an object receiver.");
152
+ let input = args[0];
153
+ let string;
154
+ let species;
155
+ let field;
156
+ let flags;
157
+ let matcher;
158
+ const release = retainValues(options.budget, () => [target, input, string, species, field, flags, matcher]);
159
+ const read = (value, key) => {
160
+ if (context?.getProperty !== undefined)
161
+ return context.getProperty(value, key);
162
+ const descriptor = getSandboxPropertyDescriptor(value, key, options.budget);
163
+ return descriptor === undefined ? undefined : readPropertyDescriptor(descriptor, value, context);
164
+ };
165
+ try {
166
+ string = await sandboxString(input, options.budget, context);
167
+ input = undefined;
168
+ field = await read(target, "constructor");
169
+ species = constructor;
170
+ if (field !== undefined) {
171
+ if (field === null || typeof field !== "object")
172
+ throw new TypeError("Invalid RegExp species constructor.");
173
+ species = await read(field, Symbol.species);
174
+ if (species === null || species === undefined)
175
+ species = constructor;
176
+ }
177
+ field = undefined;
178
+ if (!isSandboxClosure(species) || species.construct === undefined)
179
+ throw new TypeError("RegExp species must be a constructor.");
180
+ field = await read(target, "flags");
181
+ flags = await sandboxString(field, options.budget, context);
182
+ field = undefined;
183
+ matcher = await invokeBuiltinClosure(species, [target, flags], options.budget, context, undefined, true);
184
+ field = await read(target, "lastIndex");
185
+ const cursor = normalizeLastIndex(await sandboxNumber(field, options.budget, context));
186
+ field = undefined;
187
+ await setSandboxProperty(matcher, "lastIndex", cursor, options.budget, true, context);
188
+ return restoreSandboxRegExpIterator({ matcher, input: string, exhausted: false,
189
+ global: flags.includes("g"), unicode: flags.includes("u") || flags.includes("v") });
190
+ }
191
+ finally {
192
+ release();
193
+ }
194
+ } }),
195
+ writable: true, configurable: true
196
+ });
197
+ Object.defineProperty(prototype, Symbol.split, {
198
+ value: createSandboxClosure({ guest: true, sandbox: true, name: "[Symbol.split]", length: 2,
199
+ call: (args, context) => regexSplit(context?.thisValue, args[0], args[1], constructor, options.budget, context) }),
200
+ writable: true, configurable: true
201
+ });
96
202
  for (const name of ["exec", "test", "toString"]) {
97
203
  Object.defineProperty(prototype, name, {
98
204
  value: createSandboxClosure({ sandbox: true, name, length: name === "toString" ? 0 : 1,
@@ -28,6 +28,7 @@ export declare function createBuiltinBindings(options: Parameters<typeof createC
28
28
  Float32Array: import("./values.js").SandboxClosure;
29
29
  Date: import("./values.js").SandboxClosure;
30
30
  Symbol: import("./values.js").SandboxClosure;
31
+ BigInt: import("./values.js").SandboxClosure;
31
32
  Map: import("./values.js").SandboxClosure;
32
33
  Set: import("./values.js").SandboxClosure;
33
34
  JSON: import("./values.js").SandboxObject;
@@ -9,6 +9,7 @@ import { createObjectArrayGlobals } from "./globals/object-array.js";
9
9
  import { createPromiseGlobals } from "./promise.js";
10
10
  import { createDateGlobal } from "./globals/date.js";
11
11
  import { createSymbolGlobal } from "./globals/symbol.js";
12
+ import { createBigIntGlobal } from "./globals/bigint.js";
12
13
  export function createBuiltinBindings(options) {
13
14
  return {
14
15
  ...createConsoleJsonGlobals(options),
@@ -16,6 +17,7 @@ export function createBuiltinBindings(options) {
16
17
  Float32Array: createFloat32ArrayGlobal(options.budget),
17
18
  Date: createDateGlobal(options),
18
19
  Symbol: createSymbolGlobal(options.budget),
20
+ BigInt: createBigIntGlobal(options.budget),
19
21
  ...createErrorGlobals(options),
20
22
  ...createMathGlobals({ random: options.random }),
21
23
  ...createObjectArrayGlobals(options),
@@ -561,6 +561,7 @@ function isSandboxLikeValue(value) {
561
561
  value === undefined ||
562
562
  typeof value === "string" ||
563
563
  typeof value === "number" ||
564
+ typeof value === "bigint" ||
564
565
  typeof value === "boolean") {
565
566
  return true;
566
567
  }
@@ -628,6 +629,7 @@ export function copyHostValueToSandbox(value, stackFrames, options, state, path)
628
629
  if (value === null ||
629
630
  value === undefined ||
630
631
  typeof value === "number" ||
632
+ typeof value === "bigint" ||
631
633
  typeof value === "boolean") {
632
634
  return value;
633
635
  }
@@ -1,4 +1,5 @@
1
1
  import { promiseReplayContext } from "./promise-replay.js";
2
+ import { bigIntOperation } from "./bigint-operators.js";
2
3
  import { accessorAdapter, readPropertyDescriptor, writePropertyDescriptor } from "./accessors.js";
3
4
  import { deleteHostObjectMember, getHostObjectKeys, getHostObjectMember, hasHostObjectMember, isGuestHostObject, setHostObjectMember } from "./host-capabilities.js";
4
5
  import { propertyFunctionName, toPropertyKey } from "./property-key.js";
@@ -51,6 +52,17 @@ const dispatchTable = {
51
52
  ArrowFunctionExpression: evaluateArrowFunction,
52
53
  AwaitExpression: evaluateAwait,
53
54
  BinaryExpression: evaluateBinaryExpression,
55
+ BigIntLiteral: async (node, context) => {
56
+ const allocation = {};
57
+ context.budget.visitNode(node.value.length);
58
+ context.budget.setRetainedDataUsage(allocation, node.value.length);
59
+ try {
60
+ return { kind: "normal", hasValue: true, value: BigInt(node.value) };
61
+ }
62
+ finally {
63
+ context.budget.setRetainedDataUsage(allocation, 0);
64
+ }
65
+ },
54
66
  BlockStatement: evaluateBlockStatement,
55
67
  BooleanLiteral: evaluatePrimitiveLiteral,
56
68
  CallExpression: evaluateCallExpression,
@@ -1805,8 +1817,11 @@ async function evaluateIdentifierUpdateExpression(node, context) {
1805
1817
  error: createError("UNBOUND_IDENTIFIER", node.argument, `Identifier '${node.argument.name}' is not defined.`)
1806
1818
  };
1807
1819
  }
1808
- const current = toNumber(await toNumericPrimitive(binding.value, context));
1809
- const next = node.operator === "++" ? current + 1 : current - 1;
1820
+ const primitive = await toNumericPrimitive(binding.value, context);
1821
+ const current = typeof primitive === "bigint" ? primitive : toNumber(primitive);
1822
+ const next = typeof current === "bigint"
1823
+ ? bigIntOperation(node.operator === "++" ? "+" : "-", current, 1n, context.budget)
1824
+ : node.operator === "++" ? current + 1 : current - 1;
1810
1825
  context.scope.assign(node.argument.name, next);
1811
1826
  return {
1812
1827
  kind: "normal",
@@ -1823,8 +1838,11 @@ async function evaluateMemberUpdateExpression(node, context) {
1823
1838
  throw new TypeError("Cannot update properties of null or undefined.");
1824
1839
  }
1825
1840
  const property = await toPropertyKey(member.property, context.budget, createCoercionContext(context));
1826
- const current = toNumber(await toNumericPrimitive(await getPropertyValue(member.object, property, context, member.superReceiver === undefined ? member.object : member.superReceiver.value), context));
1827
- const next = node.operator === "++" ? current + 1 : current - 1;
1841
+ const primitive = await toNumericPrimitive(await getPropertyValue(member.object, property, context, member.superReceiver === undefined ? member.object : member.superReceiver.value), context);
1842
+ const current = typeof primitive === "bigint" ? primitive : toNumber(primitive);
1843
+ const next = typeof current === "bigint"
1844
+ ? bigIntOperation(node.operator === "++" ? "+" : "-", current, 1n, context.budget)
1845
+ : node.operator === "++" ? current + 1 : current - 1;
1828
1846
  if (member.superReceiver === undefined)
1829
1847
  await setSandboxProperty(member.object, property, next, context.budget, true, createCoercionContext(context));
1830
1848
  else
@@ -1858,7 +1876,7 @@ function getPropertyValue(target, property, context, receiver = target) {
1858
1876
  return readPropertyDescriptor(descriptor, receiver, createCoercionContext(context), true);
1859
1877
  if (isSandboxRegExpIterator(target))
1860
1878
  return getRegExpIteratorMember(property, context.budget);
1861
- if (typeof target === "symbol") {
1879
+ if (typeof target === "symbol" || typeof target === "bigint") {
1862
1880
  const prototype = getBoxedPrototype(target, context.budget);
1863
1881
  return prototype === undefined ? undefined : getPropertyValue(prototype, property, context, receiver);
1864
1882
  }
@@ -2041,6 +2059,8 @@ async function evaluateObjectPropertyKey(node, context) {
2041
2059
  return evaluateMemberProperty(node.key, context);
2042
2060
  }
2043
2061
  function getStaticPropertyName(node) {
2062
+ if (node.type === "BigIntLiteral")
2063
+ return BigInt(node.value).toString();
2044
2064
  if (node.type === "Identifier") {
2045
2065
  return node.name;
2046
2066
  }
@@ -2074,7 +2094,7 @@ async function evaluateMemberCallExpression(node, context) {
2074
2094
  return evaluateResolvedCallExpression(node, await getPropertyValue(member.object, member.property, context), context, member.object);
2075
2095
  if (Array.isArray(member.object) && hasExplicitSandboxPrototype(member.object))
2076
2096
  return evaluateResolvedCallExpression(node, await getPropertyValue(member.object, member.property, context), context, member.object);
2077
- if ((typeof member.object === "string" || typeof member.object === "number" || typeof member.object === "boolean" || typeof member.object === "symbol") &&
2097
+ if ((typeof member.object === "string" || typeof member.object === "number" || typeof member.object === "bigint" || typeof member.object === "boolean" || typeof member.object === "symbol") &&
2078
2098
  getBoxedPrototype(member.object, context.budget) !== undefined) {
2079
2099
  if (isDefaultBoxedMethod(member.object, member.property, context.budget)) {
2080
2100
  if (typeof member.object === "string" && isStringMethodName(member.property))
@@ -2259,10 +2279,14 @@ async function applyUnaryOperator(operator, value, context) {
2259
2279
  return undefined;
2260
2280
  case "+":
2261
2281
  return toNumber(await toNumericPrimitive(value, context));
2262
- case "-":
2263
- return -toNumber(await toNumericPrimitive(value, context));
2264
- case "~":
2265
- return ~toNumber(await toNumericPrimitive(value, context));
2282
+ case "-": {
2283
+ const primitive = await toNumericPrimitive(value, context);
2284
+ return typeof primitive === "bigint" ? bigIntOperation("-", 0n, primitive, context.budget) : -toNumber(primitive);
2285
+ }
2286
+ case "~": {
2287
+ const primitive = await toNumericPrimitive(value, context);
2288
+ return typeof primitive === "bigint" ? bigIntOperation("^", primitive, -1n, context.budget) : ~toNumber(primitive);
2289
+ }
2266
2290
  }
2267
2291
  }
2268
2292
  function describeTypeofValue(value) {
@@ -2278,6 +2302,12 @@ function isTruthy(value) {
2278
2302
  return Boolean(value);
2279
2303
  }
2280
2304
  function applyBinaryOperator(node, left, right, context) {
2305
+ if ((typeof left === "bigint" || typeof right === "bigint") &&
2306
+ ["-", "*", "/", "%", "**", "&", "|", "^", "<<", ">>", ">>>"].includes(node.operator)) {
2307
+ if (typeof left !== "bigint" || typeof right !== "bigint")
2308
+ throw new TypeError("Cannot mix BigInt and other numeric types.");
2309
+ return bigIntOperation(node.operator, left, right, context.budget);
2310
+ }
2281
2311
  switch (node.operator) {
2282
2312
  case "+":
2283
2313
  return applyAdditionOperator(left, right, context);
@@ -2410,6 +2440,11 @@ async function applyCompoundAssignmentOperator(operator, left, right, context) {
2410
2440
  if (convertingObject)
2411
2441
  convertedLeft = left;
2412
2442
  right = await toNumericPrimitive(right, context, operator === "+=" ? "default" : "number");
2443
+ if (operator !== "+=" && (typeof left === "bigint" || typeof right === "bigint")) {
2444
+ if (typeof left !== "bigint" || typeof right !== "bigint")
2445
+ throw new TypeError("Cannot mix BigInt and other numeric types.");
2446
+ return bigIntOperation(operator.slice(0, -1), left, right, context.budget);
2447
+ }
2413
2448
  switch (operator) {
2414
2449
  case "+=":
2415
2450
  return applyAdditionOperator(left, right, context);
@@ -2447,6 +2482,11 @@ function applyAdditionOperator(left, right, context) {
2447
2482
  if (typeof leftPrimitive === "string" || typeof rightPrimitive === "string") {
2448
2483
  return context.budget.allocateString(toString(leftPrimitive) + toString(rightPrimitive));
2449
2484
  }
2485
+ if (typeof leftPrimitive === "bigint" || typeof rightPrimitive === "bigint") {
2486
+ if (typeof leftPrimitive !== "bigint" || typeof rightPrimitive !== "bigint")
2487
+ throw new TypeError("Cannot mix BigInt and other numeric types.");
2488
+ return bigIntOperation("+", leftPrimitive, rightPrimitive, context.budget);
2489
+ }
2450
2490
  return toNumber(leftPrimitive) + toNumber(rightPrimitive);
2451
2491
  }
2452
2492
  function compareRelational(left, right, operator) {
@@ -2464,8 +2504,9 @@ function compareRelational(left, right, operator) {
2464
2504
  return leftPrimitive >= rightPrimitive;
2465
2505
  }
2466
2506
  }
2467
- const leftNumber = toNumber(leftPrimitive);
2468
- const rightNumber = toNumber(rightPrimitive);
2507
+ const hasBigInt = typeof leftPrimitive === "bigint" || typeof rightPrimitive === "bigint";
2508
+ const leftNumber = typeof leftPrimitive === "bigint" || (hasBigInt && typeof leftPrimitive === "string") ? leftPrimitive : toNumber(leftPrimitive);
2509
+ const rightNumber = typeof rightPrimitive === "bigint" || (hasBigInt && typeof rightPrimitive === "string") ? rightPrimitive : toNumber(rightPrimitive);
2469
2510
  switch (operator) {
2470
2511
  case "<":
2471
2512
  return leftNumber < rightNumber;
@@ -2478,6 +2519,8 @@ function compareRelational(left, right, operator) {
2478
2519
  }
2479
2520
  }
2480
2521
  function isLooselyEqual(left, right) {
2522
+ if (typeof left === "bigint" || typeof right === "bigint")
2523
+ return left == right;
2481
2524
  const leftType = getCoercionType(left);
2482
2525
  const rightType = getCoercionType(right);
2483
2526
  if (leftType === rightType) {
@@ -2510,6 +2553,8 @@ function isPrimitiveCoercionType(type) {
2510
2553
  return type !== "object";
2511
2554
  }
2512
2555
  function getCoercionType(value) {
2556
+ if (typeof value === "bigint")
2557
+ return "bigint";
2513
2558
  if (typeof value === "symbol")
2514
2559
  return "symbol";
2515
2560
  if (value === null) {
@@ -2544,6 +2589,8 @@ async function toNumericPrimitive(value, context, hint = "number") {
2544
2589
  throw new TypeError("Expected a sandbox value.");
2545
2590
  }
2546
2591
  function toNumber(value) {
2592
+ if (typeof value === "bigint")
2593
+ throw new TypeError("Cannot convert a BigInt value to a number");
2547
2594
  if (typeof value === "symbol")
2548
2595
  throw new TypeError("Cannot convert a Symbol value to a number");
2549
2596
  if (isSandboxDate(value))
@@ -5,7 +5,7 @@ import { boxedValue, isSandboxBox } from "./boxed.js";
5
5
  import { getHostObjectIterator, isGuestHostObject } from "./host-capabilities.js";
6
6
  import { isSandboxCollectionIterator, nextCollectionIterator } from "./collection-iterator.js";
7
7
  import { isSandboxRegExpIterator } from "./regexp-iterator.js";
8
- import { nextRegExpIterator } from "./methods/regexp-iterator.js";
8
+ import { nextObservableRegExpIterator, nextRegExpIterator } from "./methods/regexp-iterator.js";
9
9
  import { Budget, isFatalSandboxError } from "./budget.js";
10
10
  import { sandboxString } from "./string-coercion.js";
11
11
  import { awaitSandboxValue, awaitWithSignal } from "./cancel.js";
@@ -225,8 +225,11 @@ export function getSandboxIterator(value, budget, context) {
225
225
  }
226
226
  if (isSandboxCollectionIterator(value))
227
227
  return { next: () => nextCollectionIterator(value, budget), snapshotIndex: () => 0 };
228
- if (isSandboxRegExpIterator(value))
228
+ if (isSandboxRegExpIterator(value)) {
229
+ if (context !== undefined && budget !== undefined)
230
+ return { asynchronous: true, next: () => nextObservableRegExpIterator(value, budget, context), snapshotIndex: () => 0 };
229
231
  return { next: () => nextRegExpIterator(value, budget), snapshotIndex: () => 0 };
232
+ }
230
233
  if (isGuestHostObject(value))
231
234
  return getHostObjectIterator(value);
232
235
  if (isFloat32Array(value)) {
@@ -30,7 +30,7 @@ export function callNumberMethod(value, methodName, args, budget, context) {
30
30
  if (argument !== null && typeof argument === "object") {
31
31
  return formatObjectArgument(value, methodName, argument, budget, context);
32
32
  }
33
- return formatNumber(value, methodName, argument === undefined ? undefined : Number(argument), budget);
33
+ return formatNumber(value, methodName, argument === undefined ? undefined : +argument, budget);
34
34
  }
35
35
  async function formatObjectArgument(value, methodName, argument, budget, context) {
36
36
  const retainedArgument = {};
@@ -0,0 +1,3 @@
1
+ import { type Budget } from "../budget.js";
2
+ import { type SandboxCallContext, type SandboxClosure, type SandboxValue } from "../values.js";
3
+ export declare function regexSplit(target: SandboxValue, input: SandboxValue, limit: SandboxValue, constructor: SandboxClosure, budget: Budget, context?: SandboxCallContext): Promise<SandboxValue[]>;
@@ -0,0 +1,102 @@
1
+ import { isSandboxClosure } from "../values.js";
2
+ import { getSandboxPropertyDescriptor } from "../object-model.js";
3
+ import { readPropertyDescriptor } from "../accessors.js";
4
+ import { invokeBuiltinClosure } from "../builtin-call.js";
5
+ import { setSandboxProperty } from "../interpreter.js";
6
+ import { sandboxNumber, sandboxString } from "../string-coercion.js";
7
+ import { normalizeLastIndex } from "../regex/engine.js";
8
+ import { retainValues } from "../resources.js";
9
+ import { regexExec } from "./regex.js";
10
+ export async function regexSplit(target, input, limit, constructor, budget, context) {
11
+ if (target === null || typeof target !== "object")
12
+ throw new TypeError("RegExp split requires an object receiver.");
13
+ let string;
14
+ let species;
15
+ let field;
16
+ let flags;
17
+ let matcher;
18
+ let match;
19
+ const result = [];
20
+ const release = retainValues(budget, () => [target, input, limit, string, species, field, flags, matcher, match, result]);
21
+ const read = (value, key) => {
22
+ if (context?.getProperty !== undefined)
23
+ return context.getProperty(value, key);
24
+ const descriptor = getSandboxPropertyDescriptor(value, key, budget);
25
+ return descriptor === undefined ? undefined : readPropertyDescriptor(descriptor, value, context);
26
+ };
27
+ const append = (value) => {
28
+ budget.allocateArrayLength(result.length + 1);
29
+ result.push(value);
30
+ };
31
+ try {
32
+ string = await sandboxString(input, budget, context);
33
+ input = undefined;
34
+ field = await read(target, "constructor");
35
+ species = constructor;
36
+ if (field !== undefined) {
37
+ if (field === null || typeof field !== "object")
38
+ throw new TypeError("Invalid RegExp species constructor.");
39
+ species = await read(field, Symbol.species);
40
+ if (species === null || species === undefined)
41
+ species = constructor;
42
+ }
43
+ field = undefined;
44
+ if (!isSandboxClosure(species) || species.construct === undefined)
45
+ throw new TypeError("RegExp species must be a constructor.");
46
+ field = await read(target, "flags");
47
+ flags = await sandboxString(field, budget, context);
48
+ field = undefined;
49
+ const unicode = flags.includes("u") || flags.includes("v");
50
+ if (!flags.includes("y"))
51
+ flags = budget.allocateString(flags + "y");
52
+ matcher = await invokeBuiltinClosure(species, [target, flags], budget, context, undefined, true);
53
+ const maximum = limit === undefined ? 2 ** 32 - 1 : (await sandboxNumber(limit, budget, context)) >>> 0;
54
+ limit = undefined;
55
+ if (maximum === 0)
56
+ return result;
57
+ if (string.length === 0) {
58
+ match = await regexExec(matcher, string, budget, context);
59
+ if (match === null)
60
+ append(string);
61
+ return result;
62
+ }
63
+ let end = 0;
64
+ let index = 0;
65
+ while (index < string.length) {
66
+ budget.visitNode();
67
+ match = undefined;
68
+ await setSandboxProperty(matcher, "lastIndex", index, budget, true, context);
69
+ match = await regexExec(matcher, string, budget, context);
70
+ if (match !== null) {
71
+ field = await read(matcher, "lastIndex");
72
+ const next = Math.min(normalizeLastIndex(await sandboxNumber(field, budget, context)), string.length);
73
+ field = undefined;
74
+ if (next !== end) {
75
+ append(budget.allocateString(string.slice(end, index)));
76
+ if (result.length === maximum)
77
+ return result;
78
+ end = next;
79
+ field = await read(match, "length");
80
+ const length = normalizeLastIndex(await sandboxNumber(field, budget, context));
81
+ field = undefined;
82
+ for (let capture = 1; capture < length; capture++) {
83
+ budget.visitNode();
84
+ field = await read(match, String(capture));
85
+ append(field);
86
+ field = undefined;
87
+ if (result.length === maximum)
88
+ return result;
89
+ }
90
+ index = end;
91
+ continue;
92
+ }
93
+ }
94
+ index += unicode && (string.codePointAt(index) ?? 0) > 0xffff ? 2 : 1;
95
+ }
96
+ append(budget.allocateString(string.slice(end)));
97
+ return result;
98
+ }
99
+ finally {
100
+ release();
101
+ }
102
+ }
@@ -11,4 +11,4 @@ export declare function callRegexMethod(target: SandboxValue, methodName: RegexM
11
11
  export declare function regexExec(target: SandboxValue, input: string, budget: Budget, context?: SandboxCallContext): Promise<SandboxValue>;
12
12
  export declare function regexToString(target: SandboxValue, budget: Budget, context?: SandboxCallContext): Promise<string>;
13
13
  export declare function executeRegex(target: SandboxRegex, input: string, lastIndex: number): RegexMatch | null;
14
- export declare function toMatchArray(match: RegexMatch | null, input: string): SandboxValue;
14
+ export declare function toMatchArray(match: RegexMatch | null, input: string, budget?: Budget): SandboxValue;
@@ -1,7 +1,7 @@
1
1
  import { createSandboxClosure, getSandboxRegexPattern, getRegexProperties, isSandboxClosure, isSandboxRegex } from "../values.js";
2
2
  import { matchRegex } from "../regex/engine.js";
3
3
  import { invokeBuiltinClosure } from "../builtin-call.js";
4
- import { getSandboxPropertyDescriptor, getSandboxPrototype, hasExplicitSandboxPrototype } from "../object-model.js";
4
+ import { getSandboxPropertyDescriptor, getSandboxPrototype, hasExplicitSandboxPrototype, setSandboxPrototype } from "../object-model.js";
5
5
  import { readPropertyDescriptor } from "../accessors.js";
6
6
  import { retainValues } from "../resources.js";
7
7
  import { sandboxNumber, sandboxString } from "../string-coercion.js";
@@ -160,7 +160,7 @@ export async function callRegexMethod(target, methodName, args, budget, context)
160
160
  cursor = target.lastIndex;
161
161
  const lastIndex = await sandboxNumber(cursor, budget, context);
162
162
  const match = executeRegex(target, input, lastIndex);
163
- return toMatchArray(match, input);
163
+ return toMatchArray(match, input, budget);
164
164
  }
165
165
  finally {
166
166
  budget.setRetainedValues(retained, undefined);
@@ -218,16 +218,27 @@ export async function regexToString(target, budget, context) {
218
218
  export function executeRegex(target, input, lastIndex) {
219
219
  const pattern = getSandboxRegexPattern(target);
220
220
  const match = matchRegex(pattern, input, lastIndex);
221
- if (pattern.flags.global) {
221
+ if (pattern.flags.global || pattern.flags.sticky) {
222
222
  target.lastIndex = match === null ? 0 : match.index + match.text.length;
223
223
  }
224
224
  return match;
225
225
  }
226
- export function toMatchArray(match, input) {
226
+ export function toMatchArray(match, input, budget) {
227
227
  if (match === null) {
228
228
  return null;
229
229
  }
230
+ budget?.allocateArrayLength(match.captures.length + 1);
230
231
  const result = [match.text, ...match.captures];
231
- Object.assign(result, { index: match.index, input, groups: undefined });
232
+ if (match.groups !== undefined)
233
+ setSandboxPrototype(match.groups, null, budget);
234
+ if (match.indicesGroups !== undefined)
235
+ setSandboxPrototype(match.indicesGroups, null, budget);
236
+ Object.assign(result, { index: match.index, input, groups: match.groups });
237
+ if (match.indices !== undefined) {
238
+ budget?.allocateArrayLength(match.indices.length);
239
+ budget?.allocateArrayLength(2);
240
+ Object.assign(match.indices, { groups: match.indicesGroups });
241
+ Object.assign(result, { indices: match.indices });
242
+ }
232
243
  return result;
233
244
  }
@@ -1,8 +1,12 @@
1
1
  import type { Budget } from "../budget.js";
2
2
  import { type SandboxRegExpIterator } from "../regexp-iterator.js";
3
- import { type SandboxValue } from "../values.js";
3
+ import { type SandboxCallContext, type SandboxValue } from "../values.js";
4
4
  export declare function nextRegExpIterator(iterator: SandboxRegExpIterator, budget?: Budget): {
5
5
  value: SandboxValue;
6
6
  done: boolean;
7
7
  };
8
+ export declare function nextObservableRegExpIterator(iterator: SandboxRegExpIterator, budget: Budget, context: SandboxCallContext): Promise<{
9
+ value: SandboxValue;
10
+ done: boolean;
11
+ }>;
8
12
  export declare function getRegExpIteratorMember(property: PropertyKey, budget: Budget): SandboxValue;