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.
- package/dist/index.js +1855 -1153
- package/dist/index.js.map +4 -4
- package/dist/metafile.json +1 -1
- package/package.json +1 -1
- package/packages/safe-js/dist/chunks/{chunk-I2Z37MKZ.js → chunk-2J6W3YGB.js} +2 -2
- package/packages/safe-js/dist/chunks/{chunk-XKCTB5FR.js → chunk-YEZOXLY4.js} +3203 -2543
- package/packages/safe-js/dist/chunks/chunk-YEZOXLY4.js.map +7 -0
- package/packages/safe-js/dist/cli.js +2 -2
- package/packages/safe-js/dist/core.js +1 -1
- package/packages/safe-js/dist/graph-depth.js +3 -0
- package/packages/safe-js/dist/index.js +2 -2
- package/packages/safe-js/dist/interp/cancel.js +3 -0
- package/packages/safe-js/dist/interp/globals/misc.js +2 -1
- package/packages/safe-js/dist/interp/globals/object.js +3 -0
- package/packages/safe-js/dist/interp/globals/regex.js +88 -7
- package/packages/safe-js/dist/interp/interpreter.js +14 -7
- package/packages/safe-js/dist/interp/iteration.js +6 -1
- package/packages/safe-js/dist/interp/methods/regex.d.ts +7 -3
- package/packages/safe-js/dist/interp/methods/regex.js +127 -21
- package/packages/safe-js/dist/interp/methods/regexp-iterator.d.ts +8 -0
- package/packages/safe-js/dist/interp/methods/regexp-iterator.js +49 -0
- package/packages/safe-js/dist/interp/methods/string.d.ts +2 -0
- package/packages/safe-js/dist/interp/methods/string.js +412 -118
- package/packages/safe-js/dist/interp/object-model.d.ts +2 -0
- package/packages/safe-js/dist/interp/object-model.js +39 -9
- package/packages/safe-js/dist/interp/regexp-iterator.d.ts +14 -0
- package/packages/safe-js/dist/interp/regexp-iterator.js +18 -0
- package/packages/safe-js/dist/interp/string-coercion.js +11 -7
- package/packages/safe-js/dist/interp/values.d.ts +2 -1
- package/packages/safe-js/dist/interp/values.js +35 -0
- package/packages/safe-js/dist/snapshot/dump-format.js +26 -2
- package/packages/safe-js/dist/snapshot/replay-data.d.ts +9 -1
- package/packages/safe-js/dist/snapshot/replay-data.js +31 -0
- package/packages/safe-js/dist/snapshot/replay-inputs.js +17 -0
- package/packages/safe-js/dist/snapshot/restore.js +17 -1
- package/packages/safe-js/dist/snapshot/serialize.d.ts +10 -2
- package/packages/safe-js/dist/snapshot/serialize.js +26 -10
- package/packages/safe-js/dist/snapshot/validation.js +14 -2
- package/packages/safe-js/dist/chunks/chunk-XKCTB5FR.js.map +0 -7
- /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
|
|
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(
|
|
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
|
-
|
|
120
|
-
|
|
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
|
-
...
|
|
127
|
-
|
|
128
|
-
|
|
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 {
|
|
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)
|
|
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
|
|
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 (
|
|
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 =
|
|
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 =
|
|
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
|
-
:
|
|
414
|
-
? [
|
|
415
|
-
:
|
|
416
|
-
?
|
|
417
|
-
:
|
|
418
|
-
?
|
|
419
|
-
:
|
|
420
|
-
? [...value.
|
|
421
|
-
:
|
|
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
|
}
|