poe-code 14.0.52 → 14.0.54
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 +187 -99
- package/dist/index.js.map +3 -3
- package/dist/metafile.json +1 -1
- package/package.json +1 -1
- package/packages/safe-bash/dist/browser.js +35 -15
- package/packages/safe-bash/dist/browser.js.map +3 -3
- package/packages/safe-bash/dist/shell/arrays/state.d.ts +2 -1
- package/packages/safe-bash/dist/shell/arrays/state.d.ts.map +1 -1
- package/packages/safe-bash/dist/shell/arrays/state.js +23 -5
- package/packages/safe-bash/dist/shell/arrays/state.js.map +1 -1
- package/packages/safe-bash/dist/shell/cleanup.d.ts.map +1 -1
- package/packages/safe-bash/dist/shell/cleanup.js +11 -5
- package/packages/safe-bash/dist/shell/cleanup.js.map +1 -1
- package/packages/safe-bash/dist/shell/runtime.js +5 -5
- package/packages/safe-bash/dist/shell/runtime.js.map +1 -1
- package/packages/safe-js/dist/chunks/{chunk-DVWTNFTV.js → chunk-L7PHF62H.js} +182 -99
- package/packages/safe-js/dist/chunks/{chunk-DVWTNFTV.js.map → chunk-L7PHF62H.js.map} +3 -3
- package/packages/safe-js/dist/chunks/{chunk-XIBH4BH2.js → chunk-Z55VACOY.js} +2 -2
- 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/interpreter.js +5 -1
- package/packages/safe-js/dist/interp/methods/array.d.ts +12 -3
- package/packages/safe-js/dist/interp/methods/array.js +164 -46
- package/packages/safe-js/dist/interp/methods/number.d.ts +2 -2
- package/packages/safe-js/dist/interp/methods/number.js +27 -46
- package/packages/safe-js/dist/interp/methods/string.js +17 -3
- /package/packages/safe-js/dist/chunks/{chunk-XIBH4BH2.js.map → chunk-Z55VACOY.js.map} +0 -0
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
validateMigrationSemantics,
|
|
28
28
|
validateSnapshotData,
|
|
29
29
|
validateSnapshotMigration
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-L7PHF62H.js";
|
|
31
31
|
import {
|
|
32
32
|
createFileSystem,
|
|
33
33
|
createNodeFileSystemAdapterRegistry,
|
|
@@ -8245,4 +8245,4 @@ export {
|
|
|
8245
8245
|
parseMcpConfig,
|
|
8246
8246
|
makeMcpModule
|
|
8247
8247
|
};
|
|
8248
|
-
//# sourceMappingURL=chunk-
|
|
8248
|
+
//# sourceMappingURL=chunk-Z55VACOY.js.map
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
resolveFsConfig,
|
|
23
23
|
splitFrontmatter,
|
|
24
24
|
withBrokenPipeGuard
|
|
25
|
-
} from "./chunks/chunk-
|
|
25
|
+
} from "./chunks/chunk-Z55VACOY.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-L7PHF62H.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-Z55VACOY.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-L7PHF62H.js";
|
|
54
54
|
import "./chunks/chunk-UXMKEUH3.js";
|
|
55
55
|
import "./chunks/chunk-5DYEOCT5.js";
|
|
56
56
|
import "./chunks/chunk-4YIDX44G.js";
|
|
@@ -2483,7 +2483,7 @@ async function evaluateNumberMethodCall(node, target, methodName, context) {
|
|
|
2483
2483
|
return {
|
|
2484
2484
|
kind: "normal",
|
|
2485
2485
|
hasValue: true,
|
|
2486
|
-
value: callNumberMethod(target, methodName, args.value, context.budget)
|
|
2486
|
+
value: await callNumberMethod(target, methodName, args.value, context.budget, createCoercionContext(context))
|
|
2487
2487
|
};
|
|
2488
2488
|
}
|
|
2489
2489
|
catch (error) {
|
|
@@ -2496,6 +2496,10 @@ async function evaluateNumberMethodCall(node, target, methodName, context) {
|
|
|
2496
2496
|
function createArrayMethodOptions(context) {
|
|
2497
2497
|
return {
|
|
2498
2498
|
budget: context.budget,
|
|
2499
|
+
context: createCoercionContext(context),
|
|
2500
|
+
hasProperty: (value, property) => hasSandboxProperty(value, property, context),
|
|
2501
|
+
setProperty: (value, property, entry) => setSandboxProperty(value, property, entry, context.budget),
|
|
2502
|
+
deleteProperty: deleteSandboxProperty,
|
|
2499
2503
|
callClosure: (closure, args, stack, thisValue) => invokeSandboxClosure(closure, args, context, stack, undefined, thisValue)
|
|
2500
2504
|
};
|
|
2501
2505
|
}
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
import { Budget } from "../budget.js";
|
|
2
|
-
import { type SandboxArray, type SandboxClosure, type SandboxValue } from "../values.js";
|
|
2
|
+
import { type SandboxArray, type SandboxCallContext, type SandboxClosure, type SandboxObject, type SandboxValue } from "../values.js";
|
|
3
|
+
type ArrayLikeValue = SandboxArray | (SandboxObject & {
|
|
4
|
+
[index: number]: SandboxValue;
|
|
5
|
+
length: number;
|
|
6
|
+
});
|
|
3
7
|
export type ArrayMethodName = "map" | "filter" | "find" | "findIndex" | "findLast" | "findLastIndex" | "some" | "every" | "reduce" | "reduceRight" | "forEach" | "flatMap" | "flat" | "includes" | "indexOf" | "lastIndexOf" | "join" | "slice" | "concat" | "splice" | "fill" | "copyWithin" | "at" | "sort" | "reverse" | "toSorted" | "toReversed" | "toSpliced" | "with" | "push" | "pop" | "shift" | "unshift";
|
|
4
8
|
export type ArrayMethodOptions = {
|
|
5
9
|
budget: Budget;
|
|
10
|
+
context?: SandboxCallContext;
|
|
11
|
+
hasProperty?: (value: SandboxValue, property: string) => boolean;
|
|
12
|
+
setProperty?: (value: SandboxValue, property: string, entry: SandboxValue) => void;
|
|
13
|
+
deleteProperty?: (value: SandboxValue, property: string | number) => boolean;
|
|
6
14
|
callClosure: (closure: SandboxClosure, args: readonly SandboxValue[], stack: readonly string[], thisValue?: SandboxValue) => Promise<SandboxValue>;
|
|
7
15
|
};
|
|
8
|
-
export declare function getArrayMember(value:
|
|
16
|
+
export declare function getArrayMember(value: ArrayLikeValue, property: string | number, options: ArrayMethodOptions): SandboxValue | undefined;
|
|
9
17
|
export declare function isArrayMethodName(property: string | number): property is ArrayMethodName;
|
|
10
|
-
export declare function callArrayMethod(
|
|
18
|
+
export declare function callArrayMethod(receiver: SandboxValue, methodName: ArrayMethodName, args: readonly SandboxValue[], options: ArrayMethodOptions, stack?: readonly string[]): Promise<SandboxValue>;
|
|
19
|
+
export {};
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { createSandboxClosure, isSandboxClosure, isSandboxMap, isSandboxPromise, isSandboxSet } from "../values.js";
|
|
2
2
|
import { assertCollectionMutable, enterRunningState } from "../running-state.js";
|
|
3
|
+
import { getSandboxDataProperty, getSandboxPrototype } from "../object-model.js";
|
|
4
|
+
import { sandboxNumber } from "../string-coercion.js";
|
|
5
|
+
const arrayLikeSources = new WeakMap();
|
|
3
6
|
const activeArrayCallbacks = new WeakMap();
|
|
4
7
|
const arrayMethodNames = new Set([
|
|
5
8
|
"map",
|
|
@@ -51,7 +54,7 @@ export function getArrayMember(value, property, options) {
|
|
|
51
54
|
return createSandboxClosure({
|
|
52
55
|
sandbox: true,
|
|
53
56
|
name: `Array#${property}`,
|
|
54
|
-
call: (args, context) => callArrayMethod(
|
|
57
|
+
call: (args, context) => callArrayMethod(context?.thisValue, property, args, { ...options, context }, context?.stack ?? [])
|
|
55
58
|
});
|
|
56
59
|
}
|
|
57
60
|
return undefined;
|
|
@@ -69,29 +72,94 @@ function getArrayIndex(property) {
|
|
|
69
72
|
export function isArrayMethodName(property) {
|
|
70
73
|
return typeof property === "string" && arrayMethodNames.has(property);
|
|
71
74
|
}
|
|
72
|
-
export async function callArrayMethod(
|
|
73
|
-
if (
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
callbackState
|
|
88
|
-
if (callbackState
|
|
89
|
-
|
|
90
|
-
|
|
75
|
+
export async function callArrayMethod(receiver, methodName, args, options, stack = []) {
|
|
76
|
+
if (receiver === null || receiver === undefined)
|
|
77
|
+
throw new TypeError("Array method requires a receiver.");
|
|
78
|
+
if (typeof receiver !== "object")
|
|
79
|
+
throw new TypeError("Object primitive boxing is not supported.");
|
|
80
|
+
const retainedReceiver = {};
|
|
81
|
+
options.budget.setRetainedValues(retainedReceiver, () => [receiver]);
|
|
82
|
+
try {
|
|
83
|
+
const value = Array.isArray(receiver) || methodName === "concat"
|
|
84
|
+
? receiver
|
|
85
|
+
: await arrayLikeView(receiver, options);
|
|
86
|
+
if (isMutatingArrayMethod(methodName)) {
|
|
87
|
+
assertCollectionMutable(receiver);
|
|
88
|
+
}
|
|
89
|
+
if (isCallbackArrayMethod(methodName)) {
|
|
90
|
+
let callbackState = activeArrayCallbacks.get(receiver);
|
|
91
|
+
if (callbackState === undefined) {
|
|
92
|
+
callbackState = { depth: 0, leave: enterRunningState(receiver) };
|
|
93
|
+
activeArrayCallbacks.set(receiver, callbackState);
|
|
94
|
+
}
|
|
95
|
+
callbackState.depth += 1;
|
|
96
|
+
try {
|
|
97
|
+
const result = await callArrayMethodUnlocked(value, methodName, args, options, stack);
|
|
98
|
+
return result === value ? receiver : result;
|
|
99
|
+
}
|
|
100
|
+
finally {
|
|
101
|
+
callbackState.depth -= 1;
|
|
102
|
+
if (callbackState.depth === 0) {
|
|
103
|
+
activeArrayCallbacks.delete(receiver);
|
|
104
|
+
callbackState.leave();
|
|
105
|
+
}
|
|
91
106
|
}
|
|
92
107
|
}
|
|
108
|
+
const result = await callArrayMethodUnlocked(value, methodName, args, options, stack);
|
|
109
|
+
return result === value ? receiver : result;
|
|
93
110
|
}
|
|
94
|
-
|
|
111
|
+
finally {
|
|
112
|
+
options.budget.setRetainedValues(retainedReceiver, undefined);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
async function arrayLikeView(receiver, options) {
|
|
116
|
+
const rawLength = options.context?.getProperty !== undefined
|
|
117
|
+
? options.context.getProperty(receiver, "length")
|
|
118
|
+
: getSandboxDataProperty(receiver, "length", options.budget);
|
|
119
|
+
const number = await sandboxNumber(rawLength, options.budget, options.context);
|
|
120
|
+
const length = Number.isNaN(number) || number <= 0 ? 0 : Math.min(Math.trunc(number), Number.MAX_SAFE_INTEGER);
|
|
121
|
+
// The view is internal only: callbacks, results, and accounting keep the guest receiver.
|
|
122
|
+
const view = new Proxy(Object.create(null), {
|
|
123
|
+
get: (_target, key) => {
|
|
124
|
+
options.budget.visitNode();
|
|
125
|
+
if (key === "length")
|
|
126
|
+
return length;
|
|
127
|
+
if (typeof key !== "string")
|
|
128
|
+
return undefined;
|
|
129
|
+
return options.context?.getProperty !== undefined
|
|
130
|
+
? options.context.getProperty(receiver, key)
|
|
131
|
+
: getSandboxDataProperty(receiver, key, options.budget);
|
|
132
|
+
},
|
|
133
|
+
has: (_target, key) => {
|
|
134
|
+
options.budget.visitNode();
|
|
135
|
+
if (typeof key === "string" && options.hasProperty !== undefined)
|
|
136
|
+
return options.hasProperty(receiver, key);
|
|
137
|
+
for (let current = receiver; current !== null; current = getSandboxPrototype(current, options.budget)) {
|
|
138
|
+
options.budget.visitNode();
|
|
139
|
+
if (Object.hasOwn(current, key))
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
return false;
|
|
143
|
+
},
|
|
144
|
+
set: (_target, key, entry) => {
|
|
145
|
+
options.budget.visitNode();
|
|
146
|
+
if (typeof key !== "string")
|
|
147
|
+
throw new TypeError("Array indices must be string keys.");
|
|
148
|
+
if (options.setProperty !== undefined)
|
|
149
|
+
options.setProperty(receiver, key, entry);
|
|
150
|
+
else if (!Reflect.set(receiver, key, entry))
|
|
151
|
+
throw new TypeError(`Cannot assign property '${key}'.`);
|
|
152
|
+
return true;
|
|
153
|
+
},
|
|
154
|
+
deleteProperty: (_target, key) => {
|
|
155
|
+
options.budget.visitNode();
|
|
156
|
+
if (typeof key === "string" && options.deleteProperty !== undefined)
|
|
157
|
+
return options.deleteProperty(receiver, key);
|
|
158
|
+
return Reflect.deleteProperty(receiver, key);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
arrayLikeSources.set(view, receiver);
|
|
162
|
+
return view;
|
|
95
163
|
}
|
|
96
164
|
async function callArrayMethodUnlocked(value, methodName, args, options, stack) {
|
|
97
165
|
switch (methodName) {
|
|
@@ -130,8 +198,22 @@ async function callArrayMethodUnlocked(value, methodName, args, options, stack)
|
|
|
130
198
|
return Reflect.apply(Array.prototype.lastIndexOf, value, [...args]);
|
|
131
199
|
case "join":
|
|
132
200
|
return options.budget.allocateString(Reflect.apply(Array.prototype.join, value, [...args]));
|
|
133
|
-
case "slice":
|
|
134
|
-
|
|
201
|
+
case "slice": {
|
|
202
|
+
const length = value.length;
|
|
203
|
+
const start = toIntegerOrInfinity(await sandboxNumber(args[0], options.budget, options.context));
|
|
204
|
+
const end = args[1] === undefined ? length : toIntegerOrInfinity(await sandboxNumber(args[1], options.budget, options.context));
|
|
205
|
+
const first = start < 0 ? Math.max(length + start, 0) : Math.min(start, length);
|
|
206
|
+
const final = end < 0 ? Math.max(length + end, 0) : Math.min(end, length);
|
|
207
|
+
const count = Math.max(final - first, 0);
|
|
208
|
+
options.budget.allocateArrayLength(count);
|
|
209
|
+
const result = new Array(count);
|
|
210
|
+
for (let index = 0; index < count; index += 1) {
|
|
211
|
+
options.budget.visitNode();
|
|
212
|
+
if (first + index in value)
|
|
213
|
+
result[index] = value[first + index];
|
|
214
|
+
}
|
|
215
|
+
return budgetProducedValue(result, options.budget);
|
|
216
|
+
}
|
|
135
217
|
case "concat":
|
|
136
218
|
return budgetProducedValue(Reflect.apply(Array.prototype.concat, value, [...args]), options.budget);
|
|
137
219
|
case "splice": {
|
|
@@ -152,7 +234,7 @@ async function callArrayMethodUnlocked(value, methodName, args, options, stack)
|
|
|
152
234
|
return budgetProducedValue(Reflect.apply(Array.prototype.at, value, [...args]), options.budget);
|
|
153
235
|
case "sort":
|
|
154
236
|
if (args[0] === undefined) {
|
|
155
|
-
|
|
237
|
+
Reflect.apply(Array.prototype.sort, value, []);
|
|
156
238
|
budgetProducedValue(value, options.budget);
|
|
157
239
|
return value;
|
|
158
240
|
}
|
|
@@ -160,11 +242,17 @@ async function callArrayMethodUnlocked(value, methodName, args, options, stack)
|
|
|
160
242
|
budgetProducedValue(value, options.budget);
|
|
161
243
|
return value;
|
|
162
244
|
case "reverse":
|
|
163
|
-
|
|
245
|
+
Reflect.apply(Array.prototype.reverse, value, []);
|
|
164
246
|
budgetProducedValue(value, options.budget);
|
|
165
247
|
return value;
|
|
166
248
|
case "toSorted": {
|
|
167
|
-
const
|
|
249
|
+
const length = value.length;
|
|
250
|
+
options.budget.allocateArrayLength(length);
|
|
251
|
+
const result = new Array(length);
|
|
252
|
+
for (let index = 0; index < length; index += 1) {
|
|
253
|
+
options.budget.visitNode();
|
|
254
|
+
result[index] = value[index];
|
|
255
|
+
}
|
|
168
256
|
if (args[0] === undefined) {
|
|
169
257
|
result.sort();
|
|
170
258
|
}
|
|
@@ -174,13 +262,33 @@ async function callArrayMethodUnlocked(value, methodName, args, options, stack)
|
|
|
174
262
|
return budgetProducedValue(result, options.budget);
|
|
175
263
|
}
|
|
176
264
|
case "toReversed": {
|
|
177
|
-
const
|
|
178
|
-
|
|
265
|
+
const length = value.length;
|
|
266
|
+
options.budget.allocateArrayLength(length);
|
|
267
|
+
const result = new Array(length);
|
|
268
|
+
for (let index = 0; index < length; index += 1) {
|
|
269
|
+
options.budget.visitNode();
|
|
270
|
+
result[index] = value[length - index - 1];
|
|
271
|
+
}
|
|
179
272
|
return budgetProducedValue(result, options.budget);
|
|
180
273
|
}
|
|
181
274
|
case "toSpliced": {
|
|
182
|
-
const
|
|
183
|
-
|
|
275
|
+
const length = value.length;
|
|
276
|
+
const start = toIntegerOrInfinity(await sandboxNumber(args[0], options.budget, options.context));
|
|
277
|
+
const first = start < 0 ? Math.max(length + start, 0) : Math.min(start, length);
|
|
278
|
+
const inserted = Math.max(args.length - 2, 0);
|
|
279
|
+
const deleted = args.length === 0 ? 0 : args.length === 1 ? length - first
|
|
280
|
+
: Math.min(Math.max(toIntegerOrInfinity(await sandboxNumber(args[1], options.budget, options.context)), 0), length - first);
|
|
281
|
+
const resultLength = length + inserted - deleted;
|
|
282
|
+
if (resultLength > Number.MAX_SAFE_INTEGER)
|
|
283
|
+
throw new TypeError("Array-like length exceeds the safe integer limit.");
|
|
284
|
+
options.budget.allocateArrayLength(resultLength);
|
|
285
|
+
const result = new Array(resultLength);
|
|
286
|
+
for (let index = 0; index < resultLength; index += 1) {
|
|
287
|
+
options.budget.visitNode();
|
|
288
|
+
result[index] = index < first ? value[index]
|
|
289
|
+
: index < first + inserted ? args[index - first + 2]
|
|
290
|
+
: value[index - inserted + deleted];
|
|
291
|
+
}
|
|
184
292
|
return budgetProducedValue(result, options.budget);
|
|
185
293
|
}
|
|
186
294
|
case "with": {
|
|
@@ -197,41 +305,46 @@ async function callArrayMethodUnlocked(value, methodName, args, options, stack)
|
|
|
197
305
|
result[position] =
|
|
198
306
|
position === actualIndex
|
|
199
307
|
? args[1]
|
|
200
|
-
: Object.hasOwn(value, position)
|
|
201
|
-
?
|
|
202
|
-
:
|
|
308
|
+
: Array.isArray(value) && !Object.hasOwn(value, position)
|
|
309
|
+
? undefined
|
|
310
|
+
: value[position];
|
|
203
311
|
}
|
|
204
312
|
return budgetProducedValue(result, options.budget);
|
|
205
313
|
}
|
|
206
314
|
case "push": {
|
|
207
|
-
appendArrayValues(value, args);
|
|
208
|
-
const nextLength = value.length;
|
|
315
|
+
const nextLength = appendArrayValues(value, args);
|
|
209
316
|
budgetProducedValue(value, options.budget);
|
|
210
317
|
return nextLength;
|
|
211
318
|
}
|
|
212
319
|
case "pop":
|
|
213
|
-
return budgetProducedValue(
|
|
320
|
+
return budgetProducedValue(Reflect.apply(Array.prototype.pop, value, []), options.budget);
|
|
214
321
|
case "shift":
|
|
215
|
-
return budgetProducedValue(
|
|
322
|
+
return budgetProducedValue(Reflect.apply(Array.prototype.shift, value, []), options.budget);
|
|
216
323
|
case "unshift": {
|
|
217
|
-
prependArrayValues(value, args);
|
|
218
|
-
const nextLength = value.length;
|
|
324
|
+
const nextLength = prependArrayValues(value, args);
|
|
219
325
|
budgetProducedValue(value, options.budget);
|
|
220
326
|
return nextLength;
|
|
221
327
|
}
|
|
222
328
|
}
|
|
223
329
|
}
|
|
224
330
|
function appendArrayValues(target, values) {
|
|
331
|
+
let length = target.length;
|
|
332
|
+
if (length + values.length > Number.MAX_SAFE_INTEGER)
|
|
333
|
+
throw new TypeError("Array-like length exceeds the safe integer limit.");
|
|
225
334
|
for (const value of values) {
|
|
226
|
-
target
|
|
335
|
+
target[length++] = value;
|
|
227
336
|
}
|
|
337
|
+
target.length = length;
|
|
338
|
+
return length;
|
|
228
339
|
}
|
|
229
340
|
function prependArrayValues(target, values) {
|
|
230
341
|
const originalLength = target.length;
|
|
231
|
-
|
|
232
|
-
|
|
342
|
+
const length = originalLength + values.length;
|
|
343
|
+
if (length > Number.MAX_SAFE_INTEGER)
|
|
344
|
+
throw new TypeError("Array-like length exceeds the safe integer limit.");
|
|
345
|
+
for (let index = values.length === 0 ? -1 : originalLength - 1; index >= 0; index -= 1) {
|
|
233
346
|
const targetIndex = index + values.length;
|
|
234
|
-
if (
|
|
347
|
+
if (index in target) {
|
|
235
348
|
target[targetIndex] = target[index];
|
|
236
349
|
}
|
|
237
350
|
else {
|
|
@@ -241,6 +354,8 @@ function prependArrayValues(target, values) {
|
|
|
241
354
|
for (let index = 0; index < values.length; index += 1) {
|
|
242
355
|
target[index] = values[index];
|
|
243
356
|
}
|
|
357
|
+
target.length = length;
|
|
358
|
+
return length;
|
|
244
359
|
}
|
|
245
360
|
function isCallbackArrayMethod(methodName) {
|
|
246
361
|
return (methodName === "map" ||
|
|
@@ -276,6 +391,7 @@ function getRequiredCallback(methodName, value) {
|
|
|
276
391
|
}
|
|
277
392
|
async function mapArray(value, callback, options, stack, thisValue) {
|
|
278
393
|
const length = value.length;
|
|
394
|
+
options.budget.allocateArrayLength(length);
|
|
279
395
|
const result = new Array(length);
|
|
280
396
|
options.budget.setRetainedValues(result, () => [result]);
|
|
281
397
|
try {
|
|
@@ -415,7 +531,7 @@ async function reduceFromLeft(value, callback, accumulator, startIndex, length,
|
|
|
415
531
|
if (!(index in value)) {
|
|
416
532
|
continue;
|
|
417
533
|
}
|
|
418
|
-
current = await options.callClosure(callback, [current, value[index], index, value], stack);
|
|
534
|
+
current = await options.callClosure(callback, [current, value[index], index, arrayLikeSources.get(value) ?? value], stack);
|
|
419
535
|
}
|
|
420
536
|
return current;
|
|
421
537
|
}
|
|
@@ -433,7 +549,7 @@ async function reduceFromRight(value, callback, accumulator, startIndex, length,
|
|
|
433
549
|
if (!(index in value)) {
|
|
434
550
|
continue;
|
|
435
551
|
}
|
|
436
|
-
current = await options.callClosure(callback, [current, value[index], index, value], stack);
|
|
552
|
+
current = await options.callClosure(callback, [current, value[index], index, arrayLikeSources.get(value) ?? value], stack);
|
|
437
553
|
}
|
|
438
554
|
return current;
|
|
439
555
|
}
|
|
@@ -552,7 +668,7 @@ async function compareEntries(left, right, comparator, options, stack) {
|
|
|
552
668
|
return Number.isNaN(result) ? 0 : result;
|
|
553
669
|
}
|
|
554
670
|
async function callArrayCallback(callback, value, index, array, options, stack, thisValue) {
|
|
555
|
-
return options.callClosure(callback, [value, index, array], stack, thisValue);
|
|
671
|
+
return options.callClosure(callback, [value, index, arrayLikeSources.get(array) ?? array], stack, thisValue);
|
|
556
672
|
}
|
|
557
673
|
function findNextDefinedIndex(value, startIndex, direction, length, budget) {
|
|
558
674
|
for (let index = startIndex; direction > 0 ? index < length : index >= 0; index += direction) {
|
|
@@ -564,6 +680,8 @@ function findNextDefinedIndex(value, startIndex, direction, length, budget) {
|
|
|
564
680
|
return -1;
|
|
565
681
|
}
|
|
566
682
|
function budgetProducedValue(value, budget) {
|
|
683
|
+
if (typeof value === "object" && value !== null)
|
|
684
|
+
value = arrayLikeSources.get(value) ?? value;
|
|
567
685
|
allocateProducedValue(value, budget, new WeakSet());
|
|
568
686
|
return value;
|
|
569
687
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Budget } from "../budget.js";
|
|
2
|
-
import { type SandboxValue } from "../values.js";
|
|
2
|
+
import { type SandboxCallContext, type SandboxValue } from "../values.js";
|
|
3
3
|
export type NumberMethodName = "toExponential" | "toFixed" | "toPrecision" | "toString";
|
|
4
4
|
export declare function getNumberMember(property: string | number, budget: Budget): SandboxValue | undefined;
|
|
5
5
|
export declare function isNumberMethodName(property: string | number): property is NumberMethodName;
|
|
6
|
-
export declare function callNumberMethod(value: SandboxValue, methodName: NumberMethodName, args: readonly SandboxValue[], budget: Budget): string
|
|
6
|
+
export declare function callNumberMethod(value: SandboxValue, methodName: NumberMethodName, args: readonly SandboxValue[], budget: Budget, context?: SandboxCallContext): string | Promise<string>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { sandboxNumber } from "../string-coercion.js";
|
|
1
2
|
import { createSandboxClosure } from "../values.js";
|
|
2
3
|
const numberMethodNames = new Set([
|
|
3
4
|
"toExponential",
|
|
@@ -12,65 +13,45 @@ export function getNumberMember(property, budget) {
|
|
|
12
13
|
return createSandboxClosure({
|
|
13
14
|
sandbox: true,
|
|
14
15
|
name: `Number#${property}`,
|
|
15
|
-
call: (args, context) => callNumberMethod(context?.thisValue, property, args, budget)
|
|
16
|
+
call: (args, context) => callNumberMethod(context?.thisValue, property, args, budget, context)
|
|
16
17
|
});
|
|
17
18
|
}
|
|
18
19
|
export function isNumberMethodName(property) {
|
|
19
20
|
return typeof property === "string" && numberMethodNames.has(property);
|
|
20
21
|
}
|
|
21
|
-
export function callNumberMethod(value, methodName, args, budget) {
|
|
22
|
+
export function callNumberMethod(value, methodName, args, budget, context) {
|
|
22
23
|
if (typeof value !== "number") {
|
|
23
24
|
throw new TypeError(`Number#${methodName} requires a number receiver.`);
|
|
24
25
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
switch (methodName) {
|
|
29
|
-
case "toString":
|
|
30
|
-
return value.toString(asValidatedRadix(args[0]));
|
|
31
|
-
case "toExponential":
|
|
32
|
-
return args[0] === undefined
|
|
33
|
-
? value.toExponential()
|
|
34
|
-
: value.toExponential(asValidatedFractionDigits(args[0], methodName));
|
|
35
|
-
case "toFixed":
|
|
36
|
-
return value.toFixed(asValidatedFractionDigits(args[0], methodName));
|
|
37
|
-
case "toPrecision":
|
|
38
|
-
return args[0] === undefined
|
|
39
|
-
? value.toPrecision()
|
|
40
|
-
: value.toPrecision(asValidatedPrecision(args[0]));
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
function asValidatedRadix(value) {
|
|
44
|
-
if (value === undefined) {
|
|
45
|
-
return undefined;
|
|
46
|
-
}
|
|
47
|
-
const radix = toIntegerOrInfinity(value);
|
|
48
|
-
if (radix < 2 || radix > 36) {
|
|
49
|
-
throw new RangeError("Number#toString radix must be between 2 and 36.");
|
|
26
|
+
const argument = args[0];
|
|
27
|
+
if (argument !== null && typeof argument === "object") {
|
|
28
|
+
return formatObjectArgument(value, methodName, argument, budget, context);
|
|
50
29
|
}
|
|
51
|
-
return
|
|
30
|
+
return formatNumber(value, methodName, argument === undefined ? undefined : Number(argument), budget);
|
|
52
31
|
}
|
|
53
|
-
function
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
32
|
+
async function formatObjectArgument(value, methodName, argument, budget, context) {
|
|
33
|
+
const retainedArgument = {};
|
|
34
|
+
budget.setRetainedValues(retainedArgument, () => [argument]);
|
|
35
|
+
try {
|
|
36
|
+
const number = await sandboxNumber(argument, budget, context);
|
|
37
|
+
return formatNumber(value, methodName, number, budget);
|
|
57
38
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
function asValidatedPrecision(value) {
|
|
61
|
-
const precision = toIntegerOrInfinity(value);
|
|
62
|
-
if (precision < 1 || precision > 100) {
|
|
63
|
-
throw new RangeError("Number#toPrecision precision must be between 1 and 100.");
|
|
39
|
+
finally {
|
|
40
|
+
budget.setRetainedValues(retainedArgument, undefined);
|
|
64
41
|
}
|
|
65
|
-
return precision;
|
|
66
42
|
}
|
|
67
|
-
function
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
43
|
+
function formatNumber(value, methodName, argument, budget) {
|
|
44
|
+
let result;
|
|
45
|
+
try {
|
|
46
|
+
result = value[methodName](argument);
|
|
71
47
|
}
|
|
72
|
-
|
|
73
|
-
|
|
48
|
+
catch (error) {
|
|
49
|
+
if (!(error instanceof RangeError))
|
|
50
|
+
throw error;
|
|
51
|
+
const detail = methodName === "toString" ? "radix must be between 2 and 36."
|
|
52
|
+
: methodName === "toPrecision" ? "precision must be between 1 and 100."
|
|
53
|
+
: "digits must be between 0 and 100.";
|
|
54
|
+
throw new RangeError(`Number#${methodName} ${detail}`);
|
|
74
55
|
}
|
|
75
|
-
return
|
|
56
|
+
return budget.allocateString(result);
|
|
76
57
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { invokeBuiltinClosure } from "../builtin-call.js";
|
|
1
2
|
import { CompileScope } from "../regex/compile-guard.js";
|
|
3
|
+
import { sandboxString } from "../string-coercion.js";
|
|
2
4
|
import { createSandboxClosure, createSandboxRegex, deepCopyFromSandbox, isSandboxClosure, isSandboxRegex } from "../values.js";
|
|
3
5
|
import { executeRegex, toMatchArray } from "./regex.js";
|
|
4
6
|
const SPLIT_STRING_MESSAGE = "String#split only supports string separator values.";
|
|
@@ -51,9 +53,21 @@ export function getStringMember(value, property, budget) {
|
|
|
51
53
|
name: `String#${property}`,
|
|
52
54
|
...(property === "localeCompare" ? { length: 1 } : {}),
|
|
53
55
|
...(property === "isWellFormed" || property === "toWellFormed" ? { length: 0 } : {}),
|
|
54
|
-
call: (args, context) =>
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
call: async (args, context) => {
|
|
57
|
+
const receiver = context?.thisValue;
|
|
58
|
+
if (receiver === null || receiver === undefined) {
|
|
59
|
+
throw new TypeError(`String#${property} requires a non-null receiver.`);
|
|
60
|
+
}
|
|
61
|
+
const retainedReceiver = {};
|
|
62
|
+
budget.setRetainedValues(retainedReceiver, () => [receiver]);
|
|
63
|
+
try {
|
|
64
|
+
const string = await sandboxString(receiver, budget, context);
|
|
65
|
+
return await callStringMethod(string, property, args, budget, (closure, closureArgs) => invokeBuiltinClosure(closure, closureArgs, budget, context, undefined), context?.compilation);
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
budget.setRetainedValues(retainedReceiver, undefined);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
57
71
|
});
|
|
58
72
|
}
|
|
59
73
|
function getStringIndex(property) {
|
|
File without changes
|