poe-code 14.0.73 → 14.0.74

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 (40) hide show
  1. package/dist/index.js +1855 -1153
  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-I2Z37MKZ.js → chunk-2J6W3YGB.js} +2 -2
  6. package/packages/safe-js/dist/chunks/{chunk-XKCTB5FR.js → chunk-YEZOXLY4.js} +3203 -2543
  7. package/packages/safe-js/dist/chunks/chunk-YEZOXLY4.js.map +7 -0
  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/graph-depth.js +3 -0
  11. package/packages/safe-js/dist/index.js +2 -2
  12. package/packages/safe-js/dist/interp/cancel.js +3 -0
  13. package/packages/safe-js/dist/interp/globals/misc.js +2 -1
  14. package/packages/safe-js/dist/interp/globals/object.js +3 -0
  15. package/packages/safe-js/dist/interp/globals/regex.js +88 -7
  16. package/packages/safe-js/dist/interp/interpreter.js +14 -7
  17. package/packages/safe-js/dist/interp/iteration.js +6 -1
  18. package/packages/safe-js/dist/interp/methods/regex.d.ts +7 -3
  19. package/packages/safe-js/dist/interp/methods/regex.js +127 -21
  20. package/packages/safe-js/dist/interp/methods/regexp-iterator.d.ts +8 -0
  21. package/packages/safe-js/dist/interp/methods/regexp-iterator.js +49 -0
  22. package/packages/safe-js/dist/interp/methods/string.d.ts +2 -0
  23. package/packages/safe-js/dist/interp/methods/string.js +412 -118
  24. package/packages/safe-js/dist/interp/object-model.d.ts +2 -0
  25. package/packages/safe-js/dist/interp/object-model.js +39 -9
  26. package/packages/safe-js/dist/interp/regexp-iterator.d.ts +14 -0
  27. package/packages/safe-js/dist/interp/regexp-iterator.js +18 -0
  28. package/packages/safe-js/dist/interp/string-coercion.js +11 -7
  29. package/packages/safe-js/dist/interp/values.d.ts +2 -1
  30. package/packages/safe-js/dist/interp/values.js +35 -0
  31. package/packages/safe-js/dist/snapshot/dump-format.js +26 -2
  32. package/packages/safe-js/dist/snapshot/replay-data.d.ts +9 -1
  33. package/packages/safe-js/dist/snapshot/replay-data.js +31 -0
  34. package/packages/safe-js/dist/snapshot/replay-inputs.js +17 -0
  35. package/packages/safe-js/dist/snapshot/restore.js +17 -1
  36. package/packages/safe-js/dist/snapshot/serialize.d.ts +10 -2
  37. package/packages/safe-js/dist/snapshot/serialize.js +26 -10
  38. package/packages/safe-js/dist/snapshot/validation.js +14 -2
  39. package/packages/safe-js/dist/chunks/chunk-XKCTB5FR.js.map +0 -7
  40. /package/packages/safe-js/dist/chunks/{chunk-I2Z37MKZ.js.map → chunk-2J6W3YGB.js.map} +0 -0
@@ -9,6 +9,8 @@ export declare function getGuestFunctionProperty(closure: SandboxClosure, key: P
9
9
  export declare function installObjectPrototype(budget: Budget, prototype: SandboxObject, constructor: SandboxClosure): void;
10
10
  export declare function installBoxedPrototype(budget: Budget, prototype: SandboxObject, constructor: SandboxClosure, kind?: BoxedKind): void;
11
11
  export declare function getBoxedPrototype(value: BoxedPrimitive, budget: Budget): SandboxObject | undefined;
12
+ export declare function installRegexPrototype(budget: Budget, prototype: SandboxObject, constructor: SandboxClosure): void;
13
+ export declare function hasRegexPropertyOverride(value: SandboxValue, keys: readonly string[], budget: Budget): boolean;
12
14
  export declare function isDefaultBoxedMethod(value: BoxedPrimitive, key: string, budget: Budget): boolean;
13
15
  export declare function isIntrinsicConstructor(value: object): boolean;
14
16
  export declare function releaseObjectPrototype(budget: Budget): void;
@@ -9,6 +9,8 @@ const functionProperties = new WeakMap();
9
9
  const prototypes = new WeakMap();
10
10
  const intrinsicPrototypes = new WeakMap();
11
11
  const boxedPrototypes = new WeakMap();
12
+ const regexPrototypes = new WeakMap();
13
+ const initialRegexDescriptors = new WeakMap();
12
14
  const intrinsicPrototypeRoots = new WeakMap();
13
15
  const intrinsicConstructors = new WeakMap();
14
16
  const initialBoxedMethods = new WeakMap();
@@ -80,6 +82,24 @@ export function installBoxedPrototype(budget, prototype, constructor, kind = typ
80
82
  export function getBoxedPrototype(value, budget) {
81
83
  return boxedPrototypes.get(budget)?.get(typeof value);
82
84
  }
85
+ export function installRegexPrototype(budget, prototype, constructor) {
86
+ regexPrototypes.set(budget, prototype);
87
+ initialRegexDescriptors.set(budget, Object.getOwnPropertyDescriptors(prototype));
88
+ registerIntrinsicPrototype(budget, prototype, constructor);
89
+ }
90
+ export function hasRegexPropertyOverride(value, keys, budget) {
91
+ const initial = initialRegexDescriptors.get(budget);
92
+ const prototype = regexPrototypes.get(budget);
93
+ const defaultPrototype = isSandboxRegex(value) && prototype !== undefined && getSandboxPrototype(value, budget) === prototype;
94
+ return keys.some(key => {
95
+ const current = defaultPrototype
96
+ ? Object.getOwnPropertyDescriptor(getRegexProperties(value), key) ?? Object.getOwnPropertyDescriptor(prototype, key)
97
+ : getSandboxPropertyDescriptor(value, key, budget);
98
+ const expected = initial?.[key];
99
+ return expected === undefined ? current !== undefined : current === undefined ||
100
+ current.value !== expected.value || current.get !== expected.get || current.set !== expected.set;
101
+ });
102
+ }
83
103
  export function isDefaultBoxedMethod(value, key, budget) {
84
104
  const prototype = getBoxedPrototype(value, budget);
85
105
  return prototype !== undefined && initialBoxedMethods.get(prototype)?.has(key) === true &&
@@ -93,7 +113,10 @@ function registerIntrinsicPrototype(budget, prototype, constructor) {
93
113
  if (roots === undefined)
94
114
  intrinsicPrototypeRoots.set(budget, (roots = new Set()));
95
115
  roots.add(prototype);
96
- const records = [prototype, constructor]
116
+ const methods = Reflect.ownKeys(prototype)
117
+ .map(key => Object.getOwnPropertyDescriptor(prototype, key)?.value)
118
+ .filter(isGuestClosure);
119
+ const records = [...new Set([prototype, constructor, ...methods])]
97
120
  .map((target) => ({
98
121
  target,
99
122
  value: isGuestClosure(target) ? materializeFunctionProperties(target) : target,
@@ -102,7 +125,7 @@ function registerIntrinsicPrototype(budget, prototype, constructor) {
102
125
  }))
103
126
  .map((record) => ({
104
127
  ...record,
105
- descriptors: new Map(Object.entries(Object.getOwnPropertyDescriptors(record.value)))
128
+ descriptors: new Map(Reflect.ownKeys(record.value).map(key => [key, Object.getOwnPropertyDescriptor(record.value, key)]))
106
129
  }));
107
130
  const unchanged = (before, after) => before !== undefined &&
108
131
  after !== undefined &&
@@ -116,16 +139,19 @@ function registerIntrinsicPrototype(budget, prototype, constructor) {
116
139
  const current = Object.getOwnPropertyDescriptors(value);
117
140
  return (getSandboxPrototype(target) === parent &&
118
141
  hasExplicitSandboxPrototype(target) === explicit &&
119
- Object.keys(current).length === descriptors.size &&
120
- Object.keys(current).every((key) => unchanged(descriptors.get(key), current[key])));
142
+ Reflect.ownKeys(current).length === descriptors.size &&
143
+ Reflect.ownKeys(value).every((key) => unchanged(descriptors.get(key), Object.getOwnPropertyDescriptor(value, key))));
121
144
  }));
122
145
  budget.setRetainedValues(prototype, () => records.flatMap(({ target, value, descriptors, prototype: parent }) => [
123
146
  ...(getSandboxPrototype(target) === parent
124
147
  ? []
125
148
  : [getSandboxPrototype(target)]),
126
- ...Object.entries(Object.getOwnPropertyDescriptors(value)).flatMap(([key, descriptor]) => unchanged(descriptors.get(key), descriptor)
127
- ? []
128
- : [key, descriptor.value, ...retainedAccessorClosures(descriptor)])
149
+ ...Reflect.ownKeys(value).flatMap(key => {
150
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
151
+ return unchanged(descriptors.get(key), descriptor)
152
+ ? []
153
+ : [key, descriptor.value, ...retainedAccessorClosures(descriptor)];
154
+ })
129
155
  ]));
130
156
  }
131
157
  export function releaseObjectPrototype(budget) {
@@ -133,11 +159,15 @@ export function releaseObjectPrototype(budget) {
133
159
  budget.setRetainedValues(prototype, undefined);
134
160
  intrinsicPrototypeRoots.delete(budget);
135
161
  boxedPrototypes.delete(budget);
162
+ regexPrototypes.delete(budget);
163
+ initialRegexDescriptors.delete(budget);
136
164
  intrinsicPrototypes.delete(budget);
137
165
  }
138
166
  export function getSandboxPrototype(value, budget) {
139
167
  if (prototypes.has(value))
140
168
  return prototypes.get(value) ?? null;
169
+ if (budget !== undefined && isSandboxRegex(value))
170
+ return regexPrototypes.get(budget) ?? null;
141
171
  if (budget !== undefined && isSandboxBox(value)) {
142
172
  const prototype = getBoxedPrototype(boxedValue(value), budget);
143
173
  if (prototype !== undefined && prototype !== value)
@@ -213,13 +243,13 @@ export function setSandboxPrototype(value, prototype, budget) {
213
243
  if (budget !== undefined && intrinsicPrototypes.get(budget) === value && prototype !== null) {
214
244
  throw new TypeError("Object.prototype has an immutable null prototype.");
215
245
  }
216
- if ((!Array.isArray(value) && !isPrototypeRecord(value)) ||
246
+ if ((!Array.isArray(value) && !isSandboxRegex(value) && !isPrototypeRecord(value)) ||
217
247
  (prototype !== null && !Array.isArray(prototype) && !isPrototypeRecord(prototype))) {
218
248
  throw new TypeError("Prototype links require ordinary sandbox objects, arrays, or guest functions.");
219
249
  }
220
250
  if (prototypes.has(value) && getSandboxPrototype(value, budget) === prototype)
221
251
  return;
222
- if (!Object.isExtensible(isGuestClosure(value) ? materializeFunctionProperties(value) : value)) {
252
+ if (!Object.isExtensible(isGuestClosure(value) ? materializeFunctionProperties(value) : isSandboxRegex(value) ? getRegexProperties(value) : value)) {
223
253
  throw new TypeError("Cannot change the prototype of a non-extensible object.");
224
254
  }
225
255
  let depth = 0;
@@ -0,0 +1,14 @@
1
+ import type { SandboxRegex } from "./values.js";
2
+ declare const regexpIteratorBrand: unique symbol;
3
+ export type SandboxRegExpIterator = {
4
+ readonly [regexpIteratorBrand]: true;
5
+ };
6
+ export type RegExpIteratorState = {
7
+ matcher: SandboxRegex | undefined;
8
+ input: string | undefined;
9
+ exhausted: boolean;
10
+ };
11
+ export declare function isSandboxRegExpIterator(value: unknown): value is SandboxRegExpIterator;
12
+ export declare function restoreSandboxRegExpIterator(state: RegExpIteratorState, target?: SandboxRegExpIterator): SandboxRegExpIterator;
13
+ export declare function regexpIteratorState(value: SandboxRegExpIterator): RegExpIteratorState;
14
+ export {};
@@ -0,0 +1,18 @@
1
+ const states = new WeakMap();
2
+ export function isSandboxRegExpIterator(value) {
3
+ return typeof value === "object" && value !== null && states.has(value);
4
+ }
5
+ export function restoreSandboxRegExpIterator(state, target = Object.create(null)) {
6
+ if (!state.exhausted && (state.matcher === undefined || state.input === undefined))
7
+ throw new TypeError("A live RegExp iterator requires its matcher and input.");
8
+ states.set(target, state.exhausted
9
+ ? { matcher: undefined, input: undefined, exhausted: true }
10
+ : { ...state });
11
+ return target;
12
+ }
13
+ export function regexpIteratorState(value) {
14
+ const state = states.get(value);
15
+ if (state === undefined)
16
+ throw new TypeError("Expected a RegExp string iterator.");
17
+ return state;
18
+ }
@@ -7,12 +7,13 @@ import { float32Storage, isFloat32Array } from "./float32.js";
7
7
  import { assertSandboxDataDepth } from "../graph-depth.js";
8
8
  import { isGuestHostObject } from "./host-capabilities.js";
9
9
  import { collectionIteratorState, isSandboxCollectionIterator } from "./collection-iterator.js";
10
+ import { isSandboxRegExpIterator } from "./regexp-iterator.js";
10
11
  import { getGuestFunctionProperties, getSandboxPrototype, hasExplicitSandboxPrototype, isGuestClosure } from "./object-model.js";
11
- import { getRegexMember } from "./methods/regex.js";
12
+ import { regexToString } from "./methods/regex.js";
12
13
  import { retainValues } from "./resources.js";
13
14
  import { functionString } from "./function-string.js";
14
15
  import { boxedValue, isSandboxBox } from "./boxed.js";
15
- import { isSandboxClosure, isSandboxPromise, isSandboxMap, isSandboxSet, isSandboxRegex, isSandboxGenerator } from "./values.js";
16
+ import { isSandboxClosure, isSandboxPromise, isSandboxMap, isSandboxSet, isSandboxRegex, getRegexProperties, isSandboxGenerator } from "./values.js";
16
17
  const defaultStringHook = Symbol("defaultStringHook");
17
18
  const defaultValueHook = Symbol("defaultValueHook");
18
19
  const joiningArrays = new WeakSet();
@@ -115,14 +116,16 @@ function conversionHook(value, name, budget, context) {
115
116
  isSandboxMap(value) ||
116
117
  isSandboxSet(value) ||
117
118
  isSandboxCollectionIterator(value) ||
119
+ isSandboxRegExpIterator(value) ||
118
120
  isSandboxPromise(value) ||
119
- isSandboxRegex(value) ||
121
+ (isSandboxRegex(value) && getSandboxPrototype(value, budget) === null) ||
120
122
  isSandboxGenerator(value) ||
121
123
  isGuestHostObject(value));
122
124
  let current = value;
123
125
  let depth = 0;
124
126
  while (current !== null) {
125
- const properties = isGuestClosure(current) ? getGuestFunctionProperties(current) : current;
127
+ const properties = isGuestClosure(current) ? getGuestFunctionProperties(current)
128
+ : isSandboxRegex(current) ? getRegexProperties(current) : current;
126
129
  const descriptor = properties === undefined ? undefined : Object.getOwnPropertyDescriptor(properties, name);
127
130
  if (descriptor !== undefined) {
128
131
  return readPropertyDescriptor(descriptor, value, context);
@@ -154,15 +157,16 @@ async function defaultToString(value, budget, context, joining) {
154
157
  return "[object Map]";
155
158
  if (isSandboxSet(value))
156
159
  return "[object Set]";
160
+ if (isSandboxRegExpIterator(value))
161
+ return "[object RegExp String Iterator]";
157
162
  if (isSandboxCollectionIterator(value))
158
163
  return collectionIteratorState(value).collectionKind === "map"
159
164
  ? "[object Map Iterator]"
160
165
  : "[object Set Iterator]";
161
166
  if (isSandboxGenerator(value))
162
167
  return "[object Generator]";
163
- if (isSandboxRegex(value)) {
164
- return budget.allocateString(`/${String(getRegexMember(value, "source", budget))}/${String(getRegexMember(value, "flags", budget))}`);
165
- }
168
+ if (isSandboxRegex(value))
169
+ return regexToString(value, budget, context);
166
170
  if (isSandboxDate(value))
167
171
  return budget.allocateString(dateString(value));
168
172
  if (Array.isArray(value) || isFloat32Array(value)) {
@@ -1,6 +1,7 @@
1
1
  export { getRegexProperties } from "./regexp-properties.js";
2
2
  import { sandboxMapBrand, sandboxSetBrand } from "./collection-brands.js";
3
3
  import { type SandboxCollectionIterator } from "./collection-iterator.js";
4
+ import { type SandboxRegExpIterator } from "./regexp-iterator.js";
4
5
  import type { Budget, CompileTicket } from "./budget.js";
5
6
  import { CompileScope } from "./regex/compile-guard.js";
6
7
  import type { GeneratorChannel } from "./generator.js";
@@ -15,7 +16,7 @@ declare const sandboxRegexBrand: unique symbol;
15
16
  declare const sandboxRegexPattern: unique symbol;
16
17
  declare const sandboxRetainedValues: unique symbol;
17
18
  export type SandboxPrimitive = string | number | boolean | symbol | null | undefined;
18
- export type SandboxValue = SandboxPrimitive | Date | Float32Array | SandboxObject | SandboxArray | SandboxClosure | SandboxGenerator | SandboxCollectionIterator | SandboxMap | SandboxSet | SandboxPromise | SandboxRegex;
19
+ export type SandboxValue = SandboxPrimitive | Date | Float32Array | SandboxObject | SandboxArray | SandboxClosure | SandboxGenerator | SandboxCollectionIterator | SandboxRegExpIterator | SandboxMap | SandboxSet | SandboxPromise | SandboxRegex;
19
20
  export type SandboxObject = {
20
21
  [key: string]: SandboxValue;
21
22
  [key: symbol]: SandboxValue;
@@ -5,6 +5,7 @@ export { getRegexProperties } from "./regexp-properties.js";
5
5
  import { retainedAccessorClosures } from "./accessors.js";
6
6
  import { isSandboxMap, isSandboxSet, sandboxMapBrand, sandboxSetBrand } from "./collection-brands.js";
7
7
  import { collectionIteratorState, isSandboxCollectionIterator, restoreSandboxCollectionIterator, snapshotCollectionIterator } from "./collection-iterator.js";
8
+ import { regexpIteratorState, isSandboxRegExpIterator, restoreSandboxRegExpIterator } from "./regexp-iterator.js";
8
9
  import { copyNativeDate, dateDataProperties, exportDate, isSandboxDate } from "./date.js";
9
10
  import { boxedDataProperties, boxedValue, createSandboxBox, isSandboxBox, nativeBoxedValue } from "./boxed.js";
10
11
  import { getHostObjectKeys, getHostObjectMember, hasHostObjectMember, measureHostObjectData, isGuestHostObject, isLiveCapability } from "./host-capabilities.js";
@@ -400,6 +401,17 @@ export function measureSandboxData(values, options = {}) {
400
401
  }
401
402
  return;
402
403
  }
404
+ if (isSandboxRegExpIterator(value)) {
405
+ const state = regexpIteratorState(value);
406
+ visit(state.matcher, depth + 1);
407
+ visit(state.input, depth + 1);
408
+ for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(value))) {
409
+ usage += key.length + 1;
410
+ if ("value" in descriptor)
411
+ visit(descriptor.value, depth + 1);
412
+ }
413
+ return;
414
+ }
403
415
  if (isSandboxCollectionIterator(value)) {
404
416
  visit(collectionIteratorState(value).collection, depth + 1);
405
417
  for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(value))) {
@@ -588,6 +600,26 @@ function copyToSandbox(value, state, path = "<root>", cloneSandboxCollections =
588
600
  isSandboxPromise(value)) {
589
601
  return value;
590
602
  }
603
+ if (isSandboxRegExpIterator(value)) {
604
+ if (hasGuestObjectState(value))
605
+ throw new TypeError("Guest prototype links and custom descriptors cannot be copied as data.");
606
+ if (!cloneSandboxCollections)
607
+ return value;
608
+ const existing = state.seen.get(value);
609
+ if (existing !== undefined)
610
+ return existing;
611
+ const snapshot = regexpIteratorState(value);
612
+ const copy = restoreSandboxRegExpIterator({ matcher: undefined, input: undefined, exhausted: true });
613
+ state.seen.set(value, copy);
614
+ const matcher = copyToSandbox(snapshot.matcher, state, `${path}.<matcher>`, true, depth + 1);
615
+ if (matcher !== undefined && !isSandboxRegex(matcher))
616
+ throw new TypeError("Invalid RegExp iterator matcher.");
617
+ restoreSandboxRegExpIterator({ ...snapshot, matcher }, copy);
618
+ for (const entry of getEnumerableObjectEntries(value, path)) {
619
+ defineOwnDataProperty(copy, entry.key, copyToSandbox(entry.value, state, joinPath(path, entry.key), true, depth + 1));
620
+ }
621
+ return copy;
622
+ }
591
623
  if (isSandboxCollectionIterator(value)) {
592
624
  if (hasGuestObjectState(value))
593
625
  throw new TypeError("Guest prototype links and custom descriptors cannot be copied as data.");
@@ -890,6 +922,9 @@ function copyFromSandbox(value, state, path = "<root>", options, depth = 0) {
890
922
  if (isSandboxCollectionIterator(value)) {
891
923
  throw new TypeError("Sandbox collection iterators cannot cross into host values.");
892
924
  }
925
+ if (isSandboxRegExpIterator(value)) {
926
+ throw new TypeError("Sandbox RegExp iterators cannot cross into host values.");
927
+ }
893
928
  if (isSandboxRegex(value)) {
894
929
  throw new TypeError("Invalid sandbox RegExp brand.");
895
930
  }
@@ -1,5 +1,6 @@
1
1
  export const DUMP_FORMAT_VERSION = 1;
2
2
  import { getRegexProperties, isSandboxRegex } from "../interp/values.js";
3
+ import { isSandboxRegExpIterator, regexpIteratorState } from "../interp/regexp-iterator.js";
3
4
  import { hasCustomRegexProperties, serializeRegexProperties } from "./regexp-properties.js";
4
5
  export const EXECUTION_SEMANTICS = "jobs-v8";
5
6
  import { assertSnapshotGraphDepth } from "../graph-depth.js";
@@ -81,7 +82,7 @@ function serializeDumpValue(value, path, state) {
81
82
  if (hasGuestObjectState(value)) {
82
83
  throw new TypeError("Guest function properties and prototype links cannot be serialized.");
83
84
  }
84
- if ((isSandboxRegex(value) && hasCustomRegexProperties(value)) || isSandboxBox(value) || isSandboxDate(value) || isFloat32Array(value))
85
+ if (isSandboxRegExpIterator(value) || (isSandboxRegex(value) && hasCustomRegexProperties(value)) || isSandboxBox(value) || isSandboxDate(value) || isFloat32Array(value))
85
86
  return serializeHeapReference(value, path, state);
86
87
  if (Array.isArray(value)) {
87
88
  const reference = serializeHeapReference(value, path, state);
@@ -106,7 +107,29 @@ function serializeHeapReference(value, path, state) {
106
107
  }
107
108
  if (!state.serializedHeapIds.has(id)) {
108
109
  state.serializedHeapIds.add(id);
109
- if (isSandboxRegex(value) && hasCustomRegexProperties(value)) {
110
+ if (isSandboxRegExpIterator(value)) {
111
+ const snapshot = regexpIteratorState(value);
112
+ const matcher = snapshot.matcher;
113
+ const entries = Object.create(null);
114
+ state.heap[String(id)] = {
115
+ kind: "regexp-iterator", exhausted: snapshot.exhausted,
116
+ matcher: matcher === undefined ? { kind: "undefined" } : { kind: "regex", source: matcher.source, flags: matcher.flags, lastIndex: Number(matcher.lastIndex) },
117
+ input: snapshot.input ?? { kind: "undefined" }, entries,
118
+ symbolEntries: serializeSymbolProperties(value, entry => {
119
+ const serialized = serializeDumpValue(entry, `${path}.[symbol]`, state);
120
+ if (serialized === SKIP_VALUE)
121
+ throw new TypeError("Unsupported RegExp iterator symbol property in public dump.");
122
+ return serialized;
123
+ })
124
+ };
125
+ for (const [key, entry] of getEnumerableDataEntries(value)) {
126
+ const serialized = serializeDumpValue(entry, `${path}.${key}`, state);
127
+ if (serialized === SKIP_VALUE)
128
+ throw new TypeError("Unsupported RegExp iterator property in public dump.");
129
+ entries[key] = serialized;
130
+ }
131
+ }
132
+ else if (isSandboxRegex(value) && hasCustomRegexProperties(value)) {
110
133
  const encode = (entry) => {
111
134
  const serialized = serializeDumpValue(entry, `${path}.<regex-property>`, state);
112
135
  if (serialized === SKIP_VALUE)
@@ -206,6 +229,7 @@ function indexHeapContainers(snapshot) {
206
229
  stat.cyclic ||
207
230
  ownSerializableSymbolKeys(value).length > 0 ||
208
231
  isSandboxBox(value) ||
232
+ isSandboxRegExpIterator(value) ||
209
233
  (isSandboxRegex(value) && hasCustomRegexProperties(value)) ||
210
234
  isSandboxDate(value) ||
211
235
  isFloat32Array(value) ||
@@ -27,7 +27,15 @@ type Properties = Record<string, {
27
27
  enumerable: boolean;
28
28
  writable: boolean;
29
29
  }>;
30
- type DataNode = SerializedSymbol | {
30
+ type DataNode = {
31
+ kind: "regexp-iterator";
32
+ matcher: Atom;
33
+ input: Atom;
34
+ exhausted: boolean;
35
+ properties: Properties;
36
+ extensible: boolean;
37
+ symbolEntries?: Array<SerializedSymbolProperty<Atom>>;
38
+ } | SerializedSymbol | {
31
39
  kind: "boxed";
32
40
  value: Atom;
33
41
  properties: Properties;
@@ -3,6 +3,7 @@ import { serializeRegexProperties, restoreRegexProperties } from "./regexp-prope
3
3
  import { wellKnownSymbols } from "../interp/symbols.js";
4
4
  import { symbolData, serializeSymbolProperties } from "./symbols.js";
5
5
  import { isSandboxCollectionIterator, restoreSandboxCollectionIterator, snapshotCollectionIterator } from "../interp/collection-iterator.js";
6
+ import { isSandboxRegExpIterator, regexpIteratorState, restoreSandboxRegExpIterator } from "../interp/regexp-iterator.js";
6
7
  import { hasGuestObjectState } from "../interp/object-model.js";
7
8
  import { CompileScope } from "../interp/regex/compile-guard.js";
8
9
  import { float32DataProperties, isFloat32Array } from "../interp/float32.js";
@@ -123,6 +124,18 @@ export function encodeReplayData(value, options = {}) {
123
124
  }
124
125
  nodes[id] = { ...storage, properties, extensible: Object.isExtensible(entry) };
125
126
  }
127
+ else if (isSandboxRegExpIterator(entry)) {
128
+ const snapshot = regexpIteratorState(entry);
129
+ const properties = Object.create(null);
130
+ for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(entry))) {
131
+ if (!("value" in descriptor))
132
+ throw new TypeError(`Cannot record replay data accessor '${key}'.`);
133
+ properties[key] = { value: child(descriptor.value, JSON.stringify(["property", key])), configurable: descriptor.configurable === true, enumerable: descriptor.enumerable === true, writable: descriptor.writable === true };
134
+ }
135
+ let symbolIndex = 0;
136
+ const symbolEntries = serializeSymbolProperties(entry, value => encode(value, depth + 1, [...path, { symbol: Math.floor(symbolIndex++ / 2) }]));
137
+ nodes[id] = { kind: "regexp-iterator", matcher: child(snapshot.matcher, "<matcher>"), input: child(snapshot.input, "<input>"), exhausted: snapshot.exhausted, properties, extensible: Object.isExtensible(entry), symbolEntries };
138
+ }
126
139
  else if (isSandboxCollectionIterator(entry)) {
127
140
  const snapshot = snapshotCollectionIterator(entry);
128
141
  const properties = Object.create(null);
@@ -344,6 +357,24 @@ export function decodeReplayData(input, options = {}, parent) {
344
357
  Object.preventExtensions(result);
345
358
  return result;
346
359
  }
360
+ if (kind === "regexp-iterator") {
361
+ const exhausted = own(node, "exhausted");
362
+ if (typeof exhausted !== "boolean" || typeof node.extensible !== "boolean")
363
+ throw new TypeError("Invalid replay RegExp iterator.");
364
+ const result = restoreSandboxRegExpIterator({ matcher: undefined, input: undefined, exhausted: true });
365
+ restored.set(id, result);
366
+ const matcher = child(own(node, "matcher"));
367
+ const input = child(own(node, "input"));
368
+ if (matcher !== undefined && !isSandboxRegex(matcher))
369
+ throw new TypeError("Invalid replay RegExp iterator matcher.");
370
+ if (input !== undefined && typeof input !== "string")
371
+ throw new TypeError("Invalid replay RegExp iterator input.");
372
+ restoreSandboxRegExpIterator({ matcher, input, exhausted }, result);
373
+ defineProperties(result, record(own(node, "properties")), child, node.symbolEntries);
374
+ if (!node.extensible)
375
+ Object.preventExtensions(result);
376
+ return result;
377
+ }
347
378
  if (kind === "collection-iterator") {
348
379
  const collectionKind = own(node, "collectionKind");
349
380
  const method = own(node, "method");
@@ -1,4 +1,5 @@
1
1
  import { collectionIteratorState, isSandboxCollectionIterator } from "../interp/collection-iterator.js";
2
+ import { regexpIteratorState, isSandboxRegExpIterator } from "../interp/regexp-iterator.js";
2
3
  import { createSandboxPromise, isSandboxClosure, isSandboxMap, isSandboxSet, isSandboxPromise } from "../interp/values.js";
3
4
  import { decodeReplayData, encodeReplayData } from "./replay-data.js";
4
5
  import { CompileScope } from "../interp/regex/compile-guard.js";
@@ -59,6 +60,20 @@ export function prepareReplayInputs(current, saved, preparePromise, onCapability
59
60
  value = descriptor.value;
60
61
  continue;
61
62
  }
63
+ if (isSandboxRegExpIterator(value)) {
64
+ if (key === "<matcher>")
65
+ value = regexpIteratorState(value).matcher;
66
+ else if (key === "<input>")
67
+ value = regexpIteratorState(value).input;
68
+ else {
69
+ const property = JSON.parse(key);
70
+ if (!Array.isArray(property) || property.length !== 2 || property[0] !== "property" || typeof property[1] !== "string")
71
+ throw new TypeError("Invalid replay input iterator capability path.");
72
+ const descriptor = Object.getOwnPropertyDescriptor(value, property[1]);
73
+ value = descriptor !== undefined && "value" in descriptor ? descriptor.value : undefined;
74
+ }
75
+ continue;
76
+ }
62
77
  if (isSandboxCollectionIterator(value)) {
63
78
  if (key === "<collection>")
64
79
  value = collectionIteratorState(value).collection;
@@ -135,6 +150,7 @@ function assertReplayInputShape(restored) {
135
150
  isSandboxClosure(restored) ||
136
151
  isSandboxPromise(restored) ||
137
152
  isSandboxCollectionIterator(restored) ||
153
+ isSandboxRegExpIterator(restored) ||
138
154
  isSandboxMap(restored) ||
139
155
  isSandboxSet(restored))
140
156
  throw new TypeError("Invalid replay inputs.");
@@ -146,6 +162,7 @@ function assertReplayInputShape(restored) {
146
162
  isSandboxClosure(values[key]) ||
147
163
  isSandboxPromise(values[key]) ||
148
164
  isSandboxCollectionIterator(values[key]) ||
165
+ isSandboxRegExpIterator(values[key]) ||
149
166
  isSandboxMap(values[key]) ||
150
167
  isSandboxSet(values[key]))
151
168
  throw new TypeError(`Invalid replay input ${key}.`);
@@ -14,10 +14,11 @@ import { getGuestFunctionProperties, getGuestFunctionProperty, getSandboxDataPro
14
14
  import { functionSources } from "../parse/function-source.js";
15
15
  import { wrapCallerInjectedBindings } from "../interp/host-bridge.js";
16
16
  import { restoreSandboxCollectionIterator } from "../interp/collection-iterator.js";
17
+ import { restoreSandboxRegExpIterator } from "../interp/regexp-iterator.js";
17
18
  import { wellKnownSymbols } from "../interp/symbols.js";
18
19
  import { restoreSymbolProperties } from "./symbols.js";
19
20
  import { restoreDateProperties } from "./date-properties.js";
20
- import { isSandboxMap, isSandboxSet } from "../interp/values.js";
21
+ import { isSandboxMap, isSandboxSet, isSandboxRegex } from "../interp/values.js";
21
22
  import { createSandboxArguments, createSandboxClosure, createSandboxGenerator, createSandboxMap, createSandboxPromise, createSandboxRegex, createSandboxSet, reconcileCompiledValues } from "../interp/values.js";
22
23
  import { createGeneratorChannel, restoreGeneratorChannel } from "../interp/generator.js";
23
24
  import { hashSource } from "../parse/hash.js";
@@ -433,6 +434,21 @@ function restoreHeapValue(id, state) {
433
434
  Object.preventExtensions(args);
434
435
  return args;
435
436
  }
437
+ if (serialized.kind === "regexp-iterator") {
438
+ const iterator = restoreSandboxRegExpIterator({ matcher: undefined, input: undefined, exhausted: true });
439
+ state.heapValueById.set(id, iterator);
440
+ const matcher = deserializeValue(serialized.matcher, state);
441
+ const input = deserializeValue(serialized.input, state);
442
+ if (matcher !== undefined && !isSandboxRegex(matcher))
443
+ throw new TypeError("Invalid RegExp iterator matcher.");
444
+ if (input !== undefined && typeof input !== "string")
445
+ throw new TypeError("Invalid RegExp iterator input.");
446
+ restoreSandboxRegExpIterator({ matcher, input, exhausted: serialized.exhausted }, iterator);
447
+ for (const [key, entry] of Object.entries(serialized.entries))
448
+ Object.defineProperty(iterator, key, { value: deserializeValue(entry, state), enumerable: true, configurable: true, writable: true });
449
+ restoreSymbolProperties(iterator, serialized.symbolEntries, entry => deserializeValue(entry, state));
450
+ return iterator;
451
+ }
436
452
  if (serialized.kind === "collection-iterator") {
437
453
  const iterator = restoreSandboxCollectionIterator({ collection: undefined, collectionKind: serialized.collectionKind, method: serialized.method, index: 0, exhausted: true });
438
454
  state.heapValueById.set(id, iterator);
@@ -1,6 +1,7 @@
1
1
  import { type RegexPropertyData } from "./regexp-properties.js";
2
2
  import { type SerializedSymbol, type SerializedSymbolProperty } from "./symbols.js";
3
3
  import { type CollectionIterationMethod, type SandboxCollectionIterator } from "../interp/collection-iterator.js";
4
+ import { type SandboxRegExpIterator } from "../interp/regexp-iterator.js";
4
5
  import { type SandboxErrorName } from "../error/shape.js";
5
6
  import { type SerializedArguments } from "./arguments.js";
6
7
  import { type SerializedArray } from "./arrays.js";
@@ -48,7 +49,14 @@ export type SerializedReferenceValue = {
48
49
  kind: "ref";
49
50
  id: number;
50
51
  };
51
- export type SerializedHeapValue = SerializedSymbol | BoxedData<SerializedSnapshotValue> | ({
52
+ export type SerializedHeapValue = {
53
+ kind: "regexp-iterator";
54
+ matcher: SerializedSnapshotValue;
55
+ input: SerializedSnapshotValue;
56
+ exhausted: boolean;
57
+ entries: Record<string, SerializedSnapshotValue>;
58
+ symbolEntries?: Array<SerializedSymbolProperty<SerializedSnapshotValue>>;
59
+ } | SerializedSymbol | BoxedData<SerializedSnapshotValue> | ({
52
60
  kind: "regex-object";
53
61
  source: string;
54
62
  flags: string;
@@ -94,7 +102,7 @@ export type RuntimePromiseValue = {
94
102
  id: SnapshotId;
95
103
  promise?: Promise<unknown>;
96
104
  };
97
- export type RuntimeSnapshotValue = symbol | SandboxBox | Date | Float32Array | boolean | null | number | string | undefined | RuntimeClosureValue | SandboxGenerator | SandboxCollectionIterator | RuntimePromiseValue | SandboxMap | SandboxRegex | SandboxSet | RuntimeSnapshotValue[] | {
105
+ export type RuntimeSnapshotValue = symbol | SandboxBox | Date | Float32Array | boolean | null | number | string | undefined | RuntimeClosureValue | SandboxGenerator | SandboxCollectionIterator | SandboxRegExpIterator | RuntimePromiseValue | SandboxMap | SandboxRegex | SandboxSet | RuntimeSnapshotValue[] | {
98
106
  [key: string]: RuntimeSnapshotValue;
99
107
  };
100
108
  export type RuntimeScopeFrame = {
@@ -2,6 +2,7 @@ import { hashSource } from "../parse/hash.js";
2
2
  import { hasCustomRegexProperties, serializeRegexProperties } from "./regexp-properties.js";
3
3
  import { ownSerializableSymbolKeys, serializeSymbol, serializeSymbolProperties } from "./symbols.js";
4
4
  import { collectionIteratorState, isSandboxCollectionIterator, snapshotCollectionIterator } from "../interp/collection-iterator.js";
5
+ import { isSandboxRegExpIterator, regexpIteratorState } from "../interp/regexp-iterator.js";
5
6
  import { hasGuestObjectState } from "../interp/object-model.js";
6
7
  import { sandboxErrorTypes } from "../error/shape.js";
7
8
  import { assertSnapshotGraphDepth } from "../graph-depth.js";
@@ -180,7 +181,7 @@ function serializeValue(value, path, state) {
180
181
  throw new TypeError(`Missing regex heap reference at ${path}.`);
181
182
  return { kind: "regex", source: value.source, flags: value.flags, lastIndex: value.lastIndex };
182
183
  }
183
- if (isSandboxBox(value) || isSandboxDate(value) || isSandboxMap(value) || isSandboxSet(value) || isSandboxCollectionIterator(value) || isFloat32Array(value)) {
184
+ if (isSandboxBox(value) || isSandboxDate(value) || isSandboxMap(value) || isSandboxSet(value) || isSandboxRegExpIterator(value) || isSandboxCollectionIterator(value) || isFloat32Array(value)) {
184
185
  const reference = serializeHeapReference(value, path, state);
185
186
  if (reference === undefined) {
186
187
  throw new TypeError(`Cannot serialize collection without a heap reference at ${path}.`);
@@ -214,6 +215,17 @@ function serializeHeapReference(value, path, state) {
214
215
  lastIndex: serializeValue(value.lastIndex, `${path}.lastIndex`, state),
215
216
  ...serializeRegexProperties(value, entry => serializeValue(entry, `${path}.<regex-property>`, state)) };
216
217
  }
218
+ else if (isSandboxRegExpIterator(value)) {
219
+ const snapshot = regexpIteratorState(value);
220
+ const entries = Object.create(null);
221
+ state.heap[String(id)] = {
222
+ kind: "regexp-iterator", matcher: serializeValue(snapshot.matcher, `${path}.<matcher>`, state),
223
+ input: serializeValue(snapshot.input, `${path}.<input>`, state), exhausted: snapshot.exhausted, entries,
224
+ symbolEntries: serializeSymbolProperties(value, entry => serializeValue(entry, `${path}.[symbol]`, state))
225
+ };
226
+ for (const [key, entry] of Object.entries(value))
227
+ entries[key] = serializeValue(entry, `${path}.${key}`, state);
228
+ }
217
229
  else if (isSandboxCollectionIterator(value)) {
218
230
  const snapshot = snapshotCollectionIterator(value);
219
231
  const entries = Object.create(null);
@@ -357,6 +369,7 @@ function indexHeapContainers(input) {
357
369
  sandboxErrorTypes.has(value) ||
358
370
  isSandboxArguments(value) ||
359
371
  isSandboxCollectionIterator(value) ||
372
+ isSandboxRegExpIterator(value) ||
360
373
  isSandboxMap(value) ||
361
374
  isSandboxSet(value)) {
362
375
  heapIds.set(value, nextId);
@@ -379,6 +392,7 @@ function collectContainerStats(value, stats, ancestors) {
379
392
  !isFloat32Array(value) &&
380
393
  !isSandboxMap(value) &&
381
394
  !isSandboxCollectionIterator(value) &&
395
+ !isSandboxRegExpIterator(value) &&
382
396
  !isSandboxSet(value)) {
383
397
  return;
384
398
  }
@@ -410,15 +424,17 @@ function collectContainerStats(value, stats, ancestors) {
410
424
  ? dateDataProperties(value).flatMap(([key, descriptor]) => typeof key === "string" ? [descriptor.value] : [])
411
425
  : isSandboxBox(value)
412
426
  ? boxedDataProperties(value).map(([, descriptor]) => descriptor.value)
413
- : isSandboxCollectionIterator(value)
414
- ? [collectionIteratorState(value).collection, ...Object.values(value)]
415
- : isSandboxArguments(value)
416
- ? Object.values(Object.getOwnPropertyDescriptors(value)).flatMap((descriptor) => "value" in descriptor ? [descriptor.value] : [])
417
- : isSandboxMap(value)
418
- ? [...value.entries].flatMap(([key, entry]) => [key, entry])
419
- : isSandboxSet(value)
420
- ? [...value.values]
421
- : Object.values(value);
427
+ : isSandboxRegExpIterator(value)
428
+ ? [regexpIteratorState(value).matcher, regexpIteratorState(value).input, ...Object.values(value)]
429
+ : isSandboxCollectionIterator(value)
430
+ ? [collectionIteratorState(value).collection, ...Object.values(value)]
431
+ : isSandboxArguments(value)
432
+ ? Object.values(Object.getOwnPropertyDescriptors(value)).flatMap((descriptor) => "value" in descriptor ? [descriptor.value] : [])
433
+ : isSandboxMap(value)
434
+ ? [...value.entries].flatMap(([key, entry]) => [key, entry])
435
+ : isSandboxSet(value)
436
+ ? [...value.values]
437
+ : Object.values(value);
422
438
  for (const entry of entries) {
423
439
  collectContainerStats(entry, stats, ancestors);
424
440
  }