poe-code 14.0.72 → 14.0.73
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 +850 -638
- 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-I2Z37MKZ.js} +2 -2
- package/packages/safe-js/dist/chunks/{chunk-6UY4Z7WY.js → chunk-XKCTB5FR.js} +351 -158
- package/packages/safe-js/dist/chunks/chunk-XKCTB5FR.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 +7 -0
- package/packages/safe-js/dist/index.js +2 -2
- package/packages/safe-js/dist/interp/globals/object-array.js +9 -7
- package/packages/safe-js/dist/interp/globals/object.js +2 -2
- package/packages/safe-js/dist/interp/interpreter.js +7 -7
- package/packages/safe-js/dist/interp/methods/regex.d.ts +1 -1
- package/packages/safe-js/dist/interp/methods/regex.js +6 -3
- package/packages/safe-js/dist/interp/methods/string.js +57 -18
- package/packages/safe-js/dist/interp/object-model.js +6 -3
- 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/values.d.ts +1 -0
- package/packages/safe-js/dist/interp/values.js +76 -2
- package/packages/safe-js/dist/snapshot/dump-format.js +27 -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 +3 -2
- package/packages/safe-js/dist/snapshot/replay-data.js +4 -1
- package/packages/safe-js/dist/snapshot/restore.js +2 -0
- package/packages/safe-js/dist/snapshot/serialize.d.ts +3 -2
- package/packages/safe-js/dist/snapshot/serialize.js +23 -16
- package/packages/safe-js/dist/snapshot/validation.js +12 -1
- package/packages/safe-js/dist/chunks/chunk-6UY4Z7WY.js.map +0 -7
- /package/packages/safe-js/dist/chunks/{chunk-VYUHL33E.js.map → chunk-I2Z37MKZ.js.map} +0 -0
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
resolveFsConfig,
|
|
23
23
|
splitFrontmatter,
|
|
24
24
|
withBrokenPipeGuard
|
|
25
|
-
} from "./chunks/chunk-
|
|
25
|
+
} from "./chunks/chunk-I2Z37MKZ.js";
|
|
26
26
|
import {
|
|
27
27
|
Budget,
|
|
28
28
|
SandboxError,
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
replaceErrorStack,
|
|
35
35
|
restore,
|
|
36
36
|
run
|
|
37
|
-
} from "./chunks/chunk-
|
|
37
|
+
} from "./chunks/chunk-XKCTB5FR.js";
|
|
38
38
|
import "./chunks/chunk-ZWJ5BJUI.js";
|
|
39
39
|
import "./chunks/chunk-3YTQEPZI.js";
|
|
40
40
|
import "./chunks/chunk-4YIDX44G.js";
|
|
@@ -4,6 +4,7 @@ import { getSandboxArgumentEntries, isSandboxArguments } from "./interp/argument
|
|
|
4
4
|
import { collectionIteratorState, isSandboxCollectionIterator } from "./interp/collection-iterator.js";
|
|
5
5
|
import { isSandboxMap, isSandboxSet } from "./interp/collection-brands.js";
|
|
6
6
|
import { boxedDataProperties, isSandboxBox } from "./interp/boxed.js";
|
|
7
|
+
import { regexGuestProperties } from "./interp/regexp-properties.js";
|
|
7
8
|
export const MAX_DATA_DEPTH = 1_024;
|
|
8
9
|
export class SnapshotBudgetError extends Error {
|
|
9
10
|
code = "budgetExceeded";
|
|
@@ -64,6 +65,12 @@ function walkGraphDepth(root, rootPath, assertDepth) {
|
|
|
64
65
|
}
|
|
65
66
|
}
|
|
66
67
|
function graphEntries(value) {
|
|
68
|
+
const properties = regexGuestProperties.get(value);
|
|
69
|
+
if (properties !== undefined)
|
|
70
|
+
return Reflect.ownKeys(properties).flatMap(key => {
|
|
71
|
+
const descriptor = Object.getOwnPropertyDescriptor(properties, key);
|
|
72
|
+
return "value" in descriptor ? [[`.${String(key)}`, descriptor.value]] : [];
|
|
73
|
+
});
|
|
67
74
|
if (isSandboxBox(value))
|
|
68
75
|
return boxedDataProperties(value).map(([key, descriptor]) => [`.${key}`, descriptor.value]);
|
|
69
76
|
if (isSandboxArguments(value)) {
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
runWithSpawnUsageAccumulator,
|
|
27
27
|
splitFrontmatter,
|
|
28
28
|
supportsSpawnMode
|
|
29
|
-
} from "./chunks/chunk-
|
|
29
|
+
} from "./chunks/chunk-I2Z37MKZ.js";
|
|
30
30
|
import {
|
|
31
31
|
Budget,
|
|
32
32
|
FileSnapshotBackend,
|
|
@@ -50,7 +50,7 @@ import {
|
|
|
50
50
|
registerPendingHostCallPolicy,
|
|
51
51
|
restore,
|
|
52
52
|
run
|
|
53
|
-
} from "./chunks/chunk-
|
|
53
|
+
} from "./chunks/chunk-XKCTB5FR.js";
|
|
54
54
|
import "./chunks/chunk-ZWJ5BJUI.js";
|
|
55
55
|
import "./chunks/chunk-3YTQEPZI.js";
|
|
56
56
|
import "./chunks/chunk-4YIDX44G.js";
|
|
@@ -17,7 +17,7 @@ import { toPropertyKey } from "../property-key.js";
|
|
|
17
17
|
import { createNumericParsers } from "./numeric-parsers.js";
|
|
18
18
|
import { createPrimitiveConstructor } from "./primitives.js";
|
|
19
19
|
import { getSandboxDataProperty, getSandboxPropertyDescriptor, getSandboxPrototype, isGuestClosure, markDescriptorObject, materializeFunctionProperties, setSandboxPrototype } from "../object-model.js";
|
|
20
|
-
import { allocateProducedSandboxValue, createSandboxClosure, deepCopyToSandbox, defineOwnDataProperty, isSandboxClosure, isSandboxGenerator, isSandboxMap, isSandboxPromise, isSandboxRegex, isSandboxSet, measureSandboxData, ownEnumerableSandboxKeys as getOwnEnumerableKeys, ownSandboxSymbolKeys, ownEnumerableSandboxEntries as getDirectEntries } from "../values.js";
|
|
20
|
+
import { allocateProducedSandboxValue, createSandboxClosure, deepCopyToSandbox, defineOwnDataProperty, isSandboxClosure, isSandboxGenerator, isSandboxMap, isSandboxPromise, isSandboxRegex, getRegexProperties, isSandboxSet, measureSandboxData, ownEnumerableSandboxKeys as getOwnEnumerableKeys, ownSandboxSymbolKeys, ownEnumerableSandboxEntries as getDirectEntries } from "../values.js";
|
|
21
21
|
export function createObjectArrayGlobals(options) {
|
|
22
22
|
return {
|
|
23
23
|
Object: createObjectGlobal({
|
|
@@ -171,14 +171,14 @@ export function createObjectArrayGlobals(options) {
|
|
|
171
171
|
call: ([value]) => {
|
|
172
172
|
if (isGuestHostObject(value))
|
|
173
173
|
throw new TypeError("Live host objects cannot be made non-extensible.");
|
|
174
|
-
Object.preventExtensions(isGuestClosure(value) ? materializeFunctionProperties(value) : value);
|
|
174
|
+
Object.preventExtensions(isGuestClosure(value) ? materializeFunctionProperties(value) : isSandboxRegex(value) ? getRegexProperties(value) : value);
|
|
175
175
|
return value;
|
|
176
176
|
},
|
|
177
177
|
name: "preventExtensions"
|
|
178
178
|
}),
|
|
179
179
|
isExtensible: createSandboxClosure({
|
|
180
180
|
sandbox: true,
|
|
181
|
-
call: ([value]) => Object.isExtensible(isGuestClosure(value) ? materializeFunctionProperties(value) : value),
|
|
181
|
+
call: ([value]) => Object.isExtensible(isGuestClosure(value) ? materializeFunctionProperties(value) : isSandboxRegex(value) ? getRegexProperties(value) : value),
|
|
182
182
|
name: "isExtensible"
|
|
183
183
|
}),
|
|
184
184
|
seal: createSandboxClosure({
|
|
@@ -186,14 +186,14 @@ export function createObjectArrayGlobals(options) {
|
|
|
186
186
|
call: ([value]) => {
|
|
187
187
|
if (isGuestHostObject(value))
|
|
188
188
|
throw new TypeError("Live host objects cannot be sealed.");
|
|
189
|
-
Object.seal(isGuestClosure(value) ? materializeFunctionProperties(value) : value);
|
|
189
|
+
Object.seal(isGuestClosure(value) ? materializeFunctionProperties(value) : isSandboxRegex(value) ? getRegexProperties(value) : value);
|
|
190
190
|
return value;
|
|
191
191
|
},
|
|
192
192
|
name: "seal"
|
|
193
193
|
}),
|
|
194
194
|
isSealed: createSandboxClosure({
|
|
195
195
|
sandbox: true,
|
|
196
|
-
call: ([value]) => Object.isSealed(isGuestClosure(value) ? materializeFunctionProperties(value) : value),
|
|
196
|
+
call: ([value]) => Object.isSealed(isGuestClosure(value) ? materializeFunctionProperties(value) : isSandboxRegex(value) ? getRegexProperties(value) : value),
|
|
197
197
|
name: "isSealed"
|
|
198
198
|
}),
|
|
199
199
|
freeze: createSandboxClosure({
|
|
@@ -202,7 +202,7 @@ export function createObjectArrayGlobals(options) {
|
|
|
202
202
|
if (isGuestHostObject(value))
|
|
203
203
|
throw new TypeError("Live host objects cannot be frozen.");
|
|
204
204
|
if (typeof value === "object" && value !== null) {
|
|
205
|
-
Object.freeze(isGuestClosure(value) ? materializeFunctionProperties(value) : value);
|
|
205
|
+
Object.freeze(isGuestClosure(value) ? materializeFunctionProperties(value) : isSandboxRegex(value) ? getRegexProperties(value) : value);
|
|
206
206
|
}
|
|
207
207
|
return value;
|
|
208
208
|
},
|
|
@@ -210,7 +210,7 @@ export function createObjectArrayGlobals(options) {
|
|
|
210
210
|
}),
|
|
211
211
|
isFrozen: createSandboxClosure({
|
|
212
212
|
sandbox: true,
|
|
213
|
-
call: ([value]) => Object.isFrozen(isGuestClosure(value) ? materializeFunctionProperties(value) : value),
|
|
213
|
+
call: ([value]) => Object.isFrozen(isGuestClosure(value) ? materializeFunctionProperties(value) : isSandboxRegex(value) ? getRegexProperties(value) : value),
|
|
214
214
|
name: "isFrozen"
|
|
215
215
|
}),
|
|
216
216
|
assign: createSandboxClosure({
|
|
@@ -425,6 +425,8 @@ function assignSandboxValues(target, sources, budget, context) {
|
|
|
425
425
|
})();
|
|
426
426
|
}
|
|
427
427
|
function objectProperties(value, mutable = false) {
|
|
428
|
+
if (isSandboxRegex(value))
|
|
429
|
+
return getRegexProperties(value);
|
|
428
430
|
if (isSandboxDate(value)) {
|
|
429
431
|
return value;
|
|
430
432
|
}
|
|
@@ -9,7 +9,7 @@ import { hasHostObjectMember, isGuestHostObject } from "../host-capabilities.js"
|
|
|
9
9
|
import { collectionIteratorState, isSandboxCollectionIterator } from "../collection-iterator.js";
|
|
10
10
|
import { getSandboxPrototype, getSandboxPropertyDescriptor, hasExplicitSandboxPrototype, installObjectPrototype, isGuestClosure, markDescriptorObject, materializeFunctionProperties, setSandboxPrototype } from "../object-model.js";
|
|
11
11
|
import { toPropertyKey } from "../property-key.js";
|
|
12
|
-
import { createSandboxClosure, isSandboxClosure, isSandboxGenerator, isSandboxMap, isSandboxPromise, isSandboxRegex, isSandboxSet } from "../values.js";
|
|
12
|
+
import { createSandboxClosure, isSandboxClosure, isSandboxGenerator, isSandboxMap, isSandboxPromise, isSandboxRegex, getRegexProperties, isSandboxSet } from "../values.js";
|
|
13
13
|
import { measureSandboxData } from "../values.js";
|
|
14
14
|
export function createObjectGlobal(methods, budget) {
|
|
15
15
|
const construct = ([value]) => {
|
|
@@ -138,7 +138,7 @@ export function hasOwnSandboxProperty(value, key, enumerable) {
|
|
|
138
138
|
isSandboxGenerator(value))
|
|
139
139
|
return false;
|
|
140
140
|
else if (isSandboxRegex(value))
|
|
141
|
-
|
|
141
|
+
properties = getRegexProperties(value);
|
|
142
142
|
else
|
|
143
143
|
properties = Object(value);
|
|
144
144
|
const descriptor = Object.getOwnPropertyDescriptor(properties, key);
|
|
@@ -26,7 +26,7 @@ import { getPromiseMember, isSandboxPromiseConstructor } from "./promise.js";
|
|
|
26
26
|
import { acquireSandboxIterator, closeIterator, readIteratorResult } from "./iteration.js";
|
|
27
27
|
import { assertCollectionMutable } from "./running-state.js";
|
|
28
28
|
import { getGeneratorMember } from "./methods/generator.js";
|
|
29
|
-
import { getRegexMember,
|
|
29
|
+
import { getRegexMember, setRegexMember } from "./methods/regex.js";
|
|
30
30
|
import { bindPattern } from "./patterns.js";
|
|
31
31
|
import { callStringMethod, getStringMember, isStringMethodName, validateStringMethodArguments } from "./methods/string.js";
|
|
32
32
|
import { callSetMethod, getSetMember, isSetMethodName } from "./methods/set.js";
|
|
@@ -39,7 +39,7 @@ import { getFloat32Member, isFloat32ArrayConstructor, setFloat32Member } from ".
|
|
|
39
39
|
import { isFloat32Array } from "./float32.js";
|
|
40
40
|
import { dateString, dateTime, isSandboxDate } from "./date.js";
|
|
41
41
|
import { getDateMember, getDatePrototype, isDateConstructor } from "./globals/date.js";
|
|
42
|
-
import { createSandboxRegex, allocateProducedSandboxValue, ownEnumerableSandboxKeys, isSandboxClosure, isSandboxGenerator, isSandboxMap, isSandboxPromise, isSandboxRegex, isSandboxSet, reconcileCompiledValues } from "./values.js";
|
|
42
|
+
import { createSandboxRegex, allocateProducedSandboxValue, ownEnumerableSandboxKeys, isSandboxClosure, isSandboxGenerator, isSandboxMap, isSandboxPromise, isSandboxRegex, getRegexProperties, isSandboxSet, reconcileCompiledValues } from "./values.js";
|
|
43
43
|
import { Scope } from "./scope.js";
|
|
44
44
|
import { hoistVarDeclarations } from "./var-hoist.js";
|
|
45
45
|
const taggedTemplateRawArrays = new WeakMap();
|
|
@@ -1772,7 +1772,7 @@ async function evaluateDeleteExpression(node, context) {
|
|
|
1772
1772
|
}
|
|
1773
1773
|
throw new TypeError("Cannot delete properties of null or undefined.");
|
|
1774
1774
|
}
|
|
1775
|
-
if (!isIndexableSandboxValue(member.object)) {
|
|
1775
|
+
if (!isIndexableSandboxValue(member.object) && !isSandboxRegex(member.object)) {
|
|
1776
1776
|
throw new TypeError("Unary operator 'delete' requires a sandbox object property.");
|
|
1777
1777
|
}
|
|
1778
1778
|
const property = await toPropertyKey(member.property, context.budget, createCoercionContext(context));
|
|
@@ -2132,8 +2132,8 @@ async function evaluateMemberCallExpression(node, context) {
|
|
|
2132
2132
|
if (isSandboxPromise(member.object)) {
|
|
2133
2133
|
return evaluateResolvedCallExpression(node, getPromiseMember(member.property, context.budget), context, member.object);
|
|
2134
2134
|
}
|
|
2135
|
-
if (isSandboxRegex(member.object)
|
|
2136
|
-
return evaluateResolvedCallExpression(node,
|
|
2135
|
+
if (isSandboxRegex(member.object)) {
|
|
2136
|
+
return evaluateResolvedCallExpression(node, await getPropertyValue(member.object, member.property, context), context, member.object);
|
|
2137
2137
|
}
|
|
2138
2138
|
if (!isIndexableSandboxValue(member.object)) {
|
|
2139
2139
|
throw new TypeError("Attempted to read a property from a non-object value.");
|
|
@@ -2646,8 +2646,6 @@ export function setSandboxProperty(target, property, value, budget, checkInherit
|
|
|
2646
2646
|
return;
|
|
2647
2647
|
}
|
|
2648
2648
|
if (isSandboxRegex(target)) {
|
|
2649
|
-
if (typeof property === "symbol")
|
|
2650
|
-
throw new TypeError("RegExp symbol properties are not yet supported.");
|
|
2651
2649
|
setRegexMember(target, property, value);
|
|
2652
2650
|
return;
|
|
2653
2651
|
}
|
|
@@ -2714,6 +2712,8 @@ function deleteSandboxProperty(target, property) {
|
|
|
2714
2712
|
return deleteHostObjectMember(target, String(property));
|
|
2715
2713
|
if (isGuestClosure(target))
|
|
2716
2714
|
target = materializeFunctionProperties(target);
|
|
2715
|
+
if (isSandboxRegex(target))
|
|
2716
|
+
target = getRegexProperties(target);
|
|
2717
2717
|
if (Array.isArray(target)) {
|
|
2718
2718
|
assertCollectionMutable(target);
|
|
2719
2719
|
}
|
|
@@ -4,7 +4,7 @@ import type { Budget } from "../budget.js";
|
|
|
4
4
|
export type RegexMethodName = "exec" | "test";
|
|
5
5
|
export declare function isRegexMethodName(property: string | number): property is RegexMethodName;
|
|
6
6
|
export declare function getRegexMember(target: SandboxRegex, property: string | number, budget: Budget): SandboxValue | undefined;
|
|
7
|
-
export declare function setRegexMember(target: SandboxRegex, property:
|
|
7
|
+
export declare function setRegexMember(target: SandboxRegex, property: PropertyKey, value: SandboxValue): void;
|
|
8
8
|
export declare function callRegexMethod(target: SandboxValue, methodName: RegexMethodName, args: readonly SandboxValue[], budget: Budget, context?: SandboxCallContext): Promise<SandboxValue>;
|
|
9
9
|
export declare function executeRegex(target: SandboxRegex, input: string, lastIndex: number): RegexMatch | null;
|
|
10
10
|
export declare function toMatchArray(match: RegexMatch | null, input: string): SandboxValue;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createSandboxClosure, getSandboxRegexPattern, isSandboxClosure, isSandboxRegex } from "../values.js";
|
|
1
|
+
import { createSandboxClosure, getSandboxRegexPattern, getRegexProperties, isSandboxClosure, isSandboxRegex } from "../values.js";
|
|
2
2
|
import { matchRegex } from "../regex/engine.js";
|
|
3
3
|
import { invokeBuiltinClosure } from "../builtin-call.js";
|
|
4
4
|
import { getSandboxDataProperty } from "../object-model.js";
|
|
@@ -67,10 +67,13 @@ function escapeRegexSource(source, budget) {
|
|
|
67
67
|
return budget === undefined ? text : budget.allocateString(text);
|
|
68
68
|
}
|
|
69
69
|
export function setRegexMember(target, property, value) {
|
|
70
|
-
|
|
70
|
+
const properties = getRegexProperties(target);
|
|
71
|
+
if (!Object.hasOwn(properties, property) &&
|
|
72
|
+
(property === "source" || property === "flags" || Object.hasOwn(regexFlagProperties, property))) {
|
|
71
73
|
throw new TypeError(`RegExp#${String(property)} is not writable.`);
|
|
72
74
|
}
|
|
73
|
-
|
|
75
|
+
if (!Reflect.set(properties, property, value))
|
|
76
|
+
throw new TypeError(`RegExp#${String(property)} is not writable.`);
|
|
74
77
|
}
|
|
75
78
|
export async function callRegexMethod(target, methodName, args, budget, context) {
|
|
76
79
|
if (target === null || typeof target !== "object" || (methodName === "exec" && !isSandboxRegex(target))) {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { types } from "node:util";
|
|
1
2
|
import { invokeBuiltinClosure } from "../builtin-call.js";
|
|
2
3
|
import { CompileScope } from "../regex/compile-guard.js";
|
|
3
4
|
import { normalizeLastIndex } from "../regex/engine.js";
|
|
4
5
|
import { sandboxNumber, sandboxString } from "../string-coercion.js";
|
|
5
6
|
import { retainValues } from "../resources.js";
|
|
6
|
-
import { getSandboxDataProperty } from "../object-model.js";
|
|
7
|
+
import { getSandboxDataProperty, getSandboxPropertyDescriptor } from "../object-model.js";
|
|
7
8
|
import { createSandboxClosure, createSandboxRegex, deepCopyFromSandbox, isSandboxClosure, isSandboxRegex } from "../values.js";
|
|
8
9
|
import { executeRegex, toMatchArray } from "./regex.js";
|
|
9
10
|
const SPLIT_STRING_MESSAGE = "String#split only supports string separator values.";
|
|
@@ -91,8 +92,12 @@ export function callStringMethod(value, methodName, args, budget, callClosure =
|
|
|
91
92
|
: Promise.resolve(sandboxString(value, budget, context)).then(string => callStringMethodBody(string, methodName, args, budget, callClosure, parent, context));
|
|
92
93
|
const symbol = methodName === "match" ? Symbol.match
|
|
93
94
|
: methodName === "search" ? Symbol.search
|
|
94
|
-
: methodName === "
|
|
95
|
+
: methodName === "matchAll" ? Symbol.matchAll
|
|
96
|
+
: methodName === "replace" || methodName === "replaceAll" ? Symbol.replace
|
|
97
|
+
: methodName === "split" ? Symbol.split : undefined;
|
|
95
98
|
const pattern = args[0];
|
|
99
|
+
if (symbol !== undefined && types.isRegExp(pattern))
|
|
100
|
+
throw new TypeError(`String#${methodName} does not accept unbranded host RegExp values.`);
|
|
96
101
|
if (symbol === undefined || pattern === null || pattern === undefined)
|
|
97
102
|
return fallback();
|
|
98
103
|
const applyHook = (hook) => {
|
|
@@ -100,11 +105,37 @@ export function callStringMethod(value, methodName, args, budget, callClosure =
|
|
|
100
105
|
return fallback();
|
|
101
106
|
if (!isSandboxClosure(hook))
|
|
102
107
|
throw new TypeError(`String#${methodName} symbol hook must be callable.`);
|
|
103
|
-
return invokeBuiltinClosure(hook,
|
|
108
|
+
return invokeBuiltinClosure(hook, symbol === Symbol.split || symbol === Symbol.replace ? [value, args[1]] : [value], budget, context, pattern);
|
|
104
109
|
};
|
|
105
|
-
|
|
106
|
-
?
|
|
107
|
-
:
|
|
110
|
+
const readProperty = (key) => context?.getProperty !== undefined
|
|
111
|
+
? context.getProperty(pattern, key)
|
|
112
|
+
: key === "flags" && isSandboxRegex(pattern) && getSandboxPropertyDescriptor(pattern, key, budget) === undefined
|
|
113
|
+
? pattern.flags : getSandboxDataProperty(pattern, key, budget);
|
|
114
|
+
const dispatch = () => {
|
|
115
|
+
const hook = readProperty(symbol);
|
|
116
|
+
return hook instanceof Promise ? hook.then(applyHook) : applyHook(hook);
|
|
117
|
+
};
|
|
118
|
+
if ((methodName === "replaceAll" || methodName === "matchAll") &&
|
|
119
|
+
(typeof pattern === "object" || typeof pattern === "function")) {
|
|
120
|
+
const checkFlags = (flags) => {
|
|
121
|
+
const checkText = (text) => {
|
|
122
|
+
if (!text.includes("g"))
|
|
123
|
+
throw new TypeError(`String#${methodName} requires a global regex.`);
|
|
124
|
+
return dispatch();
|
|
125
|
+
};
|
|
126
|
+
const text = sandboxString(flags, budget, context);
|
|
127
|
+
return typeof text === "string" ? checkText(text) : text.then(checkText);
|
|
128
|
+
};
|
|
129
|
+
const checkMatch = (match) => {
|
|
130
|
+
if (!(match === undefined ? isSandboxRegex(pattern) : Boolean(match)))
|
|
131
|
+
return dispatch();
|
|
132
|
+
const flags = readProperty("flags");
|
|
133
|
+
return flags instanceof Promise ? flags.then(checkFlags) : checkFlags(flags);
|
|
134
|
+
};
|
|
135
|
+
const match = readProperty(Symbol.match);
|
|
136
|
+
return match instanceof Promise ? match.then(checkMatch) : checkMatch(match);
|
|
137
|
+
}
|
|
138
|
+
return dispatch();
|
|
108
139
|
}
|
|
109
140
|
function callStringMethodBody(value, methodName, args, budget, callClosure = async (closure, closureArgs) => await closure.call(closureArgs), parent, context) {
|
|
110
141
|
if (methodName === "concat" && args.some(argument => argument !== null && typeof argument === "object")) {
|
|
@@ -153,7 +184,7 @@ function callStringMethodBody(value, methodName, args, budget, callClosure = asy
|
|
|
153
184
|
const regex = args[0];
|
|
154
185
|
if (isSandboxRegex(regex) && regex.lastIndex !== null && typeof regex.lastIndex === "object" &&
|
|
155
186
|
((methodName === "match" && !regex.flags.includes("g")) ||
|
|
156
|
-
|
|
187
|
+
methodName === "matchAll")) {
|
|
157
188
|
return callStringRegexCursor(value, methodName, regex, budget, parent, context);
|
|
158
189
|
}
|
|
159
190
|
if ((methodName === "match" || methodName === "matchAll" || methodName === "search") && !isSandboxRegex(args[0])) {
|
|
@@ -283,15 +314,25 @@ async function callConcat(value, args, budget, context) {
|
|
|
283
314
|
function callReplaceLikeMethod(value, methodName, args, budget, callClosure, context) {
|
|
284
315
|
const search = args[0];
|
|
285
316
|
const replacement = args[1];
|
|
286
|
-
|
|
317
|
+
const useRegex = isSandboxRegex(search) && getSandboxPropertyDescriptor(search, Symbol.replace, budget) === undefined;
|
|
318
|
+
if ((!useRegex && typeof search !== "string") ||
|
|
287
319
|
(typeof replacement !== "string" && !isSandboxClosure(replacement))) {
|
|
288
|
-
|
|
320
|
+
return (async () => {
|
|
321
|
+
let normalizedSearch;
|
|
322
|
+
let normalizedReplacement;
|
|
323
|
+
const release = retainValues(budget, () => [normalizedSearch, normalizedReplacement]);
|
|
324
|
+
try {
|
|
325
|
+
normalizedSearch = useRegex ? search : await sandboxString(search, budget, context);
|
|
326
|
+
normalizedReplacement = isSandboxClosure(replacement) ? replacement : await sandboxString(replacement, budget, context);
|
|
327
|
+
return await callReplaceLikeMethod(value, methodName, [normalizedSearch, normalizedReplacement], budget, callClosure, context);
|
|
328
|
+
}
|
|
329
|
+
finally {
|
|
330
|
+
release();
|
|
331
|
+
}
|
|
332
|
+
})();
|
|
289
333
|
}
|
|
290
334
|
if (isSandboxRegex(search)) {
|
|
291
|
-
|
|
292
|
-
throw new TypeError("String#replaceAll requires a global regex.");
|
|
293
|
-
}
|
|
294
|
-
return replaceRegex(value, search, replacement, methodName === "replaceAll", budget, callClosure, context);
|
|
335
|
+
return replaceRegex(value, search, replacement, budget, callClosure, context);
|
|
295
336
|
}
|
|
296
337
|
if (typeof replacement === "string") {
|
|
297
338
|
return budget.allocateString(methodName === "replace"
|
|
@@ -300,7 +341,7 @@ function callReplaceLikeMethod(value, methodName, args, budget, callClosure, con
|
|
|
300
341
|
}
|
|
301
342
|
return replaceWithClosure(value, search, replacement, methodName === "replaceAll", budget, callClosure);
|
|
302
343
|
}
|
|
303
|
-
async function replaceRegex(value, regex, replacement,
|
|
344
|
+
async function replaceRegex(value, regex, replacement, budget, callClosure, context) {
|
|
304
345
|
if (regex.flags.includes("g"))
|
|
305
346
|
regex.lastIndex = 0;
|
|
306
347
|
const cursor = regex.lastIndex;
|
|
@@ -308,7 +349,7 @@ async function replaceRegex(value, regex, replacement, replaceAll, budget, callC
|
|
|
308
349
|
budget.setRetainedValues(retained, () => [value, regex, cursor, replacement]);
|
|
309
350
|
try {
|
|
310
351
|
const lastIndex = await sandboxNumber(cursor, budget, context);
|
|
311
|
-
const matches = collectRegexMatches(regex, value,
|
|
352
|
+
const matches = collectRegexMatches(regex, value, regex.flags.includes("g"), undefined, lastIndex);
|
|
312
353
|
let result = "";
|
|
313
354
|
let copiedThrough = 0;
|
|
314
355
|
for (const match of matches) {
|
|
@@ -484,8 +525,6 @@ function callMatchLikeMethod(value, methodName, args, compilation, lastIndex) {
|
|
|
484
525
|
regex.lastIndex = lastIndex;
|
|
485
526
|
return match?.index ?? -1;
|
|
486
527
|
}
|
|
487
|
-
if (methodName === "matchAll" && !regex.flags.includes("g"))
|
|
488
|
-
throw new TypeError("String#matchAll requires a global regex.");
|
|
489
528
|
if (methodName === "match" && !regex.flags.includes("g"))
|
|
490
529
|
return toMatchArray(executeRegex(regex, value, lastIndex ?? Number(regex.lastIndex)), value);
|
|
491
530
|
if (methodName === "match")
|
|
@@ -493,7 +532,7 @@ function callMatchLikeMethod(value, methodName, args, compilation, lastIndex) {
|
|
|
493
532
|
const matcher = methodName === "matchAll"
|
|
494
533
|
? createSandboxRegex(regex.source, regex.flags, normalizeLastIndex(lastIndex ?? Number(regex.lastIndex)), compilation)
|
|
495
534
|
: regex;
|
|
496
|
-
const matches = collectRegexMatches(matcher, value,
|
|
535
|
+
const matches = collectRegexMatches(matcher, value, matcher.flags.includes("g"), compilation.owner?.budget, Number(matcher.lastIndex));
|
|
497
536
|
if (methodName === "match" && matches.length === 0)
|
|
498
537
|
return null;
|
|
499
538
|
return methodName === "match"
|
|
@@ -3,7 +3,7 @@ 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();
|
|
@@ -160,8 +160,9 @@ export function getSandboxPropertyDescriptor(value, key, budget) {
|
|
|
160
160
|
let depth = 0;
|
|
161
161
|
while (typeof current === "object" &&
|
|
162
162
|
current !== null &&
|
|
163
|
-
(Array.isArray(current) || isSandboxDate(current) || isPrototypeRecord(current))) {
|
|
164
|
-
const properties = isGuestClosure(current) ? getGuestFunctionProperties(current)
|
|
163
|
+
(Array.isArray(current) || isSandboxDate(current) || isSandboxRegex(current) || isPrototypeRecord(current))) {
|
|
164
|
+
const properties = isGuestClosure(current) ? getGuestFunctionProperties(current)
|
|
165
|
+
: isSandboxRegex(current) ? getRegexProperties(current) : current;
|
|
165
166
|
const descriptor = properties === undefined ? undefined : Object.getOwnPropertyDescriptor(properties, key);
|
|
166
167
|
if (descriptor !== undefined)
|
|
167
168
|
return descriptor;
|
|
@@ -179,6 +180,8 @@ export function getSandboxDataProperty(value, key, budget) {
|
|
|
179
180
|
while (typeof current === "object" && current !== null) {
|
|
180
181
|
if (isGuestHostObject(current))
|
|
181
182
|
return typeof key === "symbol" ? undefined : getHostObjectMember(current, String(key));
|
|
183
|
+
if (isSandboxRegex(current))
|
|
184
|
+
return Object.getOwnPropertyDescriptor(getRegexProperties(current), key)?.value;
|
|
182
185
|
if (isGuestClosure(current)) {
|
|
183
186
|
const entry = getGuestFunctionProperty(current, key);
|
|
184
187
|
if (entry !== undefined || Object.hasOwn(current.properties ?? {}, key))
|
|
@@ -1,3 +1,4 @@
|
|
|
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";
|
|
3
4
|
import type { Budget, CompileTicket } from "./budget.js";
|
|
@@ -1,5 +1,7 @@
|
|
|
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";
|
|
@@ -98,6 +100,8 @@ export function ownEnumerableSandboxEntries(value, excludedKeys) {
|
|
|
98
100
|
let entries;
|
|
99
101
|
if (isGuestClosure(value))
|
|
100
102
|
entries = Object.entries(value.properties ?? {});
|
|
103
|
+
else if (isSandboxRegex(value))
|
|
104
|
+
entries = Object.entries(getRegexProperties(value));
|
|
101
105
|
else if (isSandboxClosure(value) || isSandboxGenerator(value) || isSandboxMap(value) || isSandboxSet(value) || isSandboxPromise(value) || isSandboxRegex(value))
|
|
102
106
|
return [];
|
|
103
107
|
else
|
|
@@ -111,13 +115,15 @@ export function ownSandboxSymbolKeys(value) {
|
|
|
111
115
|
return [];
|
|
112
116
|
if (isSandboxClosure(value))
|
|
113
117
|
value = value.properties ?? {};
|
|
118
|
+
else if (isSandboxRegex(value))
|
|
119
|
+
value = getRegexProperties(value);
|
|
114
120
|
else if (isSandboxGenerator(value) || isSandboxMap(value) || isSandboxSet(value) || isSandboxPromise(value) || isSandboxRegex(value))
|
|
115
121
|
return [];
|
|
116
122
|
return Object.getOwnPropertySymbols(Object(value)).filter(key => !internalSymbols.has(key));
|
|
117
123
|
}
|
|
118
124
|
export function ownEnumerableSandboxKeys(value, includeSymbols = false) {
|
|
119
125
|
if (includeSymbols) {
|
|
120
|
-
const properties = isSandboxClosure(value) ? value.properties ?? {} : Object(value);
|
|
126
|
+
const properties = isSandboxClosure(value) ? value.properties ?? {} : isSandboxRegex(value) ? getRegexProperties(value) : Object(value);
|
|
121
127
|
return [...ownEnumerableSandboxKeys(value), ...ownSandboxSymbolKeys(value).filter(key => Object.getOwnPropertyDescriptor(properties, key)?.enumerable === true)];
|
|
122
128
|
}
|
|
123
129
|
if (isGuestHostObject(value))
|
|
@@ -126,6 +132,8 @@ export function ownEnumerableSandboxKeys(value, includeSymbols = false) {
|
|
|
126
132
|
throw new TypeError("Cannot convert undefined or null to object.");
|
|
127
133
|
if (isGuestClosure(value))
|
|
128
134
|
return Object.keys(value.properties ?? {});
|
|
135
|
+
if (isSandboxRegex(value))
|
|
136
|
+
return Object.keys(getRegexProperties(value));
|
|
129
137
|
if (isSandboxClosure(value) || isSandboxGenerator(value) || isSandboxMap(value) || isSandboxSet(value) || isSandboxPromise(value) || isSandboxRegex(value))
|
|
130
138
|
return [];
|
|
131
139
|
return Object.keys(Object(value));
|
|
@@ -218,6 +226,32 @@ export function createSandboxRegex(source, flags = "", lastIndex = 0, compilatio
|
|
|
218
226
|
}
|
|
219
227
|
const pattern = parseRegex(source, flags, compilation, 7 + source.length + flags.length);
|
|
220
228
|
const regex = { kind: "regex", source, flags, lastIndex };
|
|
229
|
+
const storage = Object.create(null);
|
|
230
|
+
Object.defineProperty(storage, "lastIndex", { value: lastIndex, writable: true });
|
|
231
|
+
const syncCursor = () => {
|
|
232
|
+
const descriptor = Object.getOwnPropertyDescriptor(regex, "lastIndex");
|
|
233
|
+
Object.defineProperty(storage, "lastIndex", { value: descriptor.value, writable: descriptor.writable });
|
|
234
|
+
};
|
|
235
|
+
const properties = new Proxy(storage, {
|
|
236
|
+
get: (target, key, receiver) => key === "lastIndex" ? regex.lastIndex : Reflect.get(target, key, receiver),
|
|
237
|
+
set: (target, key, value, receiver) => key === "lastIndex"
|
|
238
|
+
? Reflect.set(regex, key, value) : Reflect.set(target, key, value, receiver),
|
|
239
|
+
getOwnPropertyDescriptor(target, key) {
|
|
240
|
+
if (key === "lastIndex")
|
|
241
|
+
syncCursor();
|
|
242
|
+
return Object.getOwnPropertyDescriptor(target, key);
|
|
243
|
+
},
|
|
244
|
+
defineProperty(target, key, descriptor) {
|
|
245
|
+
if (key !== "lastIndex")
|
|
246
|
+
return Reflect.defineProperty(target, key, descriptor);
|
|
247
|
+
syncCursor();
|
|
248
|
+
if (!Reflect.defineProperty(target, key, descriptor))
|
|
249
|
+
return false;
|
|
250
|
+
const cursor = Object.getOwnPropertyDescriptor(target, key);
|
|
251
|
+
return Reflect.defineProperty(regex, key, { value: cursor.value, writable: cursor.writable });
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
regexGuestProperties.set(regex, properties);
|
|
221
255
|
Object.defineProperties(regex, {
|
|
222
256
|
[sandboxRegexBrand]: { value: true },
|
|
223
257
|
[sandboxRegexPattern]: { value: pattern }
|
|
@@ -424,6 +458,19 @@ export function measureSandboxData(values, options = {}) {
|
|
|
424
458
|
if (compiled.ticket !== undefined)
|
|
425
459
|
options.compileTickets?.add(compiled.ticket);
|
|
426
460
|
visit(lastIndex, depth + 1);
|
|
461
|
+
for (const key of Reflect.ownKeys(getRegexProperties(value))) {
|
|
462
|
+
if (key === "lastIndex")
|
|
463
|
+
continue;
|
|
464
|
+
const descriptor = Object.getOwnPropertyDescriptor(getRegexProperties(value), key);
|
|
465
|
+
usage += 1 + (typeof key === "string" ? key.length : 0);
|
|
466
|
+
if (typeof key === "symbol")
|
|
467
|
+
visit(key, depth + 1);
|
|
468
|
+
if ("value" in descriptor)
|
|
469
|
+
visit(descriptor.value, depth + 1);
|
|
470
|
+
else
|
|
471
|
+
for (const closure of retainedAccessorClosures(descriptor))
|
|
472
|
+
visit(closure, depth + 1);
|
|
473
|
+
}
|
|
427
474
|
return;
|
|
428
475
|
}
|
|
429
476
|
if (isSandboxArguments(value)) {
|
|
@@ -491,7 +538,7 @@ function captureRegexData(value) {
|
|
|
491
538
|
typeof flags.value !== "string") {
|
|
492
539
|
throw new TypeError("Invalid sandbox RegExp source or flags: expected own string data properties.");
|
|
493
540
|
}
|
|
494
|
-
const cursor = Object.getOwnPropertyDescriptor(value, "lastIndex");
|
|
541
|
+
const cursor = Object.getOwnPropertyDescriptor(regexGuestProperties.get(value) ?? value, "lastIndex");
|
|
495
542
|
if (cursor === undefined || !("value" in cursor)) {
|
|
496
543
|
throw new TypeError("Invalid sandbox RegExp lastIndex: expected an own data property.");
|
|
497
544
|
}
|
|
@@ -519,6 +566,21 @@ function copyToSandbox(value, state, path = "<root>", cloneSandboxCollections =
|
|
|
519
566
|
state.seen.set(value, copy);
|
|
520
567
|
if (!state.resetRegexLastIndex)
|
|
521
568
|
copy.lastIndex = copyToSandbox(value.lastIndex, state, `${path}.lastIndex`, true, depth + 1);
|
|
569
|
+
if (!state.structuredClone) {
|
|
570
|
+
const properties = getRegexProperties(value);
|
|
571
|
+
for (const key of Reflect.ownKeys(properties)) {
|
|
572
|
+
const descriptor = Object.getOwnPropertyDescriptor(properties, key);
|
|
573
|
+
if (!("value" in descriptor))
|
|
574
|
+
throw new TypeError("RegExp accessor properties cannot be copied as data.");
|
|
575
|
+
Object.defineProperty(getRegexProperties(copy), key, {
|
|
576
|
+
...descriptor,
|
|
577
|
+
value: key === "lastIndex" && state.resetRegexLastIndex ? 0
|
|
578
|
+
: copyToSandbox(descriptor.value, state, `${path}.${String(key)}`, true, depth + 1)
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
if (!Object.isExtensible(properties))
|
|
582
|
+
Object.preventExtensions(getRegexProperties(copy));
|
|
583
|
+
}
|
|
522
584
|
return copy;
|
|
523
585
|
}
|
|
524
586
|
if (isSandboxClosure(value) ||
|
|
@@ -745,6 +807,18 @@ function copyFromSandbox(value, state, path = "<root>", options, depth = 0) {
|
|
|
745
807
|
const regex = new RegExp(source, flags);
|
|
746
808
|
state.seen.set(value, regex);
|
|
747
809
|
Reflect.set(regex, "lastIndex", copyFromSandbox(lastIndex, state, `${path}.lastIndex`, options, depth + 1));
|
|
810
|
+
const properties = regexGuestProperties.get(value);
|
|
811
|
+
if (properties !== undefined) {
|
|
812
|
+
for (const key of Reflect.ownKeys(properties)) {
|
|
813
|
+
const descriptor = Object.getOwnPropertyDescriptor(properties, key);
|
|
814
|
+
if (!("value" in descriptor))
|
|
815
|
+
throw new TypeError("RegExp accessor properties cannot be copied as data.");
|
|
816
|
+
Object.defineProperty(regex, key, { ...descriptor,
|
|
817
|
+
value: copyFromSandbox(descriptor.value, state, `${path}.${String(key)}`, options, depth + 1) });
|
|
818
|
+
}
|
|
819
|
+
if (!Object.isExtensible(properties))
|
|
820
|
+
Object.preventExtensions(regex);
|
|
821
|
+
}
|
|
748
822
|
guard.retainScratch();
|
|
749
823
|
return regex;
|
|
750
824
|
}
|