poe-code 14.0.72 → 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 +2674 -1760
- 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-VYUHL33E.js → chunk-2J6W3YGB.js} +2 -2
- package/packages/safe-js/dist/chunks/{chunk-6UY4Z7WY.js → chunk-YEZOXLY4.js} +6279 -5426
- 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 +10 -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-array.js +9 -7
- package/packages/safe-js/dist/interp/globals/object.js +5 -2
- package/packages/safe-js/dist/interp/globals/regex.js +88 -7
- package/packages/safe-js/dist/interp/interpreter.js +21 -14
- 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 +132 -23
- 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 +460 -127
- package/packages/safe-js/dist/interp/object-model.d.ts +2 -0
- package/packages/safe-js/dist/interp/object-model.js +45 -12
- 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/regexp-properties.d.ts +3 -0
- package/packages/safe-js/dist/interp/regexp-properties.js +7 -0
- package/packages/safe-js/dist/interp/string-coercion.js +11 -7
- package/packages/safe-js/dist/interp/values.d.ts +3 -1
- package/packages/safe-js/dist/interp/values.js +111 -2
- package/packages/safe-js/dist/snapshot/dump-format.js +51 -9
- package/packages/safe-js/dist/snapshot/regexp-properties.d.ts +18 -0
- package/packages/safe-js/dist/snapshot/regexp-properties.js +58 -0
- package/packages/safe-js/dist/snapshot/replay-data.d.ts +12 -3
- package/packages/safe-js/dist/snapshot/replay-data.js +35 -1
- package/packages/safe-js/dist/snapshot/replay-inputs.js +17 -0
- package/packages/safe-js/dist/snapshot/restore.js +19 -1
- package/packages/safe-js/dist/snapshot/serialize.d.ts +12 -3
- package/packages/safe-js/dist/snapshot/serialize.js +40 -17
- package/packages/safe-js/dist/snapshot/validation.js +25 -2
- package/packages/safe-js/dist/chunks/chunk-6UY4Z7WY.js.map +0 -7
- /package/packages/safe-js/dist/chunks/{chunk-VYUHL33E.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;
|
|
@@ -3,12 +3,14 @@ import { isSandboxDate } from "./date.js";
|
|
|
3
3
|
import { retainedAccessorClosures } from "./accessors.js";
|
|
4
4
|
import { getHostObjectMember, isGuestHostObject, isLiveCapability } from "./host-capabilities.js";
|
|
5
5
|
import { boxedValue, isSandboxBox } from "./boxed.js";
|
|
6
|
-
import { isSandboxClosure, isSandboxGenerator, isSandboxMap, isSandboxPromise, isSandboxRegex, isSandboxSet } from "./values.js";
|
|
6
|
+
import { isSandboxClosure, isSandboxGenerator, isSandboxMap, isSandboxPromise, isSandboxRegex, getRegexProperties, isSandboxSet } from "./values.js";
|
|
7
7
|
const guestClosures = new WeakSet();
|
|
8
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)
|
|
@@ -160,8 +190,9 @@ export function getSandboxPropertyDescriptor(value, key, budget) {
|
|
|
160
190
|
let depth = 0;
|
|
161
191
|
while (typeof current === "object" &&
|
|
162
192
|
current !== null &&
|
|
163
|
-
(Array.isArray(current) || isSandboxDate(current) || isPrototypeRecord(current))) {
|
|
164
|
-
const properties = isGuestClosure(current) ? getGuestFunctionProperties(current)
|
|
193
|
+
(Array.isArray(current) || isSandboxDate(current) || isSandboxRegex(current) || isPrototypeRecord(current))) {
|
|
194
|
+
const properties = isGuestClosure(current) ? getGuestFunctionProperties(current)
|
|
195
|
+
: isSandboxRegex(current) ? getRegexProperties(current) : current;
|
|
165
196
|
const descriptor = properties === undefined ? undefined : Object.getOwnPropertyDescriptor(properties, key);
|
|
166
197
|
if (descriptor !== undefined)
|
|
167
198
|
return descriptor;
|
|
@@ -179,6 +210,8 @@ export function getSandboxDataProperty(value, key, budget) {
|
|
|
179
210
|
while (typeof current === "object" && current !== null) {
|
|
180
211
|
if (isGuestHostObject(current))
|
|
181
212
|
return typeof key === "symbol" ? undefined : getHostObjectMember(current, String(key));
|
|
213
|
+
if (isSandboxRegex(current))
|
|
214
|
+
return Object.getOwnPropertyDescriptor(getRegexProperties(current), key)?.value;
|
|
182
215
|
if (isGuestClosure(current)) {
|
|
183
216
|
const entry = getGuestFunctionProperty(current, key);
|
|
184
217
|
if (entry !== undefined || Object.hasOwn(current.properties ?? {}, key))
|
|
@@ -210,13 +243,13 @@ export function setSandboxPrototype(value, prototype, budget) {
|
|
|
210
243
|
if (budget !== undefined && intrinsicPrototypes.get(budget) === value && prototype !== null) {
|
|
211
244
|
throw new TypeError("Object.prototype has an immutable null prototype.");
|
|
212
245
|
}
|
|
213
|
-
if ((!Array.isArray(value) && !isPrototypeRecord(value)) ||
|
|
246
|
+
if ((!Array.isArray(value) && !isSandboxRegex(value) && !isPrototypeRecord(value)) ||
|
|
214
247
|
(prototype !== null && !Array.isArray(prototype) && !isPrototypeRecord(prototype))) {
|
|
215
248
|
throw new TypeError("Prototype links require ordinary sandbox objects, arrays, or guest functions.");
|
|
216
249
|
}
|
|
217
250
|
if (prototypes.has(value) && getSandboxPrototype(value, budget) === prototype)
|
|
218
251
|
return;
|
|
219
|
-
if (!Object.isExtensible(isGuestClosure(value) ? materializeFunctionProperties(value) : value)) {
|
|
252
|
+
if (!Object.isExtensible(isGuestClosure(value) ? materializeFunctionProperties(value) : isSandboxRegex(value) ? getRegexProperties(value) : value)) {
|
|
220
253
|
throw new TypeError("Cannot change the prototype of a non-extensible object.");
|
|
221
254
|
}
|
|
222
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,5 +1,7 @@
|
|
|
1
|
+
export { getRegexProperties } from "./regexp-properties.js";
|
|
1
2
|
import { sandboxMapBrand, sandboxSetBrand } from "./collection-brands.js";
|
|
2
3
|
import { type SandboxCollectionIterator } from "./collection-iterator.js";
|
|
4
|
+
import { type SandboxRegExpIterator } from "./regexp-iterator.js";
|
|
3
5
|
import type { Budget, CompileTicket } from "./budget.js";
|
|
4
6
|
import { CompileScope } from "./regex/compile-guard.js";
|
|
5
7
|
import type { GeneratorChannel } from "./generator.js";
|
|
@@ -14,7 +16,7 @@ declare const sandboxRegexBrand: unique symbol;
|
|
|
14
16
|
declare const sandboxRegexPattern: unique symbol;
|
|
15
17
|
declare const sandboxRetainedValues: unique symbol;
|
|
16
18
|
export type SandboxPrimitive = string | number | boolean | symbol | null | undefined;
|
|
17
|
-
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;
|
|
18
20
|
export type SandboxObject = {
|
|
19
21
|
[key: string]: SandboxValue;
|
|
20
22
|
[key: symbol]: SandboxValue;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { bindOtelSpan, getBoundOtelSpan } from "../observability/otel.js";
|
|
2
2
|
import { internalSymbols } from "./internal-symbols.js";
|
|
3
|
+
import { getRegexProperties, regexGuestProperties } from "./regexp-properties.js";
|
|
4
|
+
export { getRegexProperties } from "./regexp-properties.js";
|
|
3
5
|
import { retainedAccessorClosures } from "./accessors.js";
|
|
4
6
|
import { isSandboxMap, isSandboxSet, sandboxMapBrand, sandboxSetBrand } from "./collection-brands.js";
|
|
5
7
|
import { collectionIteratorState, isSandboxCollectionIterator, restoreSandboxCollectionIterator, snapshotCollectionIterator } from "./collection-iterator.js";
|
|
8
|
+
import { regexpIteratorState, isSandboxRegExpIterator, restoreSandboxRegExpIterator } from "./regexp-iterator.js";
|
|
6
9
|
import { copyNativeDate, dateDataProperties, exportDate, isSandboxDate } from "./date.js";
|
|
7
10
|
import { boxedDataProperties, boxedValue, createSandboxBox, isSandboxBox, nativeBoxedValue } from "./boxed.js";
|
|
8
11
|
import { getHostObjectKeys, getHostObjectMember, hasHostObjectMember, measureHostObjectData, isGuestHostObject, isLiveCapability } from "./host-capabilities.js";
|
|
@@ -98,6 +101,8 @@ export function ownEnumerableSandboxEntries(value, excludedKeys) {
|
|
|
98
101
|
let entries;
|
|
99
102
|
if (isGuestClosure(value))
|
|
100
103
|
entries = Object.entries(value.properties ?? {});
|
|
104
|
+
else if (isSandboxRegex(value))
|
|
105
|
+
entries = Object.entries(getRegexProperties(value));
|
|
101
106
|
else if (isSandboxClosure(value) || isSandboxGenerator(value) || isSandboxMap(value) || isSandboxSet(value) || isSandboxPromise(value) || isSandboxRegex(value))
|
|
102
107
|
return [];
|
|
103
108
|
else
|
|
@@ -111,13 +116,15 @@ export function ownSandboxSymbolKeys(value) {
|
|
|
111
116
|
return [];
|
|
112
117
|
if (isSandboxClosure(value))
|
|
113
118
|
value = value.properties ?? {};
|
|
119
|
+
else if (isSandboxRegex(value))
|
|
120
|
+
value = getRegexProperties(value);
|
|
114
121
|
else if (isSandboxGenerator(value) || isSandboxMap(value) || isSandboxSet(value) || isSandboxPromise(value) || isSandboxRegex(value))
|
|
115
122
|
return [];
|
|
116
123
|
return Object.getOwnPropertySymbols(Object(value)).filter(key => !internalSymbols.has(key));
|
|
117
124
|
}
|
|
118
125
|
export function ownEnumerableSandboxKeys(value, includeSymbols = false) {
|
|
119
126
|
if (includeSymbols) {
|
|
120
|
-
const properties = isSandboxClosure(value) ? value.properties ?? {} : Object(value);
|
|
127
|
+
const properties = isSandboxClosure(value) ? value.properties ?? {} : isSandboxRegex(value) ? getRegexProperties(value) : Object(value);
|
|
121
128
|
return [...ownEnumerableSandboxKeys(value), ...ownSandboxSymbolKeys(value).filter(key => Object.getOwnPropertyDescriptor(properties, key)?.enumerable === true)];
|
|
122
129
|
}
|
|
123
130
|
if (isGuestHostObject(value))
|
|
@@ -126,6 +133,8 @@ export function ownEnumerableSandboxKeys(value, includeSymbols = false) {
|
|
|
126
133
|
throw new TypeError("Cannot convert undefined or null to object.");
|
|
127
134
|
if (isGuestClosure(value))
|
|
128
135
|
return Object.keys(value.properties ?? {});
|
|
136
|
+
if (isSandboxRegex(value))
|
|
137
|
+
return Object.keys(getRegexProperties(value));
|
|
129
138
|
if (isSandboxClosure(value) || isSandboxGenerator(value) || isSandboxMap(value) || isSandboxSet(value) || isSandboxPromise(value) || isSandboxRegex(value))
|
|
130
139
|
return [];
|
|
131
140
|
return Object.keys(Object(value));
|
|
@@ -218,6 +227,32 @@ export function createSandboxRegex(source, flags = "", lastIndex = 0, compilatio
|
|
|
218
227
|
}
|
|
219
228
|
const pattern = parseRegex(source, flags, compilation, 7 + source.length + flags.length);
|
|
220
229
|
const regex = { kind: "regex", source, flags, lastIndex };
|
|
230
|
+
const storage = Object.create(null);
|
|
231
|
+
Object.defineProperty(storage, "lastIndex", { value: lastIndex, writable: true });
|
|
232
|
+
const syncCursor = () => {
|
|
233
|
+
const descriptor = Object.getOwnPropertyDescriptor(regex, "lastIndex");
|
|
234
|
+
Object.defineProperty(storage, "lastIndex", { value: descriptor.value, writable: descriptor.writable });
|
|
235
|
+
};
|
|
236
|
+
const properties = new Proxy(storage, {
|
|
237
|
+
get: (target, key, receiver) => key === "lastIndex" ? regex.lastIndex : Reflect.get(target, key, receiver),
|
|
238
|
+
set: (target, key, value, receiver) => key === "lastIndex"
|
|
239
|
+
? Reflect.set(regex, key, value) : Reflect.set(target, key, value, receiver),
|
|
240
|
+
getOwnPropertyDescriptor(target, key) {
|
|
241
|
+
if (key === "lastIndex")
|
|
242
|
+
syncCursor();
|
|
243
|
+
return Object.getOwnPropertyDescriptor(target, key);
|
|
244
|
+
},
|
|
245
|
+
defineProperty(target, key, descriptor) {
|
|
246
|
+
if (key !== "lastIndex")
|
|
247
|
+
return Reflect.defineProperty(target, key, descriptor);
|
|
248
|
+
syncCursor();
|
|
249
|
+
if (!Reflect.defineProperty(target, key, descriptor))
|
|
250
|
+
return false;
|
|
251
|
+
const cursor = Object.getOwnPropertyDescriptor(target, key);
|
|
252
|
+
return Reflect.defineProperty(regex, key, { value: cursor.value, writable: cursor.writable });
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
regexGuestProperties.set(regex, properties);
|
|
221
256
|
Object.defineProperties(regex, {
|
|
222
257
|
[sandboxRegexBrand]: { value: true },
|
|
223
258
|
[sandboxRegexPattern]: { value: pattern }
|
|
@@ -366,6 +401,17 @@ export function measureSandboxData(values, options = {}) {
|
|
|
366
401
|
}
|
|
367
402
|
return;
|
|
368
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
|
+
}
|
|
369
415
|
if (isSandboxCollectionIterator(value)) {
|
|
370
416
|
visit(collectionIteratorState(value).collection, depth + 1);
|
|
371
417
|
for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(value))) {
|
|
@@ -424,6 +470,19 @@ export function measureSandboxData(values, options = {}) {
|
|
|
424
470
|
if (compiled.ticket !== undefined)
|
|
425
471
|
options.compileTickets?.add(compiled.ticket);
|
|
426
472
|
visit(lastIndex, depth + 1);
|
|
473
|
+
for (const key of Reflect.ownKeys(getRegexProperties(value))) {
|
|
474
|
+
if (key === "lastIndex")
|
|
475
|
+
continue;
|
|
476
|
+
const descriptor = Object.getOwnPropertyDescriptor(getRegexProperties(value), key);
|
|
477
|
+
usage += 1 + (typeof key === "string" ? key.length : 0);
|
|
478
|
+
if (typeof key === "symbol")
|
|
479
|
+
visit(key, depth + 1);
|
|
480
|
+
if ("value" in descriptor)
|
|
481
|
+
visit(descriptor.value, depth + 1);
|
|
482
|
+
else
|
|
483
|
+
for (const closure of retainedAccessorClosures(descriptor))
|
|
484
|
+
visit(closure, depth + 1);
|
|
485
|
+
}
|
|
427
486
|
return;
|
|
428
487
|
}
|
|
429
488
|
if (isSandboxArguments(value)) {
|
|
@@ -491,7 +550,7 @@ function captureRegexData(value) {
|
|
|
491
550
|
typeof flags.value !== "string") {
|
|
492
551
|
throw new TypeError("Invalid sandbox RegExp source or flags: expected own string data properties.");
|
|
493
552
|
}
|
|
494
|
-
const cursor = Object.getOwnPropertyDescriptor(value, "lastIndex");
|
|
553
|
+
const cursor = Object.getOwnPropertyDescriptor(regexGuestProperties.get(value) ?? value, "lastIndex");
|
|
495
554
|
if (cursor === undefined || !("value" in cursor)) {
|
|
496
555
|
throw new TypeError("Invalid sandbox RegExp lastIndex: expected an own data property.");
|
|
497
556
|
}
|
|
@@ -519,6 +578,21 @@ function copyToSandbox(value, state, path = "<root>", cloneSandboxCollections =
|
|
|
519
578
|
state.seen.set(value, copy);
|
|
520
579
|
if (!state.resetRegexLastIndex)
|
|
521
580
|
copy.lastIndex = copyToSandbox(value.lastIndex, state, `${path}.lastIndex`, true, depth + 1);
|
|
581
|
+
if (!state.structuredClone) {
|
|
582
|
+
const properties = getRegexProperties(value);
|
|
583
|
+
for (const key of Reflect.ownKeys(properties)) {
|
|
584
|
+
const descriptor = Object.getOwnPropertyDescriptor(properties, key);
|
|
585
|
+
if (!("value" in descriptor))
|
|
586
|
+
throw new TypeError("RegExp accessor properties cannot be copied as data.");
|
|
587
|
+
Object.defineProperty(getRegexProperties(copy), key, {
|
|
588
|
+
...descriptor,
|
|
589
|
+
value: key === "lastIndex" && state.resetRegexLastIndex ? 0
|
|
590
|
+
: copyToSandbox(descriptor.value, state, `${path}.${String(key)}`, true, depth + 1)
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
if (!Object.isExtensible(properties))
|
|
594
|
+
Object.preventExtensions(getRegexProperties(copy));
|
|
595
|
+
}
|
|
522
596
|
return copy;
|
|
523
597
|
}
|
|
524
598
|
if (isSandboxClosure(value) ||
|
|
@@ -526,6 +600,26 @@ function copyToSandbox(value, state, path = "<root>", cloneSandboxCollections =
|
|
|
526
600
|
isSandboxPromise(value)) {
|
|
527
601
|
return value;
|
|
528
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
|
+
}
|
|
529
623
|
if (isSandboxCollectionIterator(value)) {
|
|
530
624
|
if (hasGuestObjectState(value))
|
|
531
625
|
throw new TypeError("Guest prototype links and custom descriptors cannot be copied as data.");
|
|
@@ -745,6 +839,18 @@ function copyFromSandbox(value, state, path = "<root>", options, depth = 0) {
|
|
|
745
839
|
const regex = new RegExp(source, flags);
|
|
746
840
|
state.seen.set(value, regex);
|
|
747
841
|
Reflect.set(regex, "lastIndex", copyFromSandbox(lastIndex, state, `${path}.lastIndex`, options, depth + 1));
|
|
842
|
+
const properties = regexGuestProperties.get(value);
|
|
843
|
+
if (properties !== undefined) {
|
|
844
|
+
for (const key of Reflect.ownKeys(properties)) {
|
|
845
|
+
const descriptor = Object.getOwnPropertyDescriptor(properties, key);
|
|
846
|
+
if (!("value" in descriptor))
|
|
847
|
+
throw new TypeError("RegExp accessor properties cannot be copied as data.");
|
|
848
|
+
Object.defineProperty(regex, key, { ...descriptor,
|
|
849
|
+
value: copyFromSandbox(descriptor.value, state, `${path}.${String(key)}`, options, depth + 1) });
|
|
850
|
+
}
|
|
851
|
+
if (!Object.isExtensible(properties))
|
|
852
|
+
Object.preventExtensions(regex);
|
|
853
|
+
}
|
|
748
854
|
guard.retainScratch();
|
|
749
855
|
return regex;
|
|
750
856
|
}
|
|
@@ -816,6 +922,9 @@ function copyFromSandbox(value, state, path = "<root>", options, depth = 0) {
|
|
|
816
922
|
if (isSandboxCollectionIterator(value)) {
|
|
817
923
|
throw new TypeError("Sandbox collection iterators cannot cross into host values.");
|
|
818
924
|
}
|
|
925
|
+
if (isSandboxRegExpIterator(value)) {
|
|
926
|
+
throw new TypeError("Sandbox RegExp iterators cannot cross into host values.");
|
|
927
|
+
}
|
|
819
928
|
if (isSandboxRegex(value)) {
|
|
820
929
|
throw new TypeError("Invalid sandbox RegExp brand.");
|
|
821
930
|
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
export const DUMP_FORMAT_VERSION = 1;
|
|
2
|
+
import { getRegexProperties, isSandboxRegex } from "../interp/values.js";
|
|
3
|
+
import { isSandboxRegExpIterator, regexpIteratorState } from "../interp/regexp-iterator.js";
|
|
4
|
+
import { hasCustomRegexProperties, serializeRegexProperties } from "./regexp-properties.js";
|
|
2
5
|
export const EXECUTION_SEMANTICS = "jobs-v8";
|
|
3
6
|
import { assertSnapshotGraphDepth } from "../graph-depth.js";
|
|
4
7
|
import { hasGuestObjectState } from "../interp/object-model.js";
|
|
@@ -79,7 +82,7 @@ function serializeDumpValue(value, path, state) {
|
|
|
79
82
|
if (hasGuestObjectState(value)) {
|
|
80
83
|
throw new TypeError("Guest function properties and prototype links cannot be serialized.");
|
|
81
84
|
}
|
|
82
|
-
if (isSandboxBox(value) || isSandboxDate(value) || isFloat32Array(value))
|
|
85
|
+
if (isSandboxRegExpIterator(value) || (isSandboxRegex(value) && hasCustomRegexProperties(value)) || isSandboxBox(value) || isSandboxDate(value) || isFloat32Array(value))
|
|
83
86
|
return serializeHeapReference(value, path, state);
|
|
84
87
|
if (Array.isArray(value)) {
|
|
85
88
|
const reference = serializeHeapReference(value, path, state);
|
|
@@ -104,7 +107,39 @@ function serializeHeapReference(value, path, state) {
|
|
|
104
107
|
}
|
|
105
108
|
if (!state.serializedHeapIds.has(id)) {
|
|
106
109
|
state.serializedHeapIds.add(id);
|
|
107
|
-
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)) {
|
|
133
|
+
const encode = (entry) => {
|
|
134
|
+
const serialized = serializeDumpValue(entry, `${path}.<regex-property>`, state);
|
|
135
|
+
if (serialized === SKIP_VALUE)
|
|
136
|
+
throw new TypeError("Unsupported RegExp property in public dump.");
|
|
137
|
+
return serialized;
|
|
138
|
+
};
|
|
139
|
+
state.heap[String(id)] = { kind: "regex-object", source: value.source, flags: value.flags,
|
|
140
|
+
lastIndex: encode(value.lastIndex), ...serializeRegexProperties(value, encode) };
|
|
141
|
+
}
|
|
142
|
+
else if (isSandboxBox(value)) {
|
|
108
143
|
state.heap[String(id)] = encodeBoxedData(value, (entry, key) => {
|
|
109
144
|
if (Object.is(entry, -0))
|
|
110
145
|
return { kind: "number", value: "-0" };
|
|
@@ -194,6 +229,8 @@ function indexHeapContainers(snapshot) {
|
|
|
194
229
|
stat.cyclic ||
|
|
195
230
|
ownSerializableSymbolKeys(value).length > 0 ||
|
|
196
231
|
isSandboxBox(value) ||
|
|
232
|
+
isSandboxRegExpIterator(value) ||
|
|
233
|
+
(isSandboxRegex(value) && hasCustomRegexProperties(value)) ||
|
|
197
234
|
isSandboxDate(value) ||
|
|
198
235
|
isFloat32Array(value) ||
|
|
199
236
|
(Array.isArray(value) && requiresArrayEntries(value)) ||
|
|
@@ -231,13 +268,18 @@ function collectContainerStats(value, stats, ancestors) {
|
|
|
231
268
|
}
|
|
232
269
|
stat.expanded = true;
|
|
233
270
|
ancestors.add(value);
|
|
234
|
-
const entries =
|
|
235
|
-
?
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
271
|
+
const entries = isSandboxRegex(value)
|
|
272
|
+
? Reflect.ownKeys(getRegexProperties(value)).flatMap(key => {
|
|
273
|
+
const descriptor = Object.getOwnPropertyDescriptor(getRegexProperties(value), key);
|
|
274
|
+
return "value" in descriptor ? [descriptor.value] : [];
|
|
275
|
+
})
|
|
276
|
+
: isSandboxDate(value)
|
|
277
|
+
? dateDataProperties(value).flatMap(([key, descriptor]) => typeof key === "string" ? [descriptor.value] : [])
|
|
278
|
+
: isSandboxBox(value)
|
|
279
|
+
? boxedDataProperties(value).map(([, descriptor]) => descriptor.value)
|
|
280
|
+
: isSandboxArguments(value)
|
|
281
|
+
? getSandboxArgumentEntries(value).map(([, entry]) => entry)
|
|
282
|
+
: getEnumerableDataValues(value);
|
|
241
283
|
for (const entry of entries) {
|
|
242
284
|
collectContainerStats(entry, stats, ancestors);
|
|
243
285
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type SandboxRegex } from "../interp/values.js";
|
|
2
|
+
import { type SerializedSymbolProperty } from "./symbols.js";
|
|
3
|
+
type DataProperty<T> = {
|
|
4
|
+
value: T;
|
|
5
|
+
enumerable: boolean;
|
|
6
|
+
writable: boolean;
|
|
7
|
+
configurable: boolean;
|
|
8
|
+
};
|
|
9
|
+
export type RegexPropertyData<T> = {
|
|
10
|
+
properties?: Record<string, DataProperty<T>>;
|
|
11
|
+
symbolEntries?: Array<SerializedSymbolProperty<T>>;
|
|
12
|
+
extensible?: boolean;
|
|
13
|
+
};
|
|
14
|
+
export declare function hasCustomRegexProperties(value: SandboxRegex): boolean;
|
|
15
|
+
export declare function serializeRegexProperties<T>(value: SandboxRegex, encode: (entry: unknown) => T): RegexPropertyData<T>;
|
|
16
|
+
export declare function validateRegexProperties(data: RegexPropertyData<unknown>): void;
|
|
17
|
+
export declare function restoreRegexProperties<T>(value: SandboxRegex, data: RegexPropertyData<T>, decode: (entry: T) => unknown): void;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { getRegexProperties } from "../interp/values.js";
|
|
2
|
+
import { restoreSymbolProperties, serializeSymbolProperties } from "./symbols.js";
|
|
3
|
+
export function hasCustomRegexProperties(value) {
|
|
4
|
+
const properties = getRegexProperties(value);
|
|
5
|
+
return Reflect.ownKeys(properties).length !== 1 || !Object.isExtensible(properties) ||
|
|
6
|
+
Object.getOwnPropertyDescriptor(properties, "lastIndex")?.writable !== true;
|
|
7
|
+
}
|
|
8
|
+
export function serializeRegexProperties(value, encode) {
|
|
9
|
+
if (!hasCustomRegexProperties(value))
|
|
10
|
+
return {};
|
|
11
|
+
const source = getRegexProperties(value);
|
|
12
|
+
const properties = Object.create(null);
|
|
13
|
+
for (const key of Object.getOwnPropertyNames(source)) {
|
|
14
|
+
const descriptor = Object.getOwnPropertyDescriptor(source, key);
|
|
15
|
+
if (!("value" in descriptor))
|
|
16
|
+
throw new TypeError("RegExp accessor properties cannot be serialized as data.");
|
|
17
|
+
properties[key] = { value: encode(descriptor.value), enumerable: descriptor.enumerable === true,
|
|
18
|
+
configurable: descriptor.configurable === true, writable: descriptor.writable === true };
|
|
19
|
+
}
|
|
20
|
+
const symbolEntries = serializeSymbolProperties(source, encode);
|
|
21
|
+
return { properties, ...(symbolEntries.length === 0 ? {} : { symbolEntries }),
|
|
22
|
+
...(Object.isExtensible(source) ? {} : { extensible: false }) };
|
|
23
|
+
}
|
|
24
|
+
export function validateRegexProperties(data) {
|
|
25
|
+
const descriptor = (value) => {
|
|
26
|
+
if (typeof value !== "object" || value === null || Array.isArray(value) ||
|
|
27
|
+
!Object.hasOwn(value, "value") ||
|
|
28
|
+
!["enumerable", "configurable", "writable"].every(key => Object.hasOwn(value, key) && typeof value[key] === "boolean") ||
|
|
29
|
+
Object.keys(value).some(key => !["value", "enumerable", "configurable", "writable"].includes(key)))
|
|
30
|
+
throw new TypeError("Invalid RegExp data property descriptor.");
|
|
31
|
+
};
|
|
32
|
+
if (data.extensible !== undefined && typeof data.extensible !== "boolean")
|
|
33
|
+
throw new TypeError("Invalid RegExp extensibility.");
|
|
34
|
+
if (data.properties !== undefined) {
|
|
35
|
+
if (typeof data.properties !== "object" || data.properties === null || Array.isArray(data.properties))
|
|
36
|
+
throw new TypeError("Invalid RegExp property data.");
|
|
37
|
+
for (const entry of Object.values(data.properties))
|
|
38
|
+
descriptor(entry);
|
|
39
|
+
}
|
|
40
|
+
if (data.symbolEntries !== undefined) {
|
|
41
|
+
if (!Array.isArray(data.symbolEntries))
|
|
42
|
+
throw new TypeError("Invalid RegExp symbol properties.");
|
|
43
|
+
for (const entry of data.symbolEntries) {
|
|
44
|
+
if (!Array.isArray(entry) || entry.length !== 2)
|
|
45
|
+
throw new TypeError("Invalid RegExp symbol property.");
|
|
46
|
+
descriptor(entry[1]);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export function restoreRegexProperties(value, data, decode) {
|
|
51
|
+
validateRegexProperties(data);
|
|
52
|
+
const properties = getRegexProperties(value);
|
|
53
|
+
for (const [key, descriptor] of Object.entries(data.properties ?? {}))
|
|
54
|
+
Object.defineProperty(properties, key, { ...descriptor, value: decode(descriptor.value) });
|
|
55
|
+
restoreSymbolProperties(properties, data.symbolEntries, decode);
|
|
56
|
+
if (data.extensible === false)
|
|
57
|
+
Object.preventExtensions(properties);
|
|
58
|
+
}
|