poe-code 14.0.62 → 14.0.64
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 +977 -528
- 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-F7TJSPDZ.js → chunk-3EXDJDQM.js} +2 -2
- package/packages/safe-js/dist/chunks/{chunk-VKGWGZBH.js → chunk-XO7B4P27.js} +945 -545
- package/packages/safe-js/dist/chunks/chunk-XO7B4P27.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/boxed.d.ts +14 -0
- package/packages/safe-js/dist/interp/boxed.js +50 -0
- package/packages/safe-js/dist/interp/globals/collections.js +4 -4
- package/packages/safe-js/dist/interp/globals/console-json.js +15 -18
- package/packages/safe-js/dist/interp/globals/misc.js +1 -1
- package/packages/safe-js/dist/interp/globals/object-array.js +19 -14
- package/packages/safe-js/dist/interp/globals/object.js +10 -5
- package/packages/safe-js/dist/interp/globals/primitives.d.ts +8 -0
- package/packages/safe-js/dist/interp/globals/primitives.js +69 -0
- package/packages/safe-js/dist/interp/host-bridge.js +22 -0
- package/packages/safe-js/dist/interp/interpreter.js +175 -122
- package/packages/safe-js/dist/interp/iteration.d.ts +5 -3
- package/packages/safe-js/dist/interp/iteration.js +22 -1
- package/packages/safe-js/dist/interp/methods/array.js +6 -3
- package/packages/safe-js/dist/interp/methods/function.js +32 -15
- package/packages/safe-js/dist/interp/methods/number.d.ts +1 -0
- package/packages/safe-js/dist/interp/methods/number.js +4 -1
- package/packages/safe-js/dist/interp/methods/string.d.ts +2 -0
- package/packages/safe-js/dist/interp/methods/string.js +2 -2
- package/packages/safe-js/dist/interp/object-model.d.ts +5 -0
- package/packages/safe-js/dist/interp/object-model.js +66 -14
- package/packages/safe-js/dist/interp/promise.js +68 -61
- package/packages/safe-js/dist/interp/string-coercion.js +4 -1
- package/packages/safe-js/dist/interp/values.d.ts +1 -0
- package/packages/safe-js/dist/interp/values.js +78 -3
- package/packages/safe-js/dist/migrate.d.ts +2 -2
- package/packages/safe-js/dist/migration-file.d.ts +4 -4
- package/packages/safe-js/dist/snapshot/boxed.d.ts +16 -0
- package/packages/safe-js/dist/snapshot/boxed.js +52 -0
- package/packages/safe-js/dist/snapshot/dump-format.js +18 -5
- package/packages/safe-js/dist/snapshot/replay-data.d.ts +5 -0
- package/packages/safe-js/dist/snapshot/replay-data.js +24 -0
- package/packages/safe-js/dist/snapshot/restore.js +8 -0
- package/packages/safe-js/dist/snapshot/serialize.d.ts +4 -2
- package/packages/safe-js/dist/snapshot/serialize.js +18 -10
- package/packages/safe-js/dist/snapshot/validation.js +22 -1
- package/packages/safe-js/dist/chunks/chunk-VKGWGZBH.js.map +0 -7
- /package/packages/safe-js/dist/chunks/{chunk-F7TJSPDZ.js.map → chunk-3EXDJDQM.js.map} +0 -0
|
@@ -14,7 +14,8 @@ import { CompileScope, RegexCompileGuard } from "./regex/compile-guard.js";
|
|
|
14
14
|
import { createCapturedException, createThrowCompletion, evaluateThrowStatement as evaluateThrowStatementResult, evaluateTryStatement as evaluateTryStatementResult, isCapturedException, isInterpreterError, surfaceThrownValue } from "./exceptions.js";
|
|
15
15
|
import { callArrayMethod, getArrayMember, isArrayMethodName } from "./methods/array.js";
|
|
16
16
|
import { getFunctionMember } from "./methods/function.js";
|
|
17
|
-
import { getGuestFunctionProperty, getSandboxPrototype, isGuestClosure, materializeFunctionProperties, setSandboxPrototype } from "./object-model.js";
|
|
17
|
+
import { getBoxedPrototype, getGuestFunctionProperty, getSandboxPrototype, hasExplicitSandboxPrototype, isDefaultBoxedMethod, isGuestClosure, materializeFunctionProperties, setSandboxPrototype } from "./object-model.js";
|
|
18
|
+
import { getStringIndex } from "./methods/string.js";
|
|
18
19
|
import { assertSandboxDataDepth } from "../graph-depth.js";
|
|
19
20
|
import { callMapMethod, getMapMember, isMapMethodName } from "./methods/map.js";
|
|
20
21
|
import { callNumberMethod, getNumberMember, isNumberMethodName } from "./methods/number.js";
|
|
@@ -34,6 +35,7 @@ import { getCollectionIteratorMember } from "./methods/collection-iterator.js";
|
|
|
34
35
|
import { getFloat32Member, isFloat32ArrayConstructor, setFloat32Member } from "./globals/float32array.js";
|
|
35
36
|
import { isFloat32Array } from "./float32.js";
|
|
36
37
|
import { dateString, dateTime, isSandboxDate } from "./date.js";
|
|
38
|
+
import { isSandboxBox } from "./boxed.js";
|
|
37
39
|
import { getDateMember, getDatePrototype, isDateConstructor } from "./globals/date.js";
|
|
38
40
|
import { createSandboxRegex, allocateProducedSandboxValue, isSandboxClosure, isSandboxGenerator, isSandboxMap, isSandboxPromise, isSandboxRegex, isSandboxSet, reconcileCompiledValues } from "./values.js";
|
|
39
41
|
import { Scope } from "./scope.js";
|
|
@@ -466,22 +468,29 @@ async function evaluateBinaryExpression(node, context) {
|
|
|
466
468
|
if (left.kind !== "normal") {
|
|
467
469
|
return left;
|
|
468
470
|
}
|
|
471
|
+
let leftValue = left.value;
|
|
469
472
|
let rightValue;
|
|
470
|
-
const release = retainValues(context.budget, () => [
|
|
473
|
+
const release = retainValues(context.budget, () => [leftValue, rightValue]);
|
|
471
474
|
try {
|
|
472
475
|
const right = await evaluateNode(node.right, context);
|
|
473
476
|
if (right.kind !== "normal") {
|
|
474
477
|
return right;
|
|
475
478
|
}
|
|
476
479
|
rightValue = right.value;
|
|
477
|
-
let leftValue = left.value;
|
|
478
480
|
if (node.operator === "in") {
|
|
479
481
|
if (typeof right.value !== "object" || right.value === null) {
|
|
480
482
|
throw new TypeError("Right-hand side of 'in' must be an object.");
|
|
481
483
|
}
|
|
482
484
|
leftValue = await toPropertyKey(leftValue, context.budget, createCoercionContext(context));
|
|
483
485
|
}
|
|
484
|
-
|
|
486
|
+
if (!["in", "instanceof", "===", "!=="].includes(node.operator)) {
|
|
487
|
+
const equality = node.operator === "==" || node.operator === "!=";
|
|
488
|
+
if (isSandboxBox(leftValue) && (!equality || (rightValue !== null && rightValue !== undefined && typeof rightValue !== "object")))
|
|
489
|
+
leftValue = await toNumericPrimitive(leftValue, context);
|
|
490
|
+
if (isSandboxBox(rightValue) && (!equality || (left.value !== null && left.value !== undefined && typeof left.value !== "object")))
|
|
491
|
+
rightValue = await toNumericPrimitive(rightValue, context);
|
|
492
|
+
}
|
|
493
|
+
const value = applyBinaryOperator(node, leftValue, rightValue, context);
|
|
485
494
|
return {
|
|
486
495
|
kind: "normal",
|
|
487
496
|
hasValue: true,
|
|
@@ -1079,62 +1088,68 @@ async function evaluateForOfStatement(node, context) {
|
|
|
1079
1088
|
};
|
|
1080
1089
|
}
|
|
1081
1090
|
async function evaluateForOfIterator(node, value, context, restoredEntry) {
|
|
1082
|
-
const iterator = getSandboxIterator(value, context.budget);
|
|
1091
|
+
const iterator = getSandboxIterator(value, context.budget, createCoercionContext(context));
|
|
1083
1092
|
if (iterator === undefined) {
|
|
1084
1093
|
throw new TypeError(`${String(value)} is not a supported iterable`);
|
|
1085
1094
|
}
|
|
1086
|
-
const
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
const iteration = restoredEntry ?? (await iterator.next());
|
|
1099
|
-
restoredEntry = undefined;
|
|
1100
|
-
if (typeof iteration !== "object" || iteration === null) {
|
|
1101
|
-
throw new TypeError("Iterator result must be an object.");
|
|
1102
|
-
}
|
|
1103
|
-
if (iteration.done) {
|
|
1104
|
-
context.activeLoopIterations.delete(nodeId);
|
|
1105
|
-
return normalEmptyResult();
|
|
1106
|
-
}
|
|
1107
|
-
context.activeLoopIterations.set(nodeId, iterator.snapshotIndex === undefined
|
|
1108
|
-
? index
|
|
1109
|
-
: {
|
|
1110
|
-
get index() {
|
|
1111
|
-
return iterator.snapshotIndex();
|
|
1112
|
-
},
|
|
1113
|
-
values: [value, iteration.value]
|
|
1114
|
-
});
|
|
1115
|
-
const scope = context.scope.child();
|
|
1116
|
-
const binding = await bindForOfLoopVariable(node.left, iteration.value, scope, context);
|
|
1117
|
-
if (!binding.ok) {
|
|
1118
|
-
return binding.result;
|
|
1119
|
-
}
|
|
1120
|
-
const iterationContext = createLoopIterationContext(context, scope);
|
|
1121
|
-
emitLoopIterationBreakpoint(node, iterationContext);
|
|
1122
|
-
const result = await evaluateNode(node.body, iterationContext);
|
|
1123
|
-
if (isMatchingBreak(result, loopLabels(node))) {
|
|
1124
|
-
context.activeLoopIterations.delete(nodeId);
|
|
1125
|
-
await closeIterator(iterator);
|
|
1126
|
-
return normalEmptyResult();
|
|
1095
|
+
const releaseIterator = retainValues(context.budget, () => [value, iterator.retainedValue]);
|
|
1096
|
+
try {
|
|
1097
|
+
const nodeId = node.nodeId ?? -1;
|
|
1098
|
+
let index = consumeRestoredLoopIterationIndex(node, context);
|
|
1099
|
+
for (let skipped = 0; skipped < index; skipped += 1) {
|
|
1100
|
+
const skippedIteration = await iterator.next();
|
|
1101
|
+
if (typeof skippedIteration !== "object" || skippedIteration === null) {
|
|
1102
|
+
throw new TypeError("Iterator result must be an object.");
|
|
1103
|
+
}
|
|
1104
|
+
if (skippedIteration.done) {
|
|
1105
|
+
return normalEmptyResult();
|
|
1106
|
+
}
|
|
1127
1107
|
}
|
|
1128
|
-
|
|
1108
|
+
while (true) {
|
|
1109
|
+
const iteration = restoredEntry ?? (await iterator.next());
|
|
1110
|
+
restoredEntry = undefined;
|
|
1111
|
+
if (typeof iteration !== "object" || iteration === null) {
|
|
1112
|
+
throw new TypeError("Iterator result must be an object.");
|
|
1113
|
+
}
|
|
1114
|
+
if (iteration.done) {
|
|
1115
|
+
context.activeLoopIterations.delete(nodeId);
|
|
1116
|
+
return normalEmptyResult();
|
|
1117
|
+
}
|
|
1118
|
+
context.activeLoopIterations.set(nodeId, iterator.snapshotIndex === undefined
|
|
1119
|
+
? index
|
|
1120
|
+
: {
|
|
1121
|
+
get index() {
|
|
1122
|
+
return iterator.snapshotIndex();
|
|
1123
|
+
},
|
|
1124
|
+
values: [value, iteration.value]
|
|
1125
|
+
});
|
|
1126
|
+
const scope = context.scope.child();
|
|
1127
|
+
const binding = await bindForOfLoopVariable(node.left, iteration.value, scope, context);
|
|
1128
|
+
if (!binding.ok) {
|
|
1129
|
+
return binding.result;
|
|
1130
|
+
}
|
|
1131
|
+
const iterationContext = createLoopIterationContext(context, scope);
|
|
1132
|
+
emitLoopIterationBreakpoint(node, iterationContext);
|
|
1133
|
+
const result = await evaluateNode(node.body, iterationContext);
|
|
1134
|
+
if (isMatchingBreak(result, loopLabels(node))) {
|
|
1135
|
+
context.activeLoopIterations.delete(nodeId);
|
|
1136
|
+
await closeIterator(iterator);
|
|
1137
|
+
return normalEmptyResult();
|
|
1138
|
+
}
|
|
1139
|
+
if (isMatchingContinue(result, loopLabels(node))) {
|
|
1140
|
+
index += 1;
|
|
1141
|
+
continue;
|
|
1142
|
+
}
|
|
1143
|
+
if (result.kind !== "normal") {
|
|
1144
|
+
context.activeLoopIterations.delete(nodeId);
|
|
1145
|
+
await closeIterator(iterator);
|
|
1146
|
+
return result;
|
|
1147
|
+
}
|
|
1129
1148
|
index += 1;
|
|
1130
|
-
continue;
|
|
1131
|
-
}
|
|
1132
|
-
if (result.kind !== "normal") {
|
|
1133
|
-
context.activeLoopIterations.delete(nodeId);
|
|
1134
|
-
await closeIterator(iterator);
|
|
1135
|
-
return result;
|
|
1136
1149
|
}
|
|
1137
|
-
|
|
1150
|
+
}
|
|
1151
|
+
finally {
|
|
1152
|
+
releaseIterator();
|
|
1138
1153
|
}
|
|
1139
1154
|
}
|
|
1140
1155
|
async function evaluateForInStatement(node, context) {
|
|
@@ -1523,49 +1538,58 @@ async function evaluateYieldDelegate(node, context) {
|
|
|
1523
1538
|
if (argument.kind !== "normal") {
|
|
1524
1539
|
return argument;
|
|
1525
1540
|
}
|
|
1526
|
-
const iterator = getSandboxIterator(argument.value, context.budget);
|
|
1541
|
+
const iterator = getSandboxIterator(argument.value, context.budget, createCoercionContext(context));
|
|
1527
1542
|
if (iterator === undefined) {
|
|
1528
1543
|
throw new TypeError(`${String(argument.value)} is not a supported iterable`);
|
|
1529
1544
|
}
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1545
|
+
const releaseIterator = retainValues(context.budget, () => [
|
|
1546
|
+
argument.value,
|
|
1547
|
+
iterator.retainedValue
|
|
1548
|
+
]);
|
|
1549
|
+
try {
|
|
1550
|
+
let completion = {
|
|
1551
|
+
type: "normal",
|
|
1552
|
+
value: undefined
|
|
1553
|
+
};
|
|
1554
|
+
const replay = context.generatorResume?.sent ?? [];
|
|
1555
|
+
let replayIndex = 0;
|
|
1556
|
+
while (true) {
|
|
1557
|
+
const method = completion.type === "normal" ? "next" : completion.type;
|
|
1558
|
+
const iteratorMethod = iterator[method];
|
|
1559
|
+
if (iteratorMethod === undefined) {
|
|
1560
|
+
if (completion.type === "throw") {
|
|
1561
|
+
throw completion.value;
|
|
1562
|
+
}
|
|
1563
|
+
return generatorCompletionResult(completion);
|
|
1542
1564
|
}
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
return
|
|
1565
|
+
const result = await iteratorMethod(completion.value);
|
|
1566
|
+
if (result.done) {
|
|
1567
|
+
if (completion.type === "return") {
|
|
1568
|
+
return generatorCompletionResult({ type: "return", value: result.value });
|
|
1569
|
+
}
|
|
1570
|
+
return {
|
|
1571
|
+
kind: "normal",
|
|
1572
|
+
hasValue: true,
|
|
1573
|
+
value: result.value
|
|
1574
|
+
};
|
|
1549
1575
|
}
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
}
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1576
|
+
if (replayIndex < replay.length - 1) {
|
|
1577
|
+
completion = replay[replayIndex + 1];
|
|
1578
|
+
replayIndex += 1;
|
|
1579
|
+
continue;
|
|
1580
|
+
}
|
|
1581
|
+
const completionPromise = context.generatorYield(allocateProducedSandboxValue(result.value, context.budget), node.nodeId);
|
|
1582
|
+
emitResumeBreakpoint(context, {
|
|
1583
|
+
kind: "generator-yield",
|
|
1584
|
+
nodeId: node.nodeId,
|
|
1585
|
+
span: node.span
|
|
1586
|
+
});
|
|
1587
|
+
completion = (await completionPromise);
|
|
1588
|
+
context.generatorResume = undefined;
|
|
1560
1589
|
}
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
nodeId: node.nodeId,
|
|
1565
|
-
span: node.span
|
|
1566
|
-
});
|
|
1567
|
-
completion = (await completionPromise);
|
|
1568
|
-
context.generatorResume = undefined;
|
|
1590
|
+
}
|
|
1591
|
+
finally {
|
|
1592
|
+
releaseIterator();
|
|
1569
1593
|
}
|
|
1570
1594
|
}
|
|
1571
1595
|
function generatorCompletionResult(completion) {
|
|
@@ -1706,6 +1730,14 @@ async function evaluateMemberExpression(node, context) {
|
|
|
1706
1730
|
function getPropertyValue(target, property, context) {
|
|
1707
1731
|
if (isGuestHostObject(target))
|
|
1708
1732
|
return getHostObjectMember(target, String(property));
|
|
1733
|
+
if (typeof target === "string" || typeof target === "number" || typeof target === "boolean") {
|
|
1734
|
+
const prototype = getBoxedPrototype(target, context.budget);
|
|
1735
|
+
if (prototype !== undefined) {
|
|
1736
|
+
if (typeof target === "string" && (property === "length" || getStringIndex(property) !== undefined))
|
|
1737
|
+
return getStringMember(target, property, context.budget);
|
|
1738
|
+
return getMemberValue(prototype, property, context);
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1709
1741
|
if (typeof target === "string")
|
|
1710
1742
|
return getStringMember(target, property, context.budget);
|
|
1711
1743
|
if (typeof target === "number")
|
|
@@ -1886,6 +1918,16 @@ async function evaluateMemberCallExpression(node, context) {
|
|
|
1886
1918
|
...reference,
|
|
1887
1919
|
property: await toPropertyKey(reference.property, context.budget, createCoercionContext(context))
|
|
1888
1920
|
};
|
|
1921
|
+
if ((typeof member.object === "string" || typeof member.object === "number" || typeof member.object === "boolean") &&
|
|
1922
|
+
getBoxedPrototype(member.object, context.budget) !== undefined) {
|
|
1923
|
+
if (isDefaultBoxedMethod(member.object, member.property, context.budget)) {
|
|
1924
|
+
if (typeof member.object === "string" && isStringMethodName(member.property))
|
|
1925
|
+
return evaluateStringMethodCall(node, member.object, member.property, context);
|
|
1926
|
+
if (typeof member.object === "number" && isNumberMethodName(member.property))
|
|
1927
|
+
return evaluateNumberMethodCall(node, member.object, member.property, context);
|
|
1928
|
+
}
|
|
1929
|
+
return evaluateResolvedCallExpression(node, getPropertyValue(member.object, member.property, context), context, member.object);
|
|
1930
|
+
}
|
|
1889
1931
|
if (typeof member.object === "string" && isStringMethodName(member.property)) {
|
|
1890
1932
|
return evaluateStringMethodCall(node, member.object, member.property, context);
|
|
1891
1933
|
}
|
|
@@ -2177,8 +2219,9 @@ function hasSandboxProperty(value, key, context) {
|
|
|
2177
2219
|
return hasHostObjectMember(current, key);
|
|
2178
2220
|
if (hasOwnSandboxProperty(current, key, false))
|
|
2179
2221
|
return true;
|
|
2180
|
-
if (
|
|
2181
|
-
|
|
2222
|
+
if (!(isGuestClosure(current) && hasExplicitSandboxPrototype(current)) &&
|
|
2223
|
+
(Array.isArray(current) || !isPlainSandboxObject(current) ||
|
|
2224
|
+
isSandboxDate(current) || isFloat32Array(current) || isSandboxGenerator(current) || isSandboxCollectionIterator(current))) {
|
|
2182
2225
|
return getPropertyValue(current, key, context) !== undefined;
|
|
2183
2226
|
}
|
|
2184
2227
|
current = getSandboxPrototype(current, context.budget);
|
|
@@ -2190,33 +2233,43 @@ function hasSandboxProperty(value, key, context) {
|
|
|
2190
2233
|
return false;
|
|
2191
2234
|
}
|
|
2192
2235
|
async function applyCompoundAssignmentOperator(operator, left, right, context) {
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2236
|
+
const convertingObject = typeof left === "object" && left !== null;
|
|
2237
|
+
let convertedLeft;
|
|
2238
|
+
const release = retainValues(context.budget, () => [convertedLeft]);
|
|
2239
|
+
try {
|
|
2240
|
+
left = await toNumericPrimitive(left, context);
|
|
2241
|
+
if (convertingObject)
|
|
2242
|
+
convertedLeft = left;
|
|
2243
|
+
right = await toNumericPrimitive(right, context);
|
|
2244
|
+
switch (operator) {
|
|
2245
|
+
case "+=":
|
|
2246
|
+
return applyAdditionOperator(left, right, context);
|
|
2247
|
+
case "-=":
|
|
2248
|
+
return toNumber(left) - toNumber(right);
|
|
2249
|
+
case "*=":
|
|
2250
|
+
return toNumber(left) * toNumber(right);
|
|
2251
|
+
case "/=":
|
|
2252
|
+
return toNumber(left) / toNumber(right);
|
|
2253
|
+
case "%=":
|
|
2254
|
+
return toNumber(left) % toNumber(right);
|
|
2255
|
+
case "**=":
|
|
2256
|
+
return toNumber(left) ** toNumber(right);
|
|
2257
|
+
case "&=":
|
|
2258
|
+
return toNumber(left) & toNumber(right);
|
|
2259
|
+
case "|=":
|
|
2260
|
+
return toNumber(left) | toNumber(right);
|
|
2261
|
+
case "^=":
|
|
2262
|
+
return toNumber(left) ^ toNumber(right);
|
|
2263
|
+
case "<<=":
|
|
2264
|
+
return toNumber(left) << toNumber(right);
|
|
2265
|
+
case ">>=":
|
|
2266
|
+
return toNumber(left) >> toNumber(right);
|
|
2267
|
+
case ">>>=":
|
|
2268
|
+
return toNumber(left) >>> toNumber(right);
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
finally {
|
|
2272
|
+
release();
|
|
2220
2273
|
}
|
|
2221
2274
|
}
|
|
2222
2275
|
function applyAdditionOperator(left, right, context) {
|
|
@@ -2626,12 +2679,12 @@ async function evaluateSpreadElement(node, context) {
|
|
|
2626
2679
|
result: value
|
|
2627
2680
|
};
|
|
2628
2681
|
}
|
|
2629
|
-
const iterator = getSandboxIterator(value.value, context.budget);
|
|
2682
|
+
const iterator = getSandboxIterator(value.value, context.budget, createCoercionContext(context));
|
|
2630
2683
|
if (iterator === undefined) {
|
|
2631
2684
|
throw new TypeError("Spread arguments must evaluate to an iterable.");
|
|
2632
2685
|
}
|
|
2633
2686
|
const spreadValues = [];
|
|
2634
|
-
const release = retainValues(context.budget, () => [value.value, ...spreadValues]);
|
|
2687
|
+
const release = retainValues(context.budget, () => [value.value, iterator.retainedValue, ...spreadValues]);
|
|
2635
2688
|
try {
|
|
2636
2689
|
while (true) {
|
|
2637
2690
|
const next = await iterator.next();
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { type SandboxValue } from "./values.js";
|
|
2
|
-
import
|
|
1
|
+
import { type SandboxCallContext, type SandboxValue } from "./values.js";
|
|
2
|
+
import { Budget } from "./budget.js";
|
|
3
3
|
export type SandboxIterator = {
|
|
4
4
|
readonly generator?: true;
|
|
5
|
+
readonly asynchronous?: true;
|
|
6
|
+
readonly retainedValue?: SandboxValue;
|
|
5
7
|
snapshotIndex?(): number;
|
|
6
8
|
next(value?: SandboxValue): IteratorResult<SandboxValue> | Promise<IteratorResult<SandboxValue>>;
|
|
7
9
|
return?(value?: SandboxValue): IteratorResult<SandboxValue> | Promise<IteratorResult<SandboxValue>>;
|
|
8
10
|
throw?(error?: SandboxValue): IteratorResult<SandboxValue> | Promise<IteratorResult<SandboxValue>>;
|
|
9
11
|
};
|
|
10
|
-
export declare function getSandboxIterator(value: SandboxValue, budget?: Budget): SandboxIterator | undefined;
|
|
12
|
+
export declare function getSandboxIterator(value: SandboxValue, budget?: Budget, context?: SandboxCallContext): SandboxIterator | undefined;
|
|
@@ -1,9 +1,30 @@
|
|
|
1
1
|
import { isSandboxGenerator, isSandboxMap, isSandboxSet } from "./values.js";
|
|
2
2
|
import { enterRunningState } from "./running-state.js";
|
|
3
3
|
import { isFloat32Array } from "./float32.js";
|
|
4
|
+
import { boxedValue, isSandboxBox } from "./boxed.js";
|
|
4
5
|
import { getHostObjectIterator, isGuestHostObject } from "./host-capabilities.js";
|
|
5
6
|
import { isSandboxCollectionIterator, nextCollectionIterator } from "./collection-iterator.js";
|
|
6
|
-
|
|
7
|
+
import { Budget } from "./budget.js";
|
|
8
|
+
import { sandboxString } from "./string-coercion.js";
|
|
9
|
+
export function getSandboxIterator(value, budget, context) {
|
|
10
|
+
if (isSandboxBox(value) && typeof boxedValue(value) === "string") {
|
|
11
|
+
const primitive = boxedValue(value);
|
|
12
|
+
let text;
|
|
13
|
+
let iterator;
|
|
14
|
+
let initialized;
|
|
15
|
+
return {
|
|
16
|
+
asynchronous: true,
|
|
17
|
+
get retainedValue() { return text === primitive ? undefined : text; },
|
|
18
|
+
next: async () => {
|
|
19
|
+
initialized ??= Promise.resolve(sandboxString(value, budget ?? new Budget(), context)).then(converted => {
|
|
20
|
+
text = converted;
|
|
21
|
+
iterator = syncIterator(converted[Symbol.iterator]());
|
|
22
|
+
});
|
|
23
|
+
await initialized;
|
|
24
|
+
return iterator.next();
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
7
28
|
if (isSandboxCollectionIterator(value))
|
|
8
29
|
return { next: () => nextCollectionIterator(value, budget), snapshotIndex: () => 0 };
|
|
9
30
|
if (isGuestHostObject(value))
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createSandboxBox } from "../boxed.js";
|
|
2
|
+
import { createSandboxClosure, isSandboxClosure, isSandboxMap, isSandboxPromise, isSandboxSet, measureSandboxData } from "../values.js";
|
|
2
3
|
import { assertCollectionMutable, enterRunningState } from "../running-state.js";
|
|
3
4
|
import { getSandboxDataProperty, getSandboxPrototype } from "../object-model.js";
|
|
4
5
|
import { sandboxNumber } from "../string-coercion.js";
|
|
@@ -75,8 +76,10 @@ export function isArrayMethodName(property) {
|
|
|
75
76
|
export async function callArrayMethod(receiver, methodName, args, options, stack = []) {
|
|
76
77
|
if (receiver === null || receiver === undefined)
|
|
77
78
|
throw new TypeError("Array method requires a receiver.");
|
|
78
|
-
if (typeof receiver !== "object")
|
|
79
|
-
|
|
79
|
+
if (typeof receiver !== "object") {
|
|
80
|
+
receiver = createSandboxBox(receiver);
|
|
81
|
+
options.budget.chargeDataUsage(measureSandboxData([receiver]));
|
|
82
|
+
}
|
|
80
83
|
const retainedReceiver = {};
|
|
81
84
|
options.budget.setRetainedValues(retainedReceiver, () => [receiver]);
|
|
82
85
|
try {
|
|
@@ -1,23 +1,37 @@
|
|
|
1
1
|
import { createSandboxClosure, isSandboxClosure } from "../values.js";
|
|
2
|
-
import { getGuestFunctionProperty, isGuestClosure } from "../object-model.js";
|
|
2
|
+
import { getGuestFunctionProperty, getSandboxPrototype, hasExplicitSandboxPrototype, isGuestClosure, setSandboxPrototype } from "../object-model.js";
|
|
3
|
+
import { assertSandboxDataDepth } from "../../graph-depth.js";
|
|
3
4
|
import { functionString } from "../function-string.js";
|
|
4
5
|
import { runResources } from "../resources.js";
|
|
5
6
|
const functionMethodNames = new Set(["apply", "bind", "call", "toString"]);
|
|
6
7
|
export function getFunctionMember(target, property, options) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
8
|
+
let current = target;
|
|
9
|
+
let depth = 0;
|
|
10
|
+
while (current !== null) {
|
|
11
|
+
if (isGuestClosure(current)) {
|
|
12
|
+
const value = getGuestFunctionProperty(current, String(property));
|
|
13
|
+
if (value !== undefined || Object.hasOwn(current.properties ?? {}, String(property)))
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
else if (isSandboxClosure(current)) {
|
|
17
|
+
if (current.properties !== undefined && Object.hasOwn(current.properties, String(property)))
|
|
18
|
+
return current.properties[String(property)];
|
|
19
|
+
if (property === "length")
|
|
20
|
+
return current.length;
|
|
21
|
+
}
|
|
22
|
+
else if (Object.hasOwn(current, String(property))) {
|
|
23
|
+
return current[String(property)];
|
|
24
|
+
}
|
|
25
|
+
if (isSandboxClosure(current) && !hasExplicitSandboxPrototype(current))
|
|
26
|
+
break;
|
|
27
|
+
current = getSandboxPrototype(current, options.budget);
|
|
28
|
+
if (current !== null) {
|
|
29
|
+
options.budget?.visitNode();
|
|
30
|
+
assertSandboxDataDepth(++depth);
|
|
31
|
+
}
|
|
20
32
|
}
|
|
33
|
+
if (current === null)
|
|
34
|
+
return undefined;
|
|
21
35
|
if (property === "toString" && runResources.getStore()?.functionSourceText === false)
|
|
22
36
|
return undefined;
|
|
23
37
|
if (!isFunctionMethodName(property)) {
|
|
@@ -44,7 +58,7 @@ function callFunctionMethod(target, methodName, args, options, stack) {
|
|
|
44
58
|
const thisValue = args[0];
|
|
45
59
|
if (methodName === "bind") {
|
|
46
60
|
const boundArgs = args.slice(1);
|
|
47
|
-
|
|
61
|
+
const bound = createSandboxClosure({
|
|
48
62
|
guest: true,
|
|
49
63
|
sandbox: true,
|
|
50
64
|
name: `bound ${target.name ?? ""}`,
|
|
@@ -58,6 +72,9 @@ function callFunctionMethod(target, methodName, args, options, stack) {
|
|
|
58
72
|
construct: (callArgs, context) => options.callClosure(target, [...boundArgs, ...callArgs], context?.stack ?? [], undefined, true)
|
|
59
73
|
})
|
|
60
74
|
});
|
|
75
|
+
if (hasExplicitSandboxPrototype(target))
|
|
76
|
+
setSandboxPrototype(bound, getSandboxPrototype(target, options.budget), options.budget);
|
|
77
|
+
return bound;
|
|
61
78
|
}
|
|
62
79
|
if (methodName === "call") {
|
|
63
80
|
return options.callClosure(target, args.slice(1), stack, thisValue);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Budget } from "../budget.js";
|
|
2
2
|
import { type SandboxCallContext, type SandboxValue } from "../values.js";
|
|
3
3
|
export type NumberMethodName = "toExponential" | "toFixed" | "toPrecision" | "toString";
|
|
4
|
+
export declare const numberMethodNames: Set<NumberMethodName>;
|
|
4
5
|
export declare function getNumberMember(property: string | number, budget: Budget): SandboxValue | undefined;
|
|
5
6
|
export declare function isNumberMethodName(property: string | number): property is NumberMethodName;
|
|
6
7
|
export declare function callNumberMethod(value: SandboxValue, methodName: NumberMethodName, args: readonly SandboxValue[], budget: Budget, context?: SandboxCallContext): string | Promise<string>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { sandboxNumber } from "../string-coercion.js";
|
|
2
|
+
import { isSandboxBox, boxedValue } from "../boxed.js";
|
|
2
3
|
import { createSandboxClosure } from "../values.js";
|
|
3
|
-
const numberMethodNames = new Set([
|
|
4
|
+
export const numberMethodNames = new Set([
|
|
4
5
|
"toExponential",
|
|
5
6
|
"toFixed",
|
|
6
7
|
"toPrecision",
|
|
@@ -20,6 +21,8 @@ export function isNumberMethodName(property) {
|
|
|
20
21
|
return typeof property === "string" && numberMethodNames.has(property);
|
|
21
22
|
}
|
|
22
23
|
export function callNumberMethod(value, methodName, args, budget, context) {
|
|
24
|
+
if (isSandboxBox(value))
|
|
25
|
+
value = boxedValue(value);
|
|
23
26
|
if (typeof value !== "number") {
|
|
24
27
|
throw new TypeError(`Number#${methodName} requires a number receiver.`);
|
|
25
28
|
}
|
|
@@ -3,7 +3,9 @@ import { Budget } from "../budget.js";
|
|
|
3
3
|
import { CompileScope } from "../regex/compile-guard.js";
|
|
4
4
|
import { type SandboxCallContext, type SandboxClosure, type SandboxValue } from "../values.js";
|
|
5
5
|
type StringMethodName = "at" | "charAt" | "charCodeAt" | "codePointAt" | "concat" | "endsWith" | "includes" | "indexOf" | "isWellFormed" | "lastIndexOf" | "localeCompare" | "match" | "matchAll" | "normalize" | "padEnd" | "padStart" | "repeat" | "replace" | "replaceAll" | "slice" | "search" | "split" | "startsWith" | "substr" | "substring" | "toLowerCase" | "toUpperCase" | "toWellFormed" | "trim" | "trimEnd" | "trimStart";
|
|
6
|
+
export declare const stringMethodNames: Set<StringMethodName>;
|
|
6
7
|
export declare function getStringMember(value: string, property: string | number, budget: Budget): SandboxValue | undefined;
|
|
8
|
+
export declare function getStringIndex(property: string | number): number | undefined;
|
|
7
9
|
export declare function isStringMethodName(property: string | number): property is StringMethodName;
|
|
8
10
|
export declare function validateStringMethodArguments(_methodName: StringMethodName, _args: readonly Expression[]): void;
|
|
9
11
|
export declare function callStringMethod(value: string, methodName: StringMethodName, args: readonly SandboxValue[], budget: Budget, callClosure?: (closure: SandboxClosure, args: readonly SandboxValue[]) => Promise<SandboxValue>, parent?: CompileScope, context?: SandboxCallContext): SandboxValue | Promise<SandboxValue>;
|
|
@@ -6,7 +6,7 @@ import { retainValues } from "../resources.js";
|
|
|
6
6
|
import { createSandboxClosure, createSandboxRegex, deepCopyFromSandbox, isSandboxClosure, isSandboxRegex } from "../values.js";
|
|
7
7
|
import { executeRegex, toMatchArray } from "./regex.js";
|
|
8
8
|
const SPLIT_STRING_MESSAGE = "String#split only supports string separator values.";
|
|
9
|
-
const stringMethodNames = new Set([
|
|
9
|
+
export const stringMethodNames = new Set([
|
|
10
10
|
"at",
|
|
11
11
|
"charAt",
|
|
12
12
|
"charCodeAt",
|
|
@@ -72,7 +72,7 @@ export function getStringMember(value, property, budget) {
|
|
|
72
72
|
}
|
|
73
73
|
});
|
|
74
74
|
}
|
|
75
|
-
function getStringIndex(property) {
|
|
75
|
+
export function getStringIndex(property) {
|
|
76
76
|
const index = typeof property === "number" ? property : Number(property);
|
|
77
77
|
if (!Number.isInteger(index) || index < 0 || String(index) !== String(property)) {
|
|
78
78
|
return undefined;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Budget } from "./budget.js";
|
|
2
|
+
import { type BoxedPrimitive } from "./boxed.js";
|
|
2
3
|
import { type SandboxClosure, type SandboxObject, type SandboxValue } from "./values.js";
|
|
3
4
|
export declare function registerGuestClosure(closure: SandboxClosure): void;
|
|
4
5
|
export declare function isGuestClosure(value: unknown): value is SandboxClosure;
|
|
@@ -6,6 +7,10 @@ export declare function getGuestFunctionProperties(closure: SandboxClosure): San
|
|
|
6
7
|
export declare function materializeFunctionProperties(closure: SandboxClosure): SandboxObject;
|
|
7
8
|
export declare function getGuestFunctionProperty(closure: SandboxClosure, key: string): SandboxValue;
|
|
8
9
|
export declare function installObjectPrototype(budget: Budget, prototype: SandboxObject, constructor: SandboxClosure): void;
|
|
10
|
+
export declare function installBoxedPrototype(budget: Budget, prototype: SandboxObject, constructor: SandboxClosure): void;
|
|
11
|
+
export declare function getBoxedPrototype(value: BoxedPrimitive, budget: Budget): SandboxObject | undefined;
|
|
12
|
+
export declare function isDefaultBoxedMethod(value: BoxedPrimitive, key: string, budget: Budget): boolean;
|
|
13
|
+
export declare function isIntrinsicConstructor(value: object): boolean;
|
|
9
14
|
export declare function releaseObjectPrototype(budget: Budget): void;
|
|
10
15
|
export declare function getSandboxPrototype(value: object, budget?: Budget): object | null;
|
|
11
16
|
export declare function hasExplicitSandboxPrototype(value: object): boolean;
|