poe-code 14.0.65 → 14.0.66
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 +1723 -797
- 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-4VT2M7WL.js → chunk-MKTUVVEB.js} +2 -2
- package/packages/safe-js/dist/chunks/{chunk-WBWD7ZCM.js → chunk-YKISHTWT.js} +1675 -772
- package/packages/safe-js/dist/chunks/chunk-YKISHTWT.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/accessors.d.ts +9 -0
- package/packages/safe-js/dist/interp/accessors.js +68 -0
- package/packages/safe-js/dist/interp/async.js +3 -3
- package/packages/safe-js/dist/interp/classes.js +10 -4
- package/packages/safe-js/dist/interp/exceptions.d.ts +1 -1
- package/packages/safe-js/dist/interp/exceptions.js +47 -8
- package/packages/safe-js/dist/interp/globals/collections.js +53 -16
- package/packages/safe-js/dist/interp/globals/console-json.js +41 -26
- package/packages/safe-js/dist/interp/globals/object-array.js +229 -68
- package/packages/safe-js/dist/interp/globals/object.js +6 -3
- package/packages/safe-js/dist/interp/globals/primitives.js +11 -5
- package/packages/safe-js/dist/interp/interpreter.d.ts +2 -2
- package/packages/safe-js/dist/interp/interpreter.js +83 -44
- package/packages/safe-js/dist/interp/iteration.js +13 -0
- package/packages/safe-js/dist/interp/methods/array.d.ts +1 -1
- package/packages/safe-js/dist/interp/methods/array.js +368 -109
- package/packages/safe-js/dist/interp/methods/function.js +56 -20
- package/packages/safe-js/dist/interp/methods/regex.js +1 -1
- package/packages/safe-js/dist/interp/object-model.d.ts +1 -0
- package/packages/safe-js/dist/interp/object-model.js +48 -10
- package/packages/safe-js/dist/interp/patterns.d.ts +2 -2
- package/packages/safe-js/dist/interp/patterns.js +35 -16
- package/packages/safe-js/dist/interp/promise.d.ts +1 -1
- package/packages/safe-js/dist/interp/promise.js +103 -63
- package/packages/safe-js/dist/interp/string-coercion.d.ts +1 -0
- package/packages/safe-js/dist/interp/string-coercion.js +47 -37
- package/packages/safe-js/dist/interp/values.d.ts +2 -1
- package/packages/safe-js/dist/interp/values.js +26 -1
- package/packages/safe-js/dist/parse/parser.d.ts +1 -1
- package/packages/safe-js/dist/parse/parser.js +37 -8
- package/packages/safe-js/dist/chunks/chunk-WBWD7ZCM.js.map +0 -7
- /package/packages/safe-js/dist/chunks/{chunk-4VT2M7WL.js.map → chunk-MKTUVVEB.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-MKTUVVEB.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-YKISHTWT.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-MKTUVVEB.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-YKISHTWT.js";
|
|
54
54
|
import "./chunks/chunk-UXMKEUH3.js";
|
|
55
55
|
import "./chunks/chunk-5DYEOCT5.js";
|
|
56
56
|
import "./chunks/chunk-4YIDX44G.js";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { SandboxCallContext, SandboxClosure, SandboxValue } from "./values.js";
|
|
2
|
+
type NativeAccessor = (...args: never[]) => unknown;
|
|
3
|
+
/** Native descriptors store identity only. Guest code runs through invokeClosure. */
|
|
4
|
+
export declare function accessorAdapter(closure: SandboxClosure, kind: "get" | "set"): NativeAccessor;
|
|
5
|
+
export declare function accessorClosure(adapter: NativeAccessor | undefined): SandboxClosure | undefined;
|
|
6
|
+
export declare function retainedAccessorClosures(descriptor: PropertyDescriptor): SandboxClosure[];
|
|
7
|
+
export declare function readPropertyDescriptor(descriptor: PropertyDescriptor, receiver: SandboxValue, context?: SandboxCallContext, allowNativeGetter?: boolean): SandboxValue | Promise<SandboxValue>;
|
|
8
|
+
export declare function writePropertyDescriptor(descriptor: PropertyDescriptor, receiver: SandboxValue, value: SandboxValue, context?: SandboxCallContext): Promise<void>;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const accessorClosures = new WeakMap();
|
|
2
|
+
const getterAdapters = new WeakMap();
|
|
3
|
+
const setterAdapters = new WeakMap();
|
|
4
|
+
/** Native descriptors store identity only. Guest code runs through invokeClosure. */
|
|
5
|
+
export function accessorAdapter(closure, kind) {
|
|
6
|
+
if (kind === "get") {
|
|
7
|
+
let adapter = getterAdapters.get(closure);
|
|
8
|
+
if (adapter === undefined) {
|
|
9
|
+
// In particular, native Promise transport must not execute a guest `then`
|
|
10
|
+
// getter when carrying an ordinary interpreter result between async frames.
|
|
11
|
+
adapter = () => undefined;
|
|
12
|
+
getterAdapters.set(closure, adapter);
|
|
13
|
+
accessorClosures.set(adapter, closure);
|
|
14
|
+
}
|
|
15
|
+
return adapter;
|
|
16
|
+
}
|
|
17
|
+
let adapter = setterAdapters.get(closure);
|
|
18
|
+
if (adapter === undefined) {
|
|
19
|
+
adapter = () => {
|
|
20
|
+
throw new TypeError("Accessor writes require sandbox execution.");
|
|
21
|
+
};
|
|
22
|
+
setterAdapters.set(closure, adapter);
|
|
23
|
+
accessorClosures.set(adapter, closure);
|
|
24
|
+
}
|
|
25
|
+
return adapter;
|
|
26
|
+
}
|
|
27
|
+
export function accessorClosure(adapter) {
|
|
28
|
+
if (adapter === undefined)
|
|
29
|
+
return undefined;
|
|
30
|
+
const closure = accessorClosures.get(adapter);
|
|
31
|
+
if (closure === undefined)
|
|
32
|
+
throw new TypeError("Native accessors cannot execute in the sandbox.");
|
|
33
|
+
return closure;
|
|
34
|
+
}
|
|
35
|
+
export function retainedAccessorClosures(descriptor) {
|
|
36
|
+
const closures = [];
|
|
37
|
+
for (const adapter of [descriptor.get, descriptor.set]) {
|
|
38
|
+
const closure = adapter === undefined ? undefined : accessorClosures.get(adapter);
|
|
39
|
+
if (closure !== undefined)
|
|
40
|
+
closures.push(closure);
|
|
41
|
+
}
|
|
42
|
+
return closures;
|
|
43
|
+
}
|
|
44
|
+
export function readPropertyDescriptor(descriptor, receiver, context, allowNativeGetter = false) {
|
|
45
|
+
if ("value" in descriptor)
|
|
46
|
+
return descriptor.value;
|
|
47
|
+
if (descriptor.get === undefined)
|
|
48
|
+
return undefined;
|
|
49
|
+
const getter = accessorClosures.get(descriptor.get);
|
|
50
|
+
// Low-level interpreter callers can supply trusted native getters. Public
|
|
51
|
+
// host admission still rejects them; preserve that existing internal route.
|
|
52
|
+
if (getter === undefined) {
|
|
53
|
+
if (!allowNativeGetter)
|
|
54
|
+
throw new TypeError("Native accessors cannot execute in the sandbox.");
|
|
55
|
+
return Reflect.apply(descriptor.get, receiver, []);
|
|
56
|
+
}
|
|
57
|
+
if (context?.invokeClosure === undefined)
|
|
58
|
+
throw new TypeError("Accessor reads require sandbox execution.");
|
|
59
|
+
return context.invokeClosure(getter, [], receiver);
|
|
60
|
+
}
|
|
61
|
+
export function writePropertyDescriptor(descriptor, receiver, value, context) {
|
|
62
|
+
const setter = accessorClosure(descriptor.set);
|
|
63
|
+
if (setter === undefined)
|
|
64
|
+
throw new TypeError("Cannot assign to a getter-only property.");
|
|
65
|
+
if (context?.invokeClosure === undefined)
|
|
66
|
+
throw new TypeError("Accessor writes require sandbox execution.");
|
|
67
|
+
return context.invokeClosure(setter, [value], receiver).then(() => undefined);
|
|
68
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createGeneratorChannel } from "./generator.js";
|
|
2
2
|
import { getBoundOtelSpan } from "../observability/otel.js";
|
|
3
3
|
import { bindPattern } from "./patterns.js";
|
|
4
|
-
import {
|
|
4
|
+
import { requiresPromiseResolution, resolveSandboxValue } from "./promise.js";
|
|
5
5
|
import { runAsyncPrefix, suspendJob } from "./jobs.js";
|
|
6
6
|
import { CompileScope } from "./regex/compile-guard.js";
|
|
7
7
|
import { awaitSandboxValue } from "./cancel.js";
|
|
@@ -29,7 +29,7 @@ export async function evaluateFunctionExpression(node, context, evaluateNode) {
|
|
|
29
29
|
return {
|
|
30
30
|
kind: "normal",
|
|
31
31
|
hasValue: true,
|
|
32
|
-
value: createInterpretedClosure(node, context, evaluateNode)
|
|
32
|
+
value: createInterpretedClosure(node, context, evaluateNode, node.method === true ? context.functionEnvironment?.homeObject : undefined)
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
const wrapperScope = context.scope.child();
|
|
@@ -102,7 +102,7 @@ export function executeAsyncFunction(execute, budget, signal) {
|
|
|
102
102
|
runAsyncPrefix(async () => {
|
|
103
103
|
try {
|
|
104
104
|
const value = await execute(completePrefix);
|
|
105
|
-
resolve(
|
|
105
|
+
resolve(requiresPromiseResolution(value, budget)
|
|
106
106
|
? awaitSandboxValue(createSandboxPromise(resolveSandboxValue(value, { budget }), {
|
|
107
107
|
trackReplay: false
|
|
108
108
|
}), signal, budget)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getFunctionLength } from "../parse/bindings.js";
|
|
2
2
|
import { functionSources } from "../parse/function-source.js";
|
|
3
|
+
import { accessorAdapter } from "./accessors.js";
|
|
3
4
|
import { createInterpretedClosure, executeClosure } from "./async.js";
|
|
4
5
|
import { retainValues } from "./resources.js";
|
|
5
6
|
import { getSandboxPrototype, materializeFunctionProperties, setSandboxPrototype } from "./object-model.js";
|
|
@@ -26,7 +27,7 @@ export async function evaluateClass(node, context, evaluateNode, callContext) {
|
|
|
26
27
|
parent = result.value;
|
|
27
28
|
if (parent !== null && (!isSandboxClosure(parent) || parent.construct === undefined))
|
|
28
29
|
throw new TypeError("Class extends value is not a constructor or null.");
|
|
29
|
-
prototypeParent = parent === null ? null : callContext.getProperty(parent, "prototype");
|
|
30
|
+
prototypeParent = parent === null ? null : await callContext.getProperty(parent, "prototype");
|
|
30
31
|
if (prototypeParent !== null && typeof prototypeParent !== "object")
|
|
31
32
|
throw new TypeError("Class extends value has an invalid prototype.");
|
|
32
33
|
}
|
|
@@ -66,7 +67,7 @@ export async function evaluateClass(node, context, evaluateNode, callContext) {
|
|
|
66
67
|
};
|
|
67
68
|
if (!derived) {
|
|
68
69
|
thisValue = {};
|
|
69
|
-
const targetPrototype = invocation.getProperty(newTarget, "prototype");
|
|
70
|
+
const targetPrototype = await invocation.getProperty(newTarget, "prototype");
|
|
70
71
|
if (typeof targetPrototype === "object" && targetPrototype !== null)
|
|
71
72
|
setSandboxPrototype(thisValue, targetPrototype, context.budget);
|
|
72
73
|
}
|
|
@@ -136,8 +137,13 @@ export async function evaluateClass(node, context, evaluateNode, callContext) {
|
|
|
136
137
|
else {
|
|
137
138
|
const home = element.static ? constructor : prototype;
|
|
138
139
|
const method = createInterpretedClosure(element.value, classContext, evaluateNode, home);
|
|
139
|
-
|
|
140
|
-
Object.defineProperty(
|
|
140
|
+
const accessor = element.kind === "get" || element.kind === "set" ? element.kind : undefined;
|
|
141
|
+
Object.defineProperty(materializeFunctionProperties(method), "name", {
|
|
142
|
+
value: accessor === undefined ? key : `${accessor} ${key}`
|
|
143
|
+
});
|
|
144
|
+
Object.defineProperty(element.static ? properties : prototype, key, accessor === undefined
|
|
145
|
+
? { value: method, configurable: true, writable: true, enumerable: false }
|
|
146
|
+
: { [accessor]: accessorAdapter(method, accessor), configurable: true, enumerable: false });
|
|
141
147
|
}
|
|
142
148
|
}
|
|
143
149
|
if (node.id !== undefined)
|
|
@@ -31,7 +31,7 @@ type ExceptionContext = {
|
|
|
31
31
|
callStack: readonly string[];
|
|
32
32
|
scope: Scope;
|
|
33
33
|
toPropertyKey?: (value: SandboxValue) => Promise<string>;
|
|
34
|
-
getProperty?: (value: SandboxValue, key: string | number) => SandboxValue
|
|
34
|
+
getProperty?: (value: SandboxValue, key: string | number) => SandboxValue | Promise<SandboxValue>;
|
|
35
35
|
};
|
|
36
36
|
type EvaluateExceptionNode<TContext, TError> = (node: ParseResult, context: TContext) => Promise<EvaluationResult<TError>>;
|
|
37
37
|
export declare function evaluateThrowStatement<TContext extends ExceptionContext, TError>(node: ThrowStatement, context: TContext, evaluateNode: EvaluateExceptionNode<TContext, TError>): Promise<EvaluationResult<TError>>;
|
|
@@ -2,7 +2,9 @@ import { attachErrorSpan, attachWrappedErrorCause, describeThrownValue, formatEr
|
|
|
2
2
|
import { isFatalSandboxError, SandboxError } from "./budget.js";
|
|
3
3
|
import { HostCallResumabilityError } from "./host-call.js";
|
|
4
4
|
import { withFatalPromiseCleanup } from "./promise-tracker.js";
|
|
5
|
-
import { deepCopyToSandbox,
|
|
5
|
+
import { deepCopyToSandbox, ownEnumerableSandboxKeys } from "./values.js";
|
|
6
|
+
import { hasOwnSandboxProperty } from "./globals/object.js";
|
|
7
|
+
import { retainValues } from "./resources.js";
|
|
6
8
|
import { getSandboxDataProperty } from "./object-model.js";
|
|
7
9
|
import { toPropertyKey } from "./property-key.js";
|
|
8
10
|
const capturedExceptionBrand = Symbol("CapturedException");
|
|
@@ -389,12 +391,38 @@ async function bindArrayPattern(pattern, value, context, evaluateNode) {
|
|
|
389
391
|
if (!Array.isArray(value)) {
|
|
390
392
|
throw new TypeError("Array catch bindings require an array value.");
|
|
391
393
|
}
|
|
394
|
+
let cursor = 0;
|
|
395
|
+
let done = false;
|
|
396
|
+
const next = async () => {
|
|
397
|
+
if (done || cursor >= value.length) {
|
|
398
|
+
done = true;
|
|
399
|
+
return { done: true, value: undefined };
|
|
400
|
+
}
|
|
401
|
+
const key = cursor++;
|
|
402
|
+
return {
|
|
403
|
+
done: false,
|
|
404
|
+
value: context.getProperty === undefined
|
|
405
|
+
? getSandboxDataProperty(value, key, context.budget)
|
|
406
|
+
: await context.getProperty(value, key)
|
|
407
|
+
};
|
|
408
|
+
};
|
|
392
409
|
for (let index = 0; index < pattern.elements.length; index += 1) {
|
|
393
410
|
const element = pattern.elements[index];
|
|
394
411
|
if (element === null) {
|
|
412
|
+
await next();
|
|
395
413
|
continue;
|
|
396
414
|
}
|
|
397
|
-
|
|
415
|
+
let elementValue;
|
|
416
|
+
if (element.type === "RestElement") {
|
|
417
|
+
const rest = [];
|
|
418
|
+
for (let entry = await next(); !entry.done; entry = await next()) {
|
|
419
|
+
context.budget.allocateArrayLength(rest.length + 1);
|
|
420
|
+
rest.push(entry.value);
|
|
421
|
+
}
|
|
422
|
+
elementValue = rest;
|
|
423
|
+
}
|
|
424
|
+
else
|
|
425
|
+
elementValue = (await next()).value;
|
|
398
426
|
const binding = await bindPattern(element, elementValue, context, evaluateNode);
|
|
399
427
|
if (!binding.ok) {
|
|
400
428
|
return binding;
|
|
@@ -409,7 +437,7 @@ async function bindObjectPattern(pattern, value, context, evaluateNode) {
|
|
|
409
437
|
const excludedKeys = new Set();
|
|
410
438
|
for (const property of pattern.properties) {
|
|
411
439
|
if (property.type === "RestElement") {
|
|
412
|
-
const restValue = copyObjectRest(value, excludedKeys);
|
|
440
|
+
const restValue = await copyObjectRest(value, excludedKeys, context);
|
|
413
441
|
const binding = await bindPattern(property, restValue, context, evaluateNode);
|
|
414
442
|
if (!binding.ok) {
|
|
415
443
|
return binding;
|
|
@@ -423,7 +451,7 @@ async function bindObjectPattern(pattern, value, context, evaluateNode) {
|
|
|
423
451
|
excludedKeys.add(String(key.value));
|
|
424
452
|
const binding = await bindPattern(property.value, context.getProperty === undefined
|
|
425
453
|
? getSandboxDataProperty(value, key.value, context.budget)
|
|
426
|
-
: context.getProperty(value, key.value), context, evaluateNode);
|
|
454
|
+
: await context.getProperty(value, key.value), context, evaluateNode);
|
|
427
455
|
if (!binding.ok) {
|
|
428
456
|
return binding;
|
|
429
457
|
}
|
|
@@ -460,10 +488,21 @@ function getStaticPropertyKey(property) {
|
|
|
460
488
|
throw new TypeError(`Unsupported catch binding property key '${property.type}'.`);
|
|
461
489
|
}
|
|
462
490
|
}
|
|
463
|
-
function copyObjectRest(value, excludedKeys) {
|
|
491
|
+
async function copyObjectRest(value, excludedKeys, context) {
|
|
464
492
|
const rest = Object.create(null);
|
|
465
|
-
|
|
466
|
-
|
|
493
|
+
const release = retainValues(context.budget, () => [value, rest]);
|
|
494
|
+
try {
|
|
495
|
+
for (const key of ownEnumerableSandboxKeys(value)) {
|
|
496
|
+
if (excludedKeys.has(key) || !hasOwnSandboxProperty(value, key, true))
|
|
497
|
+
continue;
|
|
498
|
+
rest[key] =
|
|
499
|
+
context.getProperty === undefined
|
|
500
|
+
? getSandboxDataProperty(value, key, context.budget)
|
|
501
|
+
: await context.getProperty(value, key);
|
|
502
|
+
}
|
|
503
|
+
return rest;
|
|
504
|
+
}
|
|
505
|
+
finally {
|
|
506
|
+
release();
|
|
467
507
|
}
|
|
468
|
-
return rest;
|
|
469
508
|
}
|
|
@@ -17,20 +17,34 @@ export function createCollectionGlobals(options) {
|
|
|
17
17
|
let key;
|
|
18
18
|
let value;
|
|
19
19
|
return populateCollection(source, map, {
|
|
20
|
-
name: "Map",
|
|
20
|
+
name: "Map",
|
|
21
|
+
budget: options.budget,
|
|
22
|
+
context,
|
|
21
23
|
retainedValues: () => [key, value],
|
|
22
24
|
append: (entry) => {
|
|
23
25
|
if (typeof entry !== "object" || entry === null)
|
|
24
26
|
throw new TypeError("Map constructor requires entry objects.");
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
const store = (entryValue) => {
|
|
28
|
+
value = entryValue;
|
|
29
|
+
const added = map.entries.has(key) ? 0 : 1;
|
|
30
|
+
const growth = added +
|
|
31
|
+
(options.budget.limits.dataSize === undefined ? 0 : measureSandboxData([key, value]));
|
|
32
|
+
options.budget.allocateCollectionEntries(map.entries.size + added);
|
|
33
|
+
map.entries.set(key, value);
|
|
34
|
+
key = value = undefined;
|
|
35
|
+
return growth;
|
|
36
|
+
};
|
|
37
|
+
const readValue = (entryKey) => {
|
|
38
|
+
key = entryKey;
|
|
39
|
+
const result = context?.getProperty !== undefined
|
|
40
|
+
? context.getProperty(entry, 1)
|
|
41
|
+
: getSandboxDataProperty(entry, 1, options.budget);
|
|
42
|
+
return result instanceof Promise ? result.then(store) : store(result);
|
|
43
|
+
};
|
|
44
|
+
const result = context?.getProperty !== undefined
|
|
45
|
+
? context.getProperty(entry, 0)
|
|
46
|
+
: getSandboxDataProperty(entry, 0, options.budget);
|
|
47
|
+
return result instanceof Promise ? result.then(readValue) : readValue(result);
|
|
34
48
|
}
|
|
35
49
|
});
|
|
36
50
|
},
|
|
@@ -44,7 +58,9 @@ export function createCollectionGlobals(options) {
|
|
|
44
58
|
construct: ([source], context) => {
|
|
45
59
|
const set = createSandboxSet([]);
|
|
46
60
|
return populateCollection(source, set, {
|
|
47
|
-
name: "Set",
|
|
61
|
+
name: "Set",
|
|
62
|
+
budget: options.budget,
|
|
63
|
+
context,
|
|
48
64
|
append: (value) => {
|
|
49
65
|
const added = set.values.has(value) ? 0 : 1;
|
|
50
66
|
const growth = added +
|
|
@@ -77,7 +93,14 @@ function populateCollection(source, collection, { name, budget, context, append,
|
|
|
77
93
|
let entry;
|
|
78
94
|
let failure;
|
|
79
95
|
const retained = {};
|
|
80
|
-
budget.setRetainedValues(retained, () => [
|
|
96
|
+
budget.setRetainedValues(retained, () => [
|
|
97
|
+
source,
|
|
98
|
+
iterator.retainedValue,
|
|
99
|
+
collection,
|
|
100
|
+
entry,
|
|
101
|
+
failure,
|
|
102
|
+
...(retainedValues?.() ?? [])
|
|
103
|
+
]);
|
|
81
104
|
const checkData = createDataCheckpoint(budget, context);
|
|
82
105
|
const closeOnThrow = (error) => {
|
|
83
106
|
failure = isCapturedException(error) ? error.reason : error;
|
|
@@ -89,7 +112,9 @@ function populateCollection(source, collection, { name, budget, context, append,
|
|
|
89
112
|
try {
|
|
90
113
|
const closing = iterator.return?.();
|
|
91
114
|
if (iterator.generator || iterator.asynchronous)
|
|
92
|
-
return Promise.resolve(closing).then(() => {
|
|
115
|
+
return Promise.resolve(closing).then(() => {
|
|
116
|
+
throw error;
|
|
117
|
+
}, rethrow);
|
|
93
118
|
}
|
|
94
119
|
catch (closeError) {
|
|
95
120
|
return rethrow(closeError);
|
|
@@ -105,6 +130,14 @@ function populateCollection(source, collection, { name, budget, context, append,
|
|
|
105
130
|
try {
|
|
106
131
|
budget.visitNode();
|
|
107
132
|
const growth = append(entry);
|
|
133
|
+
if (growth instanceof Promise)
|
|
134
|
+
return growth
|
|
135
|
+
.then((size) => {
|
|
136
|
+
entry = undefined;
|
|
137
|
+
checkData(collection, size);
|
|
138
|
+
return false;
|
|
139
|
+
})
|
|
140
|
+
.catch(closeOnThrow);
|
|
108
141
|
entry = undefined;
|
|
109
142
|
checkData(collection, growth);
|
|
110
143
|
}
|
|
@@ -113,11 +146,13 @@ function populateCollection(source, collection, { name, budget, context, append,
|
|
|
113
146
|
}
|
|
114
147
|
return false;
|
|
115
148
|
};
|
|
116
|
-
if (iterator.generator || iterator.asynchronous) {
|
|
149
|
+
if (iterator.generator || iterator.asynchronous || context !== undefined) {
|
|
117
150
|
return (async () => {
|
|
118
151
|
try {
|
|
119
152
|
checkData(collection, 0, true);
|
|
120
|
-
while (!(await consume(await iterator.next()))) {
|
|
153
|
+
while (!(await consume(await iterator.next()))) {
|
|
154
|
+
/* Consume each entry before advancing. */
|
|
155
|
+
}
|
|
121
156
|
checkData(collection, 0, true);
|
|
122
157
|
return collection;
|
|
123
158
|
}
|
|
@@ -128,7 +163,9 @@ function populateCollection(source, collection, { name, budget, context, append,
|
|
|
128
163
|
}
|
|
129
164
|
try {
|
|
130
165
|
checkData(collection, 0, true);
|
|
131
|
-
while (!consume(iterator.next())) {
|
|
166
|
+
while (!consume(iterator.next())) {
|
|
167
|
+
/* Synchronous inputs stay synchronous. */
|
|
168
|
+
}
|
|
132
169
|
checkData(collection, 0, true);
|
|
133
170
|
return collection;
|
|
134
171
|
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { retainValues } from "../resources.js";
|
|
2
|
+
import { readPropertyDescriptor } from "../accessors.js";
|
|
3
|
+
import { getSandboxPropertyDescriptor } from "../object-model.js";
|
|
1
4
|
import { dateMethods, isSandboxDate } from "../date.js";
|
|
2
5
|
import { boxedValue, isSandboxBox } from "../boxed.js";
|
|
3
6
|
import { sandboxNumber, sandboxString } from "../string-coercion.js";
|
|
@@ -96,27 +99,36 @@ async function stringifyJson(value, replacer, indent, budget, context) {
|
|
|
96
99
|
return budget.allocateString(output);
|
|
97
100
|
}
|
|
98
101
|
async function stringifyProperty(key, holder, state, indent = "") {
|
|
99
|
-
let value =
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (
|
|
106
|
-
|
|
102
|
+
let value = await getStringifyProperty(holder, key, state);
|
|
103
|
+
const release = retainValues(state.budget, () => [holder, value]);
|
|
104
|
+
try {
|
|
105
|
+
if (isSandboxDate(value)) {
|
|
106
|
+
value = dateMethods.get("toJSON").invoke(value, []);
|
|
107
|
+
}
|
|
108
|
+
else if (isStringifyContainer(value)) {
|
|
109
|
+
const toJSON = await getStringifyProperty(value, "toJSON", state);
|
|
110
|
+
if (isSandboxClosure(toJSON)) {
|
|
111
|
+
value = await callStringifyClosure(toJSON, [key], value, state);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (state.replacer !== undefined) {
|
|
115
|
+
value = await callStringifyClosure(state.replacer, [key, toSandboxValue(value)], holder, state);
|
|
107
116
|
}
|
|
117
|
+
return await stringifyValue(value, state, indent);
|
|
108
118
|
}
|
|
109
|
-
|
|
110
|
-
|
|
119
|
+
finally {
|
|
120
|
+
release();
|
|
111
121
|
}
|
|
112
|
-
return stringifyValue(value, state, indent);
|
|
113
122
|
}
|
|
114
123
|
async function stringifyValue(value, state, indent) {
|
|
115
124
|
if (isSandboxBox(value)) {
|
|
116
125
|
const primitive = boxedValue(value);
|
|
117
|
-
value =
|
|
118
|
-
|
|
119
|
-
|
|
126
|
+
value =
|
|
127
|
+
typeof primitive === "number"
|
|
128
|
+
? await sandboxNumber(value, state.budget, state.context)
|
|
129
|
+
: typeof primitive === "string"
|
|
130
|
+
? await sandboxString(value, state.budget, state.context)
|
|
131
|
+
: primitive;
|
|
120
132
|
}
|
|
121
133
|
if (value === null) {
|
|
122
134
|
return "null";
|
|
@@ -148,10 +160,12 @@ async function stringifyValue(value, state, indent) {
|
|
|
148
160
|
}
|
|
149
161
|
async function stringifyArray(value, state, indent) {
|
|
150
162
|
enterStringifyObject(value, state);
|
|
163
|
+
const entries = [];
|
|
164
|
+
const release = retainValues(state.budget, () => entries);
|
|
151
165
|
try {
|
|
152
166
|
const nextIndent = indent + state.gap;
|
|
153
|
-
const
|
|
154
|
-
for (let index = 0; index <
|
|
167
|
+
const length = value.length;
|
|
168
|
+
for (let index = 0; index < length; index += 1) {
|
|
155
169
|
entries.push((await stringifyProperty(String(index), value, state, nextIndent)) ?? "null");
|
|
156
170
|
}
|
|
157
171
|
if (entries.length === 0) {
|
|
@@ -163,14 +177,16 @@ async function stringifyArray(value, state, indent) {
|
|
|
163
177
|
return `[\n${nextIndent}${entries.join(`,\n${nextIndent}`)}\n${indent}]`;
|
|
164
178
|
}
|
|
165
179
|
finally {
|
|
180
|
+
release();
|
|
166
181
|
leaveStringifyObject(value, state);
|
|
167
182
|
}
|
|
168
183
|
}
|
|
169
184
|
async function stringifyObject(value, state, indent) {
|
|
170
185
|
enterStringifyObject(value, state);
|
|
186
|
+
const entries = [];
|
|
187
|
+
const release = retainValues(state.budget, () => entries);
|
|
171
188
|
try {
|
|
172
189
|
const nextIndent = indent + state.gap;
|
|
173
|
-
const entries = [];
|
|
174
190
|
for (const key of Object.keys(value)) {
|
|
175
191
|
const serialized = await stringifyProperty(key, value, state, nextIndent);
|
|
176
192
|
if (serialized !== undefined) {
|
|
@@ -186,6 +202,7 @@ async function stringifyObject(value, state, indent) {
|
|
|
186
202
|
return `{\n${nextIndent}${entries.join(`,\n${nextIndent}`)}\n${indent}}`;
|
|
187
203
|
}
|
|
188
204
|
finally {
|
|
205
|
+
release();
|
|
189
206
|
leaveStringifyObject(value, state);
|
|
190
207
|
}
|
|
191
208
|
}
|
|
@@ -250,15 +267,13 @@ function toSandboxValue(value) {
|
|
|
250
267
|
}
|
|
251
268
|
throw new TypeError(`JSON.stringify(value) produced an unsupported value of type ${typeof value}.`);
|
|
252
269
|
}
|
|
253
|
-
function
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}
|
|
261
|
-
return descriptor.value;
|
|
270
|
+
function getStringifyProperty(target, key, state) {
|
|
271
|
+
if (state.context?.getProperty !== undefined)
|
|
272
|
+
return state.context.getProperty(target, key);
|
|
273
|
+
const descriptor = getSandboxPropertyDescriptor(target, key, state.budget);
|
|
274
|
+
return descriptor === undefined
|
|
275
|
+
? undefined
|
|
276
|
+
: readPropertyDescriptor(descriptor, target, state.context);
|
|
262
277
|
}
|
|
263
278
|
function copyJsonToSandbox(value, budget) {
|
|
264
279
|
if (value === null ||
|