poe-code 14.0.40 → 14.0.42
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 +261 -193
- 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-LGJLTEI5.js → chunk-IRDBTJYC.js} +2 -2
- package/packages/safe-js/dist/chunks/{chunk-GO774BRE.js → chunk-M4M56OCI.js} +240 -184
- package/packages/safe-js/dist/chunks/chunk-M4M56OCI.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/index.js +2 -2
- package/packages/safe-js/dist/interp/async.d.ts +1 -0
- package/packages/safe-js/dist/interp/async.js +29 -26
- package/packages/safe-js/dist/interp/exceptions.d.ts +1 -0
- package/packages/safe-js/dist/interp/exceptions.js +2 -4
- package/packages/safe-js/dist/interp/interpreter.d.ts +1 -0
- package/packages/safe-js/dist/interp/interpreter.js +56 -62
- package/packages/safe-js/dist/interp/patterns.d.ts +1 -0
- package/packages/safe-js/dist/interp/patterns.js +8 -11
- package/packages/safe-js/dist/interp/property-key.d.ts +3 -0
- package/packages/safe-js/dist/interp/property-key.js +53 -0
- package/packages/safe-js/dist/snapshot/restore.js +23 -8
- package/packages/safe-js/dist/chunks/chunk-GO774BRE.js.map +0 -7
- /package/packages/safe-js/dist/chunks/{chunk-LGJLTEI5.js.map → chunk-IRDBTJYC.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-IRDBTJYC.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-M4M56OCI.js";
|
|
38
38
|
import "./chunks/chunk-UXMKEUH3.js";
|
|
39
39
|
import "./chunks/chunk-5DYEOCT5.js";
|
|
40
40
|
import "./chunks/chunk-4YIDX44G.js";
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
runWithSpawnUsageAccumulator,
|
|
27
27
|
splitFrontmatter,
|
|
28
28
|
supportsSpawnMode
|
|
29
|
-
} from "./chunks/chunk-
|
|
29
|
+
} from "./chunks/chunk-IRDBTJYC.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-M4M56OCI.js";
|
|
54
54
|
import "./chunks/chunk-UXMKEUH3.js";
|
|
55
55
|
import "./chunks/chunk-5DYEOCT5.js";
|
|
56
56
|
import "./chunks/chunk-4YIDX44G.js";
|
|
@@ -52,6 +52,7 @@ export declare function emitResumeBreakpoint(context: AsyncEvaluationContext, br
|
|
|
52
52
|
export declare function evaluateArrowFunctionExpression(node: ArrowFunctionExpression, context: AsyncEvaluationContext, evaluateNode: EvaluateAsyncNode): Promise<AsyncEvaluationResult>;
|
|
53
53
|
export declare function evaluateFunctionExpression(node: FunctionExpression, context: AsyncEvaluationContext, evaluateNode: EvaluateAsyncNode): Promise<AsyncEvaluationResult>;
|
|
54
54
|
export declare function createInterpretedClosure(node: ArrowFunctionExpression | FunctionDeclaration | FunctionExpression, context: AsyncEvaluationContext, evaluateNode: EvaluateAsyncNode): import("./values.js").SandboxClosure;
|
|
55
|
+
export declare function executeAsyncFunction(execute: (onSuspend: () => void) => Promise<SandboxValue>, budget: Budget, signal?: AbortSignal): import("./values.js").SandboxPromise;
|
|
55
56
|
export declare function evaluateAwaitExpression(node: AwaitExpression, context: AsyncEvaluationContext, evaluateNode: EvaluateAsyncNode): Promise<AsyncEvaluationResult>;
|
|
56
57
|
export declare function normalizeClosureResult(result: SandboxValue | Promise<SandboxValue> | PromiseLike<SandboxValue>, budget?: Budget): SandboxValue;
|
|
57
58
|
export {};
|
|
@@ -81,36 +81,39 @@ export function createInterpretedClosure(node, context, evaluateNode) {
|
|
|
81
81
|
};
|
|
82
82
|
if (!node.async)
|
|
83
83
|
return executeClosure(node, args, callContext?.thisValue, invocationContext, evaluateNode);
|
|
84
|
-
|
|
85
|
-
const synchronousPrefix = new Promise((resolve) => {
|
|
86
|
-
completePrefix = resolve;
|
|
87
|
-
});
|
|
88
|
-
const promise = new Promise((resolve, reject) => {
|
|
89
|
-
runAsyncPrefix(async () => {
|
|
90
|
-
try {
|
|
91
|
-
const value = await executeClosure(node, args, callContext?.thisValue, { ...invocationContext, onSuspend: completePrefix }, evaluateNode);
|
|
92
|
-
resolve(isSandboxPromise(value) || getThenable(value) !== undefined
|
|
93
|
-
? awaitSandboxValue(createSandboxPromise(resolveSandboxValue(value, { budget: context.budget }), {
|
|
94
|
-
trackReplay: false
|
|
95
|
-
}), context.signal, context.budget)
|
|
96
|
-
: allocateProducedSandboxValue(value, context.budget));
|
|
97
|
-
}
|
|
98
|
-
catch (error) {
|
|
99
|
-
reject(error);
|
|
100
|
-
}
|
|
101
|
-
finally {
|
|
102
|
-
completePrefix();
|
|
103
|
-
}
|
|
104
|
-
}).catch((error) => {
|
|
105
|
-
reject(error);
|
|
106
|
-
completePrefix();
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
return createSandboxPromise(promise, { synchronousPrefix });
|
|
84
|
+
return executeAsyncFunction((onSuspend) => executeClosure(node, args, callContext?.thisValue, { ...invocationContext, onSuspend }, evaluateNode), context.budget, context.signal);
|
|
110
85
|
}
|
|
111
86
|
});
|
|
112
87
|
return closure;
|
|
113
88
|
}
|
|
89
|
+
export function executeAsyncFunction(execute, budget, signal) {
|
|
90
|
+
let completePrefix;
|
|
91
|
+
const synchronousPrefix = new Promise((resolve) => {
|
|
92
|
+
completePrefix = resolve;
|
|
93
|
+
});
|
|
94
|
+
const promise = new Promise((resolve, reject) => {
|
|
95
|
+
runAsyncPrefix(async () => {
|
|
96
|
+
try {
|
|
97
|
+
const value = await execute(completePrefix);
|
|
98
|
+
resolve(isSandboxPromise(value) || getThenable(value) !== undefined
|
|
99
|
+
? awaitSandboxValue(createSandboxPromise(resolveSandboxValue(value, { budget }), {
|
|
100
|
+
trackReplay: false
|
|
101
|
+
}), signal, budget)
|
|
102
|
+
: allocateProducedSandboxValue(value, budget));
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
reject(error);
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
completePrefix();
|
|
109
|
+
}
|
|
110
|
+
}).catch((error) => {
|
|
111
|
+
reject(error);
|
|
112
|
+
completePrefix();
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
return createSandboxPromise(promise, { synchronousPrefix });
|
|
116
|
+
}
|
|
114
117
|
function createGeneratorClosure(node, context, evaluateNode) {
|
|
115
118
|
return createSandboxClosure({
|
|
116
119
|
guest: true,
|
|
@@ -29,6 +29,7 @@ type ExceptionContext = {
|
|
|
29
29
|
budget: Budget;
|
|
30
30
|
callStack: readonly string[];
|
|
31
31
|
scope: Scope;
|
|
32
|
+
toPropertyKey?: (value: SandboxValue) => Promise<string>;
|
|
32
33
|
};
|
|
33
34
|
type EvaluateExceptionNode<TContext, TError> = (node: ParseResult, context: TContext) => Promise<EvaluationResult<TError>>;
|
|
34
35
|
export declare function evaluateThrowStatement<TContext extends ExceptionContext, TError>(node: ThrowStatement, context: TContext, evaluateNode: EvaluateExceptionNode<TContext, TError>): Promise<EvaluationResult<TError>>;
|
|
@@ -3,6 +3,7 @@ import { SandboxError } from "./budget.js";
|
|
|
3
3
|
import { HostCallResumabilityError } from "./host-call.js";
|
|
4
4
|
import { withFatalPromiseCleanup } from "./promise-tracker.js";
|
|
5
5
|
import { deepCopyToSandbox } from "./values.js";
|
|
6
|
+
import { toPropertyKey } from "./property-key.js";
|
|
6
7
|
const capturedExceptionBrand = Symbol("CapturedException");
|
|
7
8
|
export async function evaluateThrowStatement(node, context, evaluateNode) {
|
|
8
9
|
const argument = await evaluateNode(node.argument, context);
|
|
@@ -389,12 +390,9 @@ async function resolvePatternPropertyKey(property, context, evaluateNode) {
|
|
|
389
390
|
result: computedKey
|
|
390
391
|
};
|
|
391
392
|
}
|
|
392
|
-
if (typeof computedKey.value !== "string" && typeof computedKey.value !== "number") {
|
|
393
|
-
throw new TypeError("Computed catch binding keys must evaluate to a string or number.");
|
|
394
|
-
}
|
|
395
393
|
return {
|
|
396
394
|
ok: true,
|
|
397
|
-
value: computedKey.value
|
|
395
|
+
value: await (context.toPropertyKey?.(computedKey.value) ?? toPropertyKey(computedKey.value, context.budget, { stack: context.callStack, thisValue: undefined }))
|
|
398
396
|
};
|
|
399
397
|
}
|
|
400
398
|
function getStaticPropertyKey(property) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { promiseReplayContext } from "./promise-replay.js";
|
|
2
2
|
import { deleteHostObjectMember, getHostObjectKeys, getHostObjectMember, hasHostObjectMember, isGuestHostObject, setHostObjectMember } from "./host-capabilities.js";
|
|
3
|
-
import {
|
|
3
|
+
import { toPropertyKey } from "./property-key.js";
|
|
4
4
|
import { assertPromiseExecutionAllowed } from "./promise-tracker.js";
|
|
5
5
|
import { SandboxJobQueue, runAsyncPrefix, suspendJob } from "./jobs.js";
|
|
6
6
|
import { withCancellationSignal } from "./cancel.js";
|
|
@@ -111,6 +111,7 @@ export async function interpret(node, options = {}) {
|
|
|
111
111
|
budget,
|
|
112
112
|
callStack: [],
|
|
113
113
|
onYield: options.onYield,
|
|
114
|
+
onSuspend: options.onSuspend,
|
|
114
115
|
captureReplayState: options.captureReplayState,
|
|
115
116
|
rootNode: node,
|
|
116
117
|
scope,
|
|
@@ -443,7 +444,7 @@ async function evaluateBinaryExpression(node, context) {
|
|
|
443
444
|
if (typeof right.value !== "object" || right.value === null) {
|
|
444
445
|
throw new TypeError("Right-hand side of 'in' must be an object.");
|
|
445
446
|
}
|
|
446
|
-
leftValue = await toPropertyKey(leftValue, context);
|
|
447
|
+
leftValue = await toPropertyKey(leftValue, context.budget, createCoercionContext(context));
|
|
447
448
|
}
|
|
448
449
|
const value = applyBinaryOperator(node, leftValue, right.value, context);
|
|
449
450
|
return {
|
|
@@ -534,7 +535,15 @@ async function evaluateMemberAssignmentExpression(node, context) {
|
|
|
534
535
|
if (member.kind === "nullish") {
|
|
535
536
|
throw new TypeError("Cannot assign properties of null or undefined.");
|
|
536
537
|
}
|
|
537
|
-
|
|
538
|
+
let property;
|
|
539
|
+
let current = undefined;
|
|
540
|
+
if (node.operator !== "=") {
|
|
541
|
+
if (member.object === null || member.object === undefined) {
|
|
542
|
+
throw new TypeError("Cannot assign properties of null or undefined.");
|
|
543
|
+
}
|
|
544
|
+
property = await toPropertyKey(member.property, context.budget, createCoercionContext(context));
|
|
545
|
+
current = getPropertyValue(member.object, property, context);
|
|
546
|
+
}
|
|
538
547
|
if (node.operator === "&&=" && !isTruthy(current)) {
|
|
539
548
|
return {
|
|
540
549
|
kind: "normal",
|
|
@@ -566,7 +575,11 @@ async function evaluateMemberAssignmentExpression(node, context) {
|
|
|
566
575
|
node.operator === "??="
|
|
567
576
|
? right.value
|
|
568
577
|
: await applyCompoundAssignmentOperator(node.operator, current, right.value, context);
|
|
569
|
-
|
|
578
|
+
if (member.object === null || member.object === undefined) {
|
|
579
|
+
throw new TypeError("Cannot assign properties of null or undefined.");
|
|
580
|
+
}
|
|
581
|
+
property ??= await toPropertyKey(member.property, context.budget, createCoercionContext(context));
|
|
582
|
+
setSandboxProperty(member.object, property, value, context.budget);
|
|
570
583
|
return {
|
|
571
584
|
kind: "normal",
|
|
572
585
|
hasValue: true,
|
|
@@ -1522,7 +1535,10 @@ async function evaluateThrowStatement(node, context) {
|
|
|
1522
1535
|
return evaluateThrowStatementResult(node, context, evaluateNode);
|
|
1523
1536
|
}
|
|
1524
1537
|
async function evaluateTryStatement(node, context) {
|
|
1525
|
-
return evaluateTryStatementResult(node,
|
|
1538
|
+
return evaluateTryStatementResult(node, {
|
|
1539
|
+
...context,
|
|
1540
|
+
toPropertyKey: (value) => toPropertyKey(value, context.budget, createCoercionContext(context))
|
|
1541
|
+
}, evaluateNode);
|
|
1526
1542
|
}
|
|
1527
1543
|
async function evaluateUnaryExpression(node, context) {
|
|
1528
1544
|
if (node.operator === "delete") {
|
|
@@ -1565,8 +1581,8 @@ async function evaluateDeleteExpression(node, context) {
|
|
|
1565
1581
|
if (member.kind === "completion") {
|
|
1566
1582
|
return member.result;
|
|
1567
1583
|
}
|
|
1568
|
-
if (member.kind === "nullish") {
|
|
1569
|
-
if (node.argument.optional) {
|
|
1584
|
+
if (member.kind === "nullish" || member.object === null || member.object === undefined) {
|
|
1585
|
+
if (member.kind === "nullish" && node.argument.optional) {
|
|
1570
1586
|
return {
|
|
1571
1587
|
kind: "normal",
|
|
1572
1588
|
hasValue: true,
|
|
@@ -1578,7 +1594,8 @@ async function evaluateDeleteExpression(node, context) {
|
|
|
1578
1594
|
if (!isIndexableSandboxValue(member.object)) {
|
|
1579
1595
|
throw new TypeError("Unary operator 'delete' requires a sandbox object property.");
|
|
1580
1596
|
}
|
|
1581
|
-
const
|
|
1597
|
+
const property = await toPropertyKey(member.property, context.budget, createCoercionContext(context));
|
|
1598
|
+
const deleted = deleteSandboxProperty(member.object, property);
|
|
1582
1599
|
return {
|
|
1583
1600
|
kind: "normal",
|
|
1584
1601
|
hasValue: true,
|
|
@@ -1622,12 +1639,13 @@ async function evaluateMemberUpdateExpression(node, context) {
|
|
|
1622
1639
|
if (member.kind === "completion") {
|
|
1623
1640
|
return member.result;
|
|
1624
1641
|
}
|
|
1625
|
-
if (member.kind === "nullish") {
|
|
1642
|
+
if (member.kind === "nullish" || member.object === null || member.object === undefined) {
|
|
1626
1643
|
throw new TypeError("Cannot update properties of null or undefined.");
|
|
1627
1644
|
}
|
|
1628
|
-
const
|
|
1645
|
+
const property = await toPropertyKey(member.property, context.budget, createCoercionContext(context));
|
|
1646
|
+
const current = toNumber(await toNumericPrimitive(getPropertyValue(member.object, property, context), context));
|
|
1629
1647
|
const next = node.operator === "++" ? current + 1 : current - 1;
|
|
1630
|
-
setSandboxProperty(member.object,
|
|
1648
|
+
setSandboxProperty(member.object, property, next, context.budget);
|
|
1631
1649
|
return {
|
|
1632
1650
|
kind: "normal",
|
|
1633
1651
|
hasValue: true,
|
|
@@ -1640,15 +1658,15 @@ async function evaluateMemberExpression(node, context) {
|
|
|
1640
1658
|
return member;
|
|
1641
1659
|
if (member.kind === "completion")
|
|
1642
1660
|
return member.result;
|
|
1643
|
-
if (member.kind === "nullish") {
|
|
1644
|
-
if (node.optional)
|
|
1661
|
+
if (member.kind === "nullish" || member.object === null || member.object === undefined) {
|
|
1662
|
+
if (member.kind === "nullish" && node.optional)
|
|
1645
1663
|
return { kind: "normal", hasValue: true, value: undefined };
|
|
1646
1664
|
throw new TypeError("Cannot read properties of null or undefined.");
|
|
1647
1665
|
}
|
|
1648
1666
|
return {
|
|
1649
1667
|
kind: "normal",
|
|
1650
1668
|
hasValue: true,
|
|
1651
|
-
value: getPropertyValue(member.object, member.property, context)
|
|
1669
|
+
value: getPropertyValue(member.object, await toPropertyKey(member.property, context.budget, createCoercionContext(context)), context)
|
|
1652
1670
|
};
|
|
1653
1671
|
}
|
|
1654
1672
|
function getPropertyValue(target, property, context) {
|
|
@@ -1685,6 +1703,7 @@ export function createPatternContext(context, scope = context.scope, evaluate =
|
|
|
1685
1703
|
const evaluationContext = { ...context, scope };
|
|
1686
1704
|
return {
|
|
1687
1705
|
evaluate: node => evaluate(node, evaluationContext),
|
|
1706
|
+
toPropertyKey: value => toPropertyKey(value, context.budget, createCoercionContext(evaluationContext)),
|
|
1688
1707
|
getProperty: (value, key) => getPropertyValue(value, key, evaluationContext),
|
|
1689
1708
|
setProperty: (target, key, value) => setSandboxProperty(target, key, value, context.budget)
|
|
1690
1709
|
};
|
|
@@ -1772,24 +1791,10 @@ async function evaluateMemberAccess(node, context) {
|
|
|
1772
1791
|
};
|
|
1773
1792
|
}
|
|
1774
1793
|
const property = node.computed
|
|
1775
|
-
? await
|
|
1776
|
-
: {
|
|
1777
|
-
if (
|
|
1778
|
-
return
|
|
1779
|
-
? {
|
|
1780
|
-
kind: "error",
|
|
1781
|
-
error: property.result.error
|
|
1782
|
-
}
|
|
1783
|
-
: {
|
|
1784
|
-
kind: "completion",
|
|
1785
|
-
result: property.result
|
|
1786
|
-
};
|
|
1787
|
-
}
|
|
1788
|
-
if (object.value === null || object.value === undefined) {
|
|
1789
|
-
return {
|
|
1790
|
-
kind: "nullish"
|
|
1791
|
-
};
|
|
1792
|
-
}
|
|
1794
|
+
? await evaluateNode(node.property, context)
|
|
1795
|
+
: { kind: "normal", value: getStaticPropertyName(node.property) };
|
|
1796
|
+
if (property.kind !== "normal")
|
|
1797
|
+
return { kind: "completion", result: property };
|
|
1793
1798
|
return {
|
|
1794
1799
|
kind: "resolved",
|
|
1795
1800
|
object: object.value,
|
|
@@ -1804,13 +1809,10 @@ async function evaluateMemberProperty(node, context) {
|
|
|
1804
1809
|
result: property
|
|
1805
1810
|
};
|
|
1806
1811
|
}
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
};
|
|
1812
|
-
}
|
|
1813
|
-
throw new TypeError("Computed property access requires a string or number key.");
|
|
1812
|
+
return {
|
|
1813
|
+
ok: true,
|
|
1814
|
+
value: await toPropertyKey(property.value, context.budget, createCoercionContext(context))
|
|
1815
|
+
};
|
|
1814
1816
|
}
|
|
1815
1817
|
async function evaluateObjectPropertyKey(node, context) {
|
|
1816
1818
|
if (!node.computed) {
|
|
@@ -1834,15 +1836,15 @@ async function evaluateMemberCallExpression(node, context) {
|
|
|
1834
1836
|
if (node.callee.type !== "MemberExpression") {
|
|
1835
1837
|
throw new TypeError("Expected member call expression.");
|
|
1836
1838
|
}
|
|
1837
|
-
const
|
|
1838
|
-
if (
|
|
1839
|
-
return
|
|
1839
|
+
const reference = await evaluateMemberAccess(node.callee, context);
|
|
1840
|
+
if (reference.kind === "error") {
|
|
1841
|
+
return reference;
|
|
1840
1842
|
}
|
|
1841
|
-
if (
|
|
1842
|
-
return
|
|
1843
|
+
if (reference.kind === "completion") {
|
|
1844
|
+
return reference.result;
|
|
1843
1845
|
}
|
|
1844
|
-
if (
|
|
1845
|
-
if (
|
|
1846
|
+
if (reference.kind === "nullish" || reference.object === null || reference.object === undefined) {
|
|
1847
|
+
if (reference.kind === "nullish") {
|
|
1846
1848
|
return {
|
|
1847
1849
|
kind: "normal",
|
|
1848
1850
|
hasValue: true,
|
|
@@ -1851,6 +1853,10 @@ async function evaluateMemberCallExpression(node, context) {
|
|
|
1851
1853
|
}
|
|
1852
1854
|
throw new TypeError("Cannot read properties of null or undefined.");
|
|
1853
1855
|
}
|
|
1856
|
+
const member = {
|
|
1857
|
+
...reference,
|
|
1858
|
+
property: await toPropertyKey(reference.property, context.budget, createCoercionContext(context))
|
|
1859
|
+
};
|
|
1854
1860
|
if (typeof member.object === "string" && isStringMethodName(member.property)) {
|
|
1855
1861
|
return evaluateStringMethodCall(node, member.object, member.property, context);
|
|
1856
1862
|
}
|
|
@@ -2123,25 +2129,13 @@ function applyBinaryOperator(node, left, right, context) {
|
|
|
2123
2129
|
return hasSandboxProperty(right, left, context);
|
|
2124
2130
|
}
|
|
2125
2131
|
}
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
!isSandboxGenerator(value) && !isGuestHostObject(value)) {
|
|
2129
|
-
for (const name of ["toString", "valueOf"]) {
|
|
2130
|
-
const method = getMemberValue(value, name, context);
|
|
2131
|
-
if (!isSandboxClosure(method))
|
|
2132
|
-
continue;
|
|
2133
|
-
const primitive = await invokeSandboxClosure(method, [], context, context.callStack, undefined, value);
|
|
2134
|
-
if (primitive === null || typeof primitive !== "object") {
|
|
2135
|
-
return context.budget.allocateString(String(primitive));
|
|
2136
|
-
}
|
|
2137
|
-
}
|
|
2138
|
-
throw new TypeError("Cannot convert object to primitive value.");
|
|
2139
|
-
}
|
|
2140
|
-
return sandboxString(value, context.budget, {
|
|
2132
|
+
function createCoercionContext(context) {
|
|
2133
|
+
return {
|
|
2141
2134
|
stack: context.callStack,
|
|
2142
2135
|
thisValue: undefined,
|
|
2136
|
+
compilation: context.compilation,
|
|
2143
2137
|
invokeClosure: (closure, args, thisValue) => invokeSandboxClosure(closure, args, context, context.callStack, undefined, thisValue)
|
|
2144
|
-
}
|
|
2138
|
+
};
|
|
2145
2139
|
}
|
|
2146
2140
|
function hasSandboxProperty(value, key, context) {
|
|
2147
2141
|
let current = value;
|
|
@@ -11,6 +11,7 @@ export type PatternTarget = {
|
|
|
11
11
|
};
|
|
12
12
|
export type PatternContext = {
|
|
13
13
|
evaluate(node: ParseResult): Promise<AsyncEvaluationResult>;
|
|
14
|
+
toPropertyKey(value: SandboxValue): Promise<string>;
|
|
14
15
|
getProperty(value: SandboxValue, key: string | number): SandboxValue;
|
|
15
16
|
setProperty(target: SandboxValue, key: string | number, value: SandboxValue): void;
|
|
16
17
|
};
|
|
@@ -90,19 +90,19 @@ async function bindMemberExpression(pattern, value, scope, context) {
|
|
|
90
90
|
if (object.kind !== "normal") {
|
|
91
91
|
return { ok: false, result: object };
|
|
92
92
|
}
|
|
93
|
+
const property = pattern.computed
|
|
94
|
+
? await context.evaluate(pattern.property)
|
|
95
|
+
: { kind: "normal", value: getStaticPropertyName(pattern.property) };
|
|
96
|
+
if (property.kind !== "normal") {
|
|
97
|
+
return { ok: false, result: property };
|
|
98
|
+
}
|
|
93
99
|
if (object.value === null || object.value === undefined) {
|
|
94
100
|
throw new TypeError("Cannot assign properties of null or undefined.");
|
|
95
101
|
}
|
|
96
102
|
if (!isIndexableValue(object.value)) {
|
|
97
103
|
throw new TypeError("Assignment expressions require a sandbox object property.");
|
|
98
104
|
}
|
|
99
|
-
|
|
100
|
-
? await evaluateProperty(pattern.property, context)
|
|
101
|
-
: { ok: true, value: getStaticPropertyName(pattern.property) };
|
|
102
|
-
if (!property.ok) {
|
|
103
|
-
return property;
|
|
104
|
-
}
|
|
105
|
-
context.setProperty(object.value, property.value, value);
|
|
105
|
+
context.setProperty(object.value, await context.toPropertyKey(property.value), value);
|
|
106
106
|
return { ok: true };
|
|
107
107
|
}
|
|
108
108
|
async function evaluatePatternKey(property, context) {
|
|
@@ -115,10 +115,7 @@ async function evaluateProperty(property, context) {
|
|
|
115
115
|
if (result.kind !== "normal") {
|
|
116
116
|
return { ok: false, result };
|
|
117
117
|
}
|
|
118
|
-
|
|
119
|
-
throw new TypeError("Computed property access requires a string or number key.");
|
|
120
|
-
}
|
|
121
|
-
return { ok: true, value: result.value };
|
|
118
|
+
return { ok: true, value: await context.toPropertyKey(result.value) };
|
|
122
119
|
}
|
|
123
120
|
function getStaticPropertyName(property) {
|
|
124
121
|
if (property.type === "Identifier") {
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { isSandboxDate } from "./date.js";
|
|
2
|
+
import { isFloat32Array } from "./float32.js";
|
|
3
|
+
import { isGuestHostObject } from "./host-capabilities.js";
|
|
4
|
+
import { getSandboxDataProperty } from "./object-model.js";
|
|
5
|
+
import { sandboxString } from "./string-coercion.js";
|
|
6
|
+
import { isSandboxClosure, isSandboxGenerator, isSandboxMap, isSandboxPromise, isSandboxRegex, isSandboxSet } from "./values.js";
|
|
7
|
+
export async function toPropertyKey(value, budget, context) {
|
|
8
|
+
if (typeof value === "string")
|
|
9
|
+
return value;
|
|
10
|
+
const invocation = context.invokeClosure === undefined
|
|
11
|
+
? {
|
|
12
|
+
...context,
|
|
13
|
+
invokeClosure: async (closure, args, thisValue) => {
|
|
14
|
+
const leaveCall = budget.enterCall();
|
|
15
|
+
try {
|
|
16
|
+
const result = closure.call(args, { ...invocation, thisValue });
|
|
17
|
+
if (isSandboxPromise(result)) {
|
|
18
|
+
await result.synchronousPrefix;
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
return await result;
|
|
22
|
+
}
|
|
23
|
+
finally {
|
|
24
|
+
leaveCall();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
: context;
|
|
29
|
+
if (typeof value === "object" &&
|
|
30
|
+
value !== null &&
|
|
31
|
+
!Array.isArray(value) &&
|
|
32
|
+
!isSandboxClosure(value) &&
|
|
33
|
+
!isSandboxMap(value) &&
|
|
34
|
+
!isSandboxSet(value) &&
|
|
35
|
+
!isSandboxPromise(value) &&
|
|
36
|
+
!isSandboxRegex(value) &&
|
|
37
|
+
!isSandboxDate(value) &&
|
|
38
|
+
!isFloat32Array(value) &&
|
|
39
|
+
!isSandboxGenerator(value) &&
|
|
40
|
+
!isGuestHostObject(value)) {
|
|
41
|
+
for (const name of ["toString", "valueOf"]) {
|
|
42
|
+
const method = getSandboxDataProperty(value, name, budget);
|
|
43
|
+
if (!isSandboxClosure(method))
|
|
44
|
+
continue;
|
|
45
|
+
const primitive = await invocation.invokeClosure(method, [], value);
|
|
46
|
+
if (primitive === null || typeof primitive !== "object") {
|
|
47
|
+
return budget.allocateString(String(primitive));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
throw new TypeError("Cannot convert object to primitive value.");
|
|
51
|
+
}
|
|
52
|
+
return sandboxString(value, budget, invocation);
|
|
53
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Budget, SandboxError } from "../interp/budget.js";
|
|
2
|
+
import { executeAsyncFunction } from "../interp/async.js";
|
|
3
|
+
import { toPropertyKey } from "../interp/property-key.js";
|
|
2
4
|
import { CompileScope } from "../interp/regex/compile-guard.js";
|
|
3
5
|
import { decodeFloat32Storage } from "./float32array.js";
|
|
4
6
|
import { restoreDateTime } from "../interp/date.js";
|
|
@@ -429,7 +431,8 @@ function restoreClosureValue(astNodeId, capturedScopeId, state) {
|
|
|
429
431
|
throw new Error(`Snapshot references unknown closure AST node ${astNodeId}.`);
|
|
430
432
|
}
|
|
431
433
|
const baseClosure = createSandboxClosure({
|
|
432
|
-
async:
|
|
434
|
+
async: node.async,
|
|
435
|
+
sandbox: true,
|
|
433
436
|
length: getFunctionLength(node.params),
|
|
434
437
|
...(node.type === "ArrowFunctionExpression" || node.id === undefined ? {} : { name: node.id.name }),
|
|
435
438
|
...(node.type !== "ArrowFunctionExpression" &&
|
|
@@ -437,18 +440,23 @@ function restoreClosureValue(astNodeId, capturedScopeId, state) {
|
|
|
437
440
|
!node.generator &&
|
|
438
441
|
!node.async
|
|
439
442
|
? {
|
|
440
|
-
construct: async (args) => {
|
|
443
|
+
construct: async (args, callContext) => {
|
|
441
444
|
const thisValue = {};
|
|
442
445
|
const prototype = getGuestFunctionProperty(restoredClosure, "prototype");
|
|
443
446
|
if (typeof prototype === "object" && prototype !== null) {
|
|
444
447
|
setSandboxPrototype(thisValue, prototype, state.budget);
|
|
445
448
|
}
|
|
446
|
-
const result = await executeRestoredClosure(node, capturedScopeId, restoredClosure, args, thisValue, state);
|
|
449
|
+
const result = await executeRestoredClosure(node, capturedScopeId, restoredClosure, args, thisValue, state, callContext);
|
|
447
450
|
return typeof result === "object" && result !== null ? result : thisValue;
|
|
448
451
|
}
|
|
449
452
|
}
|
|
450
453
|
: {}),
|
|
451
|
-
call: (args, callContext) =>
|
|
454
|
+
call: (args, callContext) => {
|
|
455
|
+
if (node.async) {
|
|
456
|
+
return executeAsyncFunction((onSuspend) => executeRestoredClosure(node, capturedScopeId, restoredClosure, args, callContext?.thisValue, state, callContext, onSuspend), state.budget);
|
|
457
|
+
}
|
|
458
|
+
return executeRestoredClosure(node, capturedScopeId, restoredClosure, args, callContext?.thisValue, state, callContext);
|
|
459
|
+
}
|
|
452
460
|
});
|
|
453
461
|
const restoredClosure = Object.defineProperties(Object.create(baseClosure), {
|
|
454
462
|
astNodeId: {
|
|
@@ -468,9 +476,10 @@ function restoreClosureValue(astNodeId, capturedScopeId, state) {
|
|
|
468
476
|
Object.defineProperty(restoredClosure, "properties", { get: () => getGuestFunctionProperties(restoredClosure) });
|
|
469
477
|
return restoredClosure;
|
|
470
478
|
}
|
|
471
|
-
async function executeRestoredClosure(node, capturedScopeId, closure, args, thisValue, state) {
|
|
472
|
-
const
|
|
473
|
-
const
|
|
479
|
+
async function executeRestoredClosure(node, capturedScopeId, closure, args, thisValue, state, callContext, onSuspend) {
|
|
480
|
+
const parent = callContext?.compilation ?? state.compilation;
|
|
481
|
+
const operation = state.budget.acquireCompileOwner(false, parent.owner);
|
|
482
|
+
const compilation = new CompileScope(operation.owner, parent);
|
|
474
483
|
state = { ...state, compilation };
|
|
475
484
|
try {
|
|
476
485
|
const capturedScope = state.scopeById.get(capturedScopeId) ?? restoreParentScope(capturedScopeId, state);
|
|
@@ -492,6 +501,7 @@ async function executeRestoredClosure(node, capturedScopeId, closure, args, this
|
|
|
492
501
|
const rest = args.slice(index);
|
|
493
502
|
state.budget.allocateArrayLength(rest.length);
|
|
494
503
|
const binding = await bindPattern(param, rest, { kind: "let" }, scope, {
|
|
504
|
+
toPropertyKey: value => toPropertyKey(value, state.budget, { ...callContext, stack: callContext?.stack ?? [], thisValue, compilation }),
|
|
495
505
|
getProperty: (value, key) => getSandboxDataProperty(value, key, state.budget),
|
|
496
506
|
setProperty: (target, key, value) => setSandboxProperty(target, key, value, state.budget),
|
|
497
507
|
evaluate: async (defaultNode) => {
|
|
@@ -499,6 +509,7 @@ async function executeRestoredClosure(node, capturedScopeId, closure, args, this
|
|
|
499
509
|
budget: state.budget,
|
|
500
510
|
compilation,
|
|
501
511
|
scope,
|
|
512
|
+
nested: true,
|
|
502
513
|
useScopeDirectly: true
|
|
503
514
|
});
|
|
504
515
|
return result.ok
|
|
@@ -521,6 +532,7 @@ async function executeRestoredClosure(node, capturedScopeId, closure, args, this
|
|
|
521
532
|
break;
|
|
522
533
|
}
|
|
523
534
|
const binding = await bindPattern(param, args[index], { kind: "let" }, scope, {
|
|
535
|
+
toPropertyKey: value => toPropertyKey(value, state.budget, { ...callContext, stack: callContext?.stack ?? [], thisValue, compilation }),
|
|
524
536
|
getProperty: (value, key) => getSandboxDataProperty(value, key, state.budget),
|
|
525
537
|
setProperty: (target, key, value) => setSandboxProperty(target, key, value, state.budget),
|
|
526
538
|
evaluate: async (defaultNode) => {
|
|
@@ -528,6 +540,7 @@ async function executeRestoredClosure(node, capturedScopeId, closure, args, this
|
|
|
528
540
|
budget: state.budget,
|
|
529
541
|
compilation,
|
|
530
542
|
scope,
|
|
543
|
+
nested: true,
|
|
531
544
|
useScopeDirectly: true
|
|
532
545
|
});
|
|
533
546
|
return result.ok
|
|
@@ -551,12 +564,14 @@ async function executeRestoredClosure(node, capturedScopeId, closure, args, this
|
|
|
551
564
|
const result = await interpret(node.body, {
|
|
552
565
|
budget: state.budget,
|
|
553
566
|
compilation,
|
|
567
|
+
nested: true,
|
|
568
|
+
onSuspend,
|
|
554
569
|
scope
|
|
555
570
|
});
|
|
556
571
|
if (!result.ok) {
|
|
557
572
|
throw new Error(result.error.message);
|
|
558
573
|
}
|
|
559
|
-
reconcileCompiledValues(state.budget, [...scope.retainedValues(), ...state.budget.retainedValues(), result.returnValue], compilation);
|
|
574
|
+
reconcileCompiledValues(state.budget, [...scope.retainedValues(), ...state.budget.retainedValues(), result.returnValue], compilation, parent, [result.returnValue]);
|
|
560
575
|
return result.returnValue;
|
|
561
576
|
}
|
|
562
577
|
finally {
|