poe-code 14.0.74 → 14.0.76
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 +1283 -144
- 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-YEZOXLY4.js → chunk-UZYQWFMY.js} +1233 -143
- package/packages/safe-js/dist/chunks/chunk-UZYQWFMY.js.map +7 -0
- package/packages/safe-js/dist/chunks/{chunk-2J6W3YGB.js → chunk-VD2AS4E4.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/index.js.map +1 -1
- package/packages/safe-js/dist/interp/bigint-operators.d.ts +3 -0
- package/packages/safe-js/dist/interp/bigint-operators.js +62 -0
- package/packages/safe-js/dist/interp/boxed.d.ts +2 -2
- package/packages/safe-js/dist/interp/boxed.js +4 -1
- package/packages/safe-js/dist/interp/globals/bigint.d.ts +2 -0
- package/packages/safe-js/dist/interp/globals/bigint.js +85 -0
- package/packages/safe-js/dist/interp/globals/console-json.js +57 -24
- package/packages/safe-js/dist/interp/globals/object-array.js +1 -1
- package/packages/safe-js/dist/interp/globals/regex.js +108 -2
- package/packages/safe-js/dist/interp/globals.d.ts +1 -0
- package/packages/safe-js/dist/interp/globals.js +2 -0
- package/packages/safe-js/dist/interp/host-bridge.js +2 -0
- package/packages/safe-js/dist/interp/interpreter.js +59 -12
- package/packages/safe-js/dist/interp/iteration.js +5 -2
- package/packages/safe-js/dist/interp/methods/number.js +1 -1
- package/packages/safe-js/dist/interp/methods/regex-split.d.ts +3 -0
- package/packages/safe-js/dist/interp/methods/regex-split.js +102 -0
- package/packages/safe-js/dist/interp/methods/regex.d.ts +1 -1
- package/packages/safe-js/dist/interp/methods/regex.js +16 -5
- package/packages/safe-js/dist/interp/methods/regexp-iterator.d.ts +5 -1
- package/packages/safe-js/dist/interp/methods/regexp-iterator.js +59 -7
- package/packages/safe-js/dist/interp/methods/string.js +9 -9
- package/packages/safe-js/dist/interp/object-model.d.ts +1 -0
- package/packages/safe-js/dist/interp/object-model.js +4 -1
- package/packages/safe-js/dist/interp/regex/compile-guard.js +26 -4
- package/packages/safe-js/dist/interp/regex/engine.d.ts +4 -0
- package/packages/safe-js/dist/interp/regex/engine.js +230 -30
- package/packages/safe-js/dist/interp/regex/parse.d.ts +42 -4
- package/packages/safe-js/dist/interp/regex/parse.js +429 -25
- package/packages/safe-js/dist/interp/regexp-iterator.d.ts +4 -2
- package/packages/safe-js/dist/interp/regexp-iterator.js +6 -1
- package/packages/safe-js/dist/interp/string-coercion.d.ts +1 -1
- package/packages/safe-js/dist/interp/string-coercion.js +8 -3
- package/packages/safe-js/dist/interp/values.d.ts +1 -1
- package/packages/safe-js/dist/interp/values.js +10 -3
- package/packages/safe-js/dist/lint/rules/AS-async-not-needed.js +2 -0
- package/packages/safe-js/dist/lint/rules/AS-missing-async.js +2 -0
- package/packages/safe-js/dist/lint/rules/known-globals.d.ts +1 -1
- package/packages/safe-js/dist/lint/rules/known-globals.js +1 -0
- package/packages/safe-js/dist/parse/parser.d.ts +6 -1
- package/packages/safe-js/dist/parse/parser.js +8 -0
- package/packages/safe-js/dist/parse/tokenizer.js +12 -4
- package/packages/safe-js/dist/parse.d.ts +1 -1
- package/packages/safe-js/dist/snapshot/bigint.d.ts +1 -0
- package/packages/safe-js/dist/snapshot/bigint.js +14 -0
- package/packages/safe-js/dist/snapshot/dump-format.js +12 -2
- package/packages/safe-js/dist/snapshot/replay-data.d.ts +6 -0
- package/packages/safe-js/dist/snapshot/replay-data.js +23 -5
- package/packages/safe-js/dist/snapshot/restore.js +10 -2
- package/packages/safe-js/dist/snapshot/serialize.d.ts +4 -1
- package/packages/safe-js/dist/snapshot/serialize.js +6 -1
- package/packages/safe-js/dist/snapshot/validation.js +27 -0
- package/packages/safe-js/dist/chunks/chunk-YEZOXLY4.js.map +0 -7
- /package/packages/safe-js/dist/chunks/{chunk-2J6W3YGB.js.map → chunk-VD2AS4E4.js.map} +0 -0
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
import { createSandboxClosure, createSandboxRegex, isSandboxRegex, reconcileCompiledValues } from "../values.js";
|
|
1
|
+
import { createSandboxClosure, createSandboxRegex, isSandboxClosure, isSandboxRegex, reconcileCompiledValues } from "../values.js";
|
|
2
2
|
import { CompileScope } from "../regex/compile-guard.js";
|
|
3
3
|
import { SandboxError } from "../budget.js";
|
|
4
|
-
import { sandboxString } from "../string-coercion.js";
|
|
4
|
+
import { sandboxNumber, sandboxString } from "../string-coercion.js";
|
|
5
5
|
import { getSandboxPropertyDescriptor, installRegexPrototype, materializeFunctionProperties, setSandboxPrototype } from "../object-model.js";
|
|
6
6
|
import { accessorAdapter, readPropertyDescriptor } from "../accessors.js";
|
|
7
7
|
import { callRegexMethod, getRegexMember, regexFlagProperties, regexSearch } from "../methods/regex.js";
|
|
8
8
|
import { regexMatch, regexReplace } from "../methods/string.js";
|
|
9
9
|
import { invokeBuiltinClosure } from "../builtin-call.js";
|
|
10
|
+
import { restoreSandboxRegExpIterator } from "../regexp-iterator.js";
|
|
11
|
+
import { normalizeLastIndex } from "../regex/engine.js";
|
|
12
|
+
import { retainValues } from "../resources.js";
|
|
13
|
+
import { setSandboxProperty } from "../interpreter.js";
|
|
14
|
+
import { regexSplit } from "../methods/regex-split.js";
|
|
10
15
|
export function createRegexGlobals(options) {
|
|
11
16
|
const invoke = (construct) => async (args, context) => {
|
|
12
17
|
const selected = options.compileOwner ?? context?.compilation?.owner;
|
|
@@ -75,7 +80,52 @@ export function createRegexGlobals(options) {
|
|
|
75
80
|
}
|
|
76
81
|
};
|
|
77
82
|
const constructor = createSandboxClosure({ guest: true, sandbox: true, name: "RegExp", length: 2, call: invoke(false), construct: invoke(true) });
|
|
83
|
+
Object.defineProperty(materializeFunctionProperties(constructor), "escape", {
|
|
84
|
+
value: createSandboxClosure({ guest: true, sandbox: true, name: "escape", length: 1,
|
|
85
|
+
call: (args) => {
|
|
86
|
+
const input = args[0];
|
|
87
|
+
if (typeof input !== "string")
|
|
88
|
+
throw new TypeError("RegExp.escape requires a string.");
|
|
89
|
+
const allocation = {};
|
|
90
|
+
let escaped = "";
|
|
91
|
+
try {
|
|
92
|
+
for (const character of input) {
|
|
93
|
+
options.budget.visitNode();
|
|
94
|
+
const point = character.codePointAt(0);
|
|
95
|
+
let part = character;
|
|
96
|
+
if (escaped.length === 0 && ((point >= 48 && point <= 57) ||
|
|
97
|
+
(point >= 65 && point <= 90) || (point >= 97 && point <= 122))) {
|
|
98
|
+
part = `\\x${point.toString(16)}`;
|
|
99
|
+
}
|
|
100
|
+
else if ("^$\\.*+?()[]{}|/".includes(character)) {
|
|
101
|
+
part = "\\" + character;
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
const control = "\f\n\r\t\v".indexOf(character);
|
|
105
|
+
if (control !== -1)
|
|
106
|
+
part = "\\" + "fnrtv"[control];
|
|
107
|
+
else if (",-=<>#&!%:;@~'`\"".includes(character) || character.trim() === "" ||
|
|
108
|
+
(point >= 0xd800 && point <= 0xdfff)) {
|
|
109
|
+
part = point <= 0xff ? `\\x${point.toString(16).padStart(2, "0")}`
|
|
110
|
+
: `\\u${point.toString(16).padStart(4, "0")}`;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
options.budget.setRetainedDataUsage(allocation, escaped.length + part.length);
|
|
114
|
+
escaped = options.budget.allocateString(escaped + part);
|
|
115
|
+
}
|
|
116
|
+
return escaped;
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
options.budget.setRetainedDataUsage(allocation, 0);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}), writable: true, configurable: true
|
|
123
|
+
});
|
|
78
124
|
const prototype = Object.create(null);
|
|
125
|
+
Object.defineProperty(materializeFunctionProperties(constructor), Symbol.species, {
|
|
126
|
+
get: accessorAdapter(createSandboxClosure({ sandbox: true, name: "get [Symbol.species]", length: 0,
|
|
127
|
+
call: (_args, context) => context?.thisValue }), "get"), configurable: true
|
|
128
|
+
});
|
|
79
129
|
Object.defineProperty(materializeFunctionProperties(constructor), "prototype", { value: prototype, writable: false });
|
|
80
130
|
Object.defineProperty(prototype, "constructor", { value: constructor, writable: true, configurable: true });
|
|
81
131
|
Object.defineProperty(prototype, Symbol.search, {
|
|
@@ -93,6 +143,62 @@ export function createRegexGlobals(options) {
|
|
|
93
143
|
call: (args, context) => regexReplace(args[0], context?.thisValue, args[1], options.budget, (closure, values) => invokeBuiltinClosure(closure, values, options.budget, context, undefined), context) }),
|
|
94
144
|
writable: true, configurable: true
|
|
95
145
|
});
|
|
146
|
+
Object.defineProperty(prototype, Symbol.matchAll, {
|
|
147
|
+
value: createSandboxClosure({ guest: true, sandbox: true, name: "[Symbol.matchAll]", length: 1,
|
|
148
|
+
call: async (args, context) => {
|
|
149
|
+
const target = context?.thisValue;
|
|
150
|
+
if (target === null || typeof target !== "object")
|
|
151
|
+
throw new TypeError("RegExp matchAll requires an object receiver.");
|
|
152
|
+
let input = args[0];
|
|
153
|
+
let string;
|
|
154
|
+
let species;
|
|
155
|
+
let field;
|
|
156
|
+
let flags;
|
|
157
|
+
let matcher;
|
|
158
|
+
const release = retainValues(options.budget, () => [target, input, string, species, field, flags, matcher]);
|
|
159
|
+
const read = (value, key) => {
|
|
160
|
+
if (context?.getProperty !== undefined)
|
|
161
|
+
return context.getProperty(value, key);
|
|
162
|
+
const descriptor = getSandboxPropertyDescriptor(value, key, options.budget);
|
|
163
|
+
return descriptor === undefined ? undefined : readPropertyDescriptor(descriptor, value, context);
|
|
164
|
+
};
|
|
165
|
+
try {
|
|
166
|
+
string = await sandboxString(input, options.budget, context);
|
|
167
|
+
input = undefined;
|
|
168
|
+
field = await read(target, "constructor");
|
|
169
|
+
species = constructor;
|
|
170
|
+
if (field !== undefined) {
|
|
171
|
+
if (field === null || typeof field !== "object")
|
|
172
|
+
throw new TypeError("Invalid RegExp species constructor.");
|
|
173
|
+
species = await read(field, Symbol.species);
|
|
174
|
+
if (species === null || species === undefined)
|
|
175
|
+
species = constructor;
|
|
176
|
+
}
|
|
177
|
+
field = undefined;
|
|
178
|
+
if (!isSandboxClosure(species) || species.construct === undefined)
|
|
179
|
+
throw new TypeError("RegExp species must be a constructor.");
|
|
180
|
+
field = await read(target, "flags");
|
|
181
|
+
flags = await sandboxString(field, options.budget, context);
|
|
182
|
+
field = undefined;
|
|
183
|
+
matcher = await invokeBuiltinClosure(species, [target, flags], options.budget, context, undefined, true);
|
|
184
|
+
field = await read(target, "lastIndex");
|
|
185
|
+
const cursor = normalizeLastIndex(await sandboxNumber(field, options.budget, context));
|
|
186
|
+
field = undefined;
|
|
187
|
+
await setSandboxProperty(matcher, "lastIndex", cursor, options.budget, true, context);
|
|
188
|
+
return restoreSandboxRegExpIterator({ matcher, input: string, exhausted: false,
|
|
189
|
+
global: flags.includes("g"), unicode: flags.includes("u") || flags.includes("v") });
|
|
190
|
+
}
|
|
191
|
+
finally {
|
|
192
|
+
release();
|
|
193
|
+
}
|
|
194
|
+
} }),
|
|
195
|
+
writable: true, configurable: true
|
|
196
|
+
});
|
|
197
|
+
Object.defineProperty(prototype, Symbol.split, {
|
|
198
|
+
value: createSandboxClosure({ guest: true, sandbox: true, name: "[Symbol.split]", length: 2,
|
|
199
|
+
call: (args, context) => regexSplit(context?.thisValue, args[0], args[1], constructor, options.budget, context) }),
|
|
200
|
+
writable: true, configurable: true
|
|
201
|
+
});
|
|
96
202
|
for (const name of ["exec", "test", "toString"]) {
|
|
97
203
|
Object.defineProperty(prototype, name, {
|
|
98
204
|
value: createSandboxClosure({ sandbox: true, name, length: name === "toString" ? 0 : 1,
|
|
@@ -28,6 +28,7 @@ export declare function createBuiltinBindings(options: Parameters<typeof createC
|
|
|
28
28
|
Float32Array: import("./values.js").SandboxClosure;
|
|
29
29
|
Date: import("./values.js").SandboxClosure;
|
|
30
30
|
Symbol: import("./values.js").SandboxClosure;
|
|
31
|
+
BigInt: import("./values.js").SandboxClosure;
|
|
31
32
|
Map: import("./values.js").SandboxClosure;
|
|
32
33
|
Set: import("./values.js").SandboxClosure;
|
|
33
34
|
JSON: import("./values.js").SandboxObject;
|
|
@@ -9,6 +9,7 @@ import { createObjectArrayGlobals } from "./globals/object-array.js";
|
|
|
9
9
|
import { createPromiseGlobals } from "./promise.js";
|
|
10
10
|
import { createDateGlobal } from "./globals/date.js";
|
|
11
11
|
import { createSymbolGlobal } from "./globals/symbol.js";
|
|
12
|
+
import { createBigIntGlobal } from "./globals/bigint.js";
|
|
12
13
|
export function createBuiltinBindings(options) {
|
|
13
14
|
return {
|
|
14
15
|
...createConsoleJsonGlobals(options),
|
|
@@ -16,6 +17,7 @@ export function createBuiltinBindings(options) {
|
|
|
16
17
|
Float32Array: createFloat32ArrayGlobal(options.budget),
|
|
17
18
|
Date: createDateGlobal(options),
|
|
18
19
|
Symbol: createSymbolGlobal(options.budget),
|
|
20
|
+
BigInt: createBigIntGlobal(options.budget),
|
|
19
21
|
...createErrorGlobals(options),
|
|
20
22
|
...createMathGlobals({ random: options.random }),
|
|
21
23
|
...createObjectArrayGlobals(options),
|
|
@@ -561,6 +561,7 @@ function isSandboxLikeValue(value) {
|
|
|
561
561
|
value === undefined ||
|
|
562
562
|
typeof value === "string" ||
|
|
563
563
|
typeof value === "number" ||
|
|
564
|
+
typeof value === "bigint" ||
|
|
564
565
|
typeof value === "boolean") {
|
|
565
566
|
return true;
|
|
566
567
|
}
|
|
@@ -628,6 +629,7 @@ export function copyHostValueToSandbox(value, stackFrames, options, state, path)
|
|
|
628
629
|
if (value === null ||
|
|
629
630
|
value === undefined ||
|
|
630
631
|
typeof value === "number" ||
|
|
632
|
+
typeof value === "bigint" ||
|
|
631
633
|
typeof value === "boolean") {
|
|
632
634
|
return value;
|
|
633
635
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { promiseReplayContext } from "./promise-replay.js";
|
|
2
|
+
import { bigIntOperation } from "./bigint-operators.js";
|
|
2
3
|
import { accessorAdapter, readPropertyDescriptor, writePropertyDescriptor } from "./accessors.js";
|
|
3
4
|
import { deleteHostObjectMember, getHostObjectKeys, getHostObjectMember, hasHostObjectMember, isGuestHostObject, setHostObjectMember } from "./host-capabilities.js";
|
|
4
5
|
import { propertyFunctionName, toPropertyKey } from "./property-key.js";
|
|
@@ -51,6 +52,17 @@ const dispatchTable = {
|
|
|
51
52
|
ArrowFunctionExpression: evaluateArrowFunction,
|
|
52
53
|
AwaitExpression: evaluateAwait,
|
|
53
54
|
BinaryExpression: evaluateBinaryExpression,
|
|
55
|
+
BigIntLiteral: async (node, context) => {
|
|
56
|
+
const allocation = {};
|
|
57
|
+
context.budget.visitNode(node.value.length);
|
|
58
|
+
context.budget.setRetainedDataUsage(allocation, node.value.length);
|
|
59
|
+
try {
|
|
60
|
+
return { kind: "normal", hasValue: true, value: BigInt(node.value) };
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
context.budget.setRetainedDataUsage(allocation, 0);
|
|
64
|
+
}
|
|
65
|
+
},
|
|
54
66
|
BlockStatement: evaluateBlockStatement,
|
|
55
67
|
BooleanLiteral: evaluatePrimitiveLiteral,
|
|
56
68
|
CallExpression: evaluateCallExpression,
|
|
@@ -1805,8 +1817,11 @@ async function evaluateIdentifierUpdateExpression(node, context) {
|
|
|
1805
1817
|
error: createError("UNBOUND_IDENTIFIER", node.argument, `Identifier '${node.argument.name}' is not defined.`)
|
|
1806
1818
|
};
|
|
1807
1819
|
}
|
|
1808
|
-
const
|
|
1809
|
-
const
|
|
1820
|
+
const primitive = await toNumericPrimitive(binding.value, context);
|
|
1821
|
+
const current = typeof primitive === "bigint" ? primitive : toNumber(primitive);
|
|
1822
|
+
const next = typeof current === "bigint"
|
|
1823
|
+
? bigIntOperation(node.operator === "++" ? "+" : "-", current, 1n, context.budget)
|
|
1824
|
+
: node.operator === "++" ? current + 1 : current - 1;
|
|
1810
1825
|
context.scope.assign(node.argument.name, next);
|
|
1811
1826
|
return {
|
|
1812
1827
|
kind: "normal",
|
|
@@ -1823,8 +1838,11 @@ async function evaluateMemberUpdateExpression(node, context) {
|
|
|
1823
1838
|
throw new TypeError("Cannot update properties of null or undefined.");
|
|
1824
1839
|
}
|
|
1825
1840
|
const property = await toPropertyKey(member.property, context.budget, createCoercionContext(context));
|
|
1826
|
-
const
|
|
1827
|
-
const
|
|
1841
|
+
const primitive = await toNumericPrimitive(await getPropertyValue(member.object, property, context, member.superReceiver === undefined ? member.object : member.superReceiver.value), context);
|
|
1842
|
+
const current = typeof primitive === "bigint" ? primitive : toNumber(primitive);
|
|
1843
|
+
const next = typeof current === "bigint"
|
|
1844
|
+
? bigIntOperation(node.operator === "++" ? "+" : "-", current, 1n, context.budget)
|
|
1845
|
+
: node.operator === "++" ? current + 1 : current - 1;
|
|
1828
1846
|
if (member.superReceiver === undefined)
|
|
1829
1847
|
await setSandboxProperty(member.object, property, next, context.budget, true, createCoercionContext(context));
|
|
1830
1848
|
else
|
|
@@ -1858,7 +1876,7 @@ function getPropertyValue(target, property, context, receiver = target) {
|
|
|
1858
1876
|
return readPropertyDescriptor(descriptor, receiver, createCoercionContext(context), true);
|
|
1859
1877
|
if (isSandboxRegExpIterator(target))
|
|
1860
1878
|
return getRegExpIteratorMember(property, context.budget);
|
|
1861
|
-
if (typeof target === "symbol") {
|
|
1879
|
+
if (typeof target === "symbol" || typeof target === "bigint") {
|
|
1862
1880
|
const prototype = getBoxedPrototype(target, context.budget);
|
|
1863
1881
|
return prototype === undefined ? undefined : getPropertyValue(prototype, property, context, receiver);
|
|
1864
1882
|
}
|
|
@@ -2041,6 +2059,8 @@ async function evaluateObjectPropertyKey(node, context) {
|
|
|
2041
2059
|
return evaluateMemberProperty(node.key, context);
|
|
2042
2060
|
}
|
|
2043
2061
|
function getStaticPropertyName(node) {
|
|
2062
|
+
if (node.type === "BigIntLiteral")
|
|
2063
|
+
return BigInt(node.value).toString();
|
|
2044
2064
|
if (node.type === "Identifier") {
|
|
2045
2065
|
return node.name;
|
|
2046
2066
|
}
|
|
@@ -2074,7 +2094,7 @@ async function evaluateMemberCallExpression(node, context) {
|
|
|
2074
2094
|
return evaluateResolvedCallExpression(node, await getPropertyValue(member.object, member.property, context), context, member.object);
|
|
2075
2095
|
if (Array.isArray(member.object) && hasExplicitSandboxPrototype(member.object))
|
|
2076
2096
|
return evaluateResolvedCallExpression(node, await getPropertyValue(member.object, member.property, context), context, member.object);
|
|
2077
|
-
if ((typeof member.object === "string" || typeof member.object === "number" || typeof member.object === "boolean" || typeof member.object === "symbol") &&
|
|
2097
|
+
if ((typeof member.object === "string" || typeof member.object === "number" || typeof member.object === "bigint" || typeof member.object === "boolean" || typeof member.object === "symbol") &&
|
|
2078
2098
|
getBoxedPrototype(member.object, context.budget) !== undefined) {
|
|
2079
2099
|
if (isDefaultBoxedMethod(member.object, member.property, context.budget)) {
|
|
2080
2100
|
if (typeof member.object === "string" && isStringMethodName(member.property))
|
|
@@ -2259,10 +2279,14 @@ async function applyUnaryOperator(operator, value, context) {
|
|
|
2259
2279
|
return undefined;
|
|
2260
2280
|
case "+":
|
|
2261
2281
|
return toNumber(await toNumericPrimitive(value, context));
|
|
2262
|
-
case "-":
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2282
|
+
case "-": {
|
|
2283
|
+
const primitive = await toNumericPrimitive(value, context);
|
|
2284
|
+
return typeof primitive === "bigint" ? bigIntOperation("-", 0n, primitive, context.budget) : -toNumber(primitive);
|
|
2285
|
+
}
|
|
2286
|
+
case "~": {
|
|
2287
|
+
const primitive = await toNumericPrimitive(value, context);
|
|
2288
|
+
return typeof primitive === "bigint" ? bigIntOperation("^", primitive, -1n, context.budget) : ~toNumber(primitive);
|
|
2289
|
+
}
|
|
2266
2290
|
}
|
|
2267
2291
|
}
|
|
2268
2292
|
function describeTypeofValue(value) {
|
|
@@ -2278,6 +2302,12 @@ function isTruthy(value) {
|
|
|
2278
2302
|
return Boolean(value);
|
|
2279
2303
|
}
|
|
2280
2304
|
function applyBinaryOperator(node, left, right, context) {
|
|
2305
|
+
if ((typeof left === "bigint" || typeof right === "bigint") &&
|
|
2306
|
+
["-", "*", "/", "%", "**", "&", "|", "^", "<<", ">>", ">>>"].includes(node.operator)) {
|
|
2307
|
+
if (typeof left !== "bigint" || typeof right !== "bigint")
|
|
2308
|
+
throw new TypeError("Cannot mix BigInt and other numeric types.");
|
|
2309
|
+
return bigIntOperation(node.operator, left, right, context.budget);
|
|
2310
|
+
}
|
|
2281
2311
|
switch (node.operator) {
|
|
2282
2312
|
case "+":
|
|
2283
2313
|
return applyAdditionOperator(left, right, context);
|
|
@@ -2410,6 +2440,11 @@ async function applyCompoundAssignmentOperator(operator, left, right, context) {
|
|
|
2410
2440
|
if (convertingObject)
|
|
2411
2441
|
convertedLeft = left;
|
|
2412
2442
|
right = await toNumericPrimitive(right, context, operator === "+=" ? "default" : "number");
|
|
2443
|
+
if (operator !== "+=" && (typeof left === "bigint" || typeof right === "bigint")) {
|
|
2444
|
+
if (typeof left !== "bigint" || typeof right !== "bigint")
|
|
2445
|
+
throw new TypeError("Cannot mix BigInt and other numeric types.");
|
|
2446
|
+
return bigIntOperation(operator.slice(0, -1), left, right, context.budget);
|
|
2447
|
+
}
|
|
2413
2448
|
switch (operator) {
|
|
2414
2449
|
case "+=":
|
|
2415
2450
|
return applyAdditionOperator(left, right, context);
|
|
@@ -2447,6 +2482,11 @@ function applyAdditionOperator(left, right, context) {
|
|
|
2447
2482
|
if (typeof leftPrimitive === "string" || typeof rightPrimitive === "string") {
|
|
2448
2483
|
return context.budget.allocateString(toString(leftPrimitive) + toString(rightPrimitive));
|
|
2449
2484
|
}
|
|
2485
|
+
if (typeof leftPrimitive === "bigint" || typeof rightPrimitive === "bigint") {
|
|
2486
|
+
if (typeof leftPrimitive !== "bigint" || typeof rightPrimitive !== "bigint")
|
|
2487
|
+
throw new TypeError("Cannot mix BigInt and other numeric types.");
|
|
2488
|
+
return bigIntOperation("+", leftPrimitive, rightPrimitive, context.budget);
|
|
2489
|
+
}
|
|
2450
2490
|
return toNumber(leftPrimitive) + toNumber(rightPrimitive);
|
|
2451
2491
|
}
|
|
2452
2492
|
function compareRelational(left, right, operator) {
|
|
@@ -2464,8 +2504,9 @@ function compareRelational(left, right, operator) {
|
|
|
2464
2504
|
return leftPrimitive >= rightPrimitive;
|
|
2465
2505
|
}
|
|
2466
2506
|
}
|
|
2467
|
-
const
|
|
2468
|
-
const
|
|
2507
|
+
const hasBigInt = typeof leftPrimitive === "bigint" || typeof rightPrimitive === "bigint";
|
|
2508
|
+
const leftNumber = typeof leftPrimitive === "bigint" || (hasBigInt && typeof leftPrimitive === "string") ? leftPrimitive : toNumber(leftPrimitive);
|
|
2509
|
+
const rightNumber = typeof rightPrimitive === "bigint" || (hasBigInt && typeof rightPrimitive === "string") ? rightPrimitive : toNumber(rightPrimitive);
|
|
2469
2510
|
switch (operator) {
|
|
2470
2511
|
case "<":
|
|
2471
2512
|
return leftNumber < rightNumber;
|
|
@@ -2478,6 +2519,8 @@ function compareRelational(left, right, operator) {
|
|
|
2478
2519
|
}
|
|
2479
2520
|
}
|
|
2480
2521
|
function isLooselyEqual(left, right) {
|
|
2522
|
+
if (typeof left === "bigint" || typeof right === "bigint")
|
|
2523
|
+
return left == right;
|
|
2481
2524
|
const leftType = getCoercionType(left);
|
|
2482
2525
|
const rightType = getCoercionType(right);
|
|
2483
2526
|
if (leftType === rightType) {
|
|
@@ -2510,6 +2553,8 @@ function isPrimitiveCoercionType(type) {
|
|
|
2510
2553
|
return type !== "object";
|
|
2511
2554
|
}
|
|
2512
2555
|
function getCoercionType(value) {
|
|
2556
|
+
if (typeof value === "bigint")
|
|
2557
|
+
return "bigint";
|
|
2513
2558
|
if (typeof value === "symbol")
|
|
2514
2559
|
return "symbol";
|
|
2515
2560
|
if (value === null) {
|
|
@@ -2544,6 +2589,8 @@ async function toNumericPrimitive(value, context, hint = "number") {
|
|
|
2544
2589
|
throw new TypeError("Expected a sandbox value.");
|
|
2545
2590
|
}
|
|
2546
2591
|
function toNumber(value) {
|
|
2592
|
+
if (typeof value === "bigint")
|
|
2593
|
+
throw new TypeError("Cannot convert a BigInt value to a number");
|
|
2547
2594
|
if (typeof value === "symbol")
|
|
2548
2595
|
throw new TypeError("Cannot convert a Symbol value to a number");
|
|
2549
2596
|
if (isSandboxDate(value))
|
|
@@ -5,7 +5,7 @@ import { boxedValue, isSandboxBox } from "./boxed.js";
|
|
|
5
5
|
import { getHostObjectIterator, isGuestHostObject } from "./host-capabilities.js";
|
|
6
6
|
import { isSandboxCollectionIterator, nextCollectionIterator } from "./collection-iterator.js";
|
|
7
7
|
import { isSandboxRegExpIterator } from "./regexp-iterator.js";
|
|
8
|
-
import { nextRegExpIterator } from "./methods/regexp-iterator.js";
|
|
8
|
+
import { nextObservableRegExpIterator, nextRegExpIterator } from "./methods/regexp-iterator.js";
|
|
9
9
|
import { Budget, isFatalSandboxError } from "./budget.js";
|
|
10
10
|
import { sandboxString } from "./string-coercion.js";
|
|
11
11
|
import { awaitSandboxValue, awaitWithSignal } from "./cancel.js";
|
|
@@ -225,8 +225,11 @@ export function getSandboxIterator(value, budget, context) {
|
|
|
225
225
|
}
|
|
226
226
|
if (isSandboxCollectionIterator(value))
|
|
227
227
|
return { next: () => nextCollectionIterator(value, budget), snapshotIndex: () => 0 };
|
|
228
|
-
if (isSandboxRegExpIterator(value))
|
|
228
|
+
if (isSandboxRegExpIterator(value)) {
|
|
229
|
+
if (context !== undefined && budget !== undefined)
|
|
230
|
+
return { asynchronous: true, next: () => nextObservableRegExpIterator(value, budget, context), snapshotIndex: () => 0 };
|
|
229
231
|
return { next: () => nextRegExpIterator(value, budget), snapshotIndex: () => 0 };
|
|
232
|
+
}
|
|
230
233
|
if (isGuestHostObject(value))
|
|
231
234
|
return getHostObjectIterator(value);
|
|
232
235
|
if (isFloat32Array(value)) {
|
|
@@ -30,7 +30,7 @@ export function callNumberMethod(value, methodName, args, budget, context) {
|
|
|
30
30
|
if (argument !== null && typeof argument === "object") {
|
|
31
31
|
return formatObjectArgument(value, methodName, argument, budget, context);
|
|
32
32
|
}
|
|
33
|
-
return formatNumber(value, methodName, argument === undefined ? undefined :
|
|
33
|
+
return formatNumber(value, methodName, argument === undefined ? undefined : +argument, budget);
|
|
34
34
|
}
|
|
35
35
|
async function formatObjectArgument(value, methodName, argument, budget, context) {
|
|
36
36
|
const retainedArgument = {};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type Budget } from "../budget.js";
|
|
2
|
+
import { type SandboxCallContext, type SandboxClosure, type SandboxValue } from "../values.js";
|
|
3
|
+
export declare function regexSplit(target: SandboxValue, input: SandboxValue, limit: SandboxValue, constructor: SandboxClosure, budget: Budget, context?: SandboxCallContext): Promise<SandboxValue[]>;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { isSandboxClosure } from "../values.js";
|
|
2
|
+
import { getSandboxPropertyDescriptor } from "../object-model.js";
|
|
3
|
+
import { readPropertyDescriptor } from "../accessors.js";
|
|
4
|
+
import { invokeBuiltinClosure } from "../builtin-call.js";
|
|
5
|
+
import { setSandboxProperty } from "../interpreter.js";
|
|
6
|
+
import { sandboxNumber, sandboxString } from "../string-coercion.js";
|
|
7
|
+
import { normalizeLastIndex } from "../regex/engine.js";
|
|
8
|
+
import { retainValues } from "../resources.js";
|
|
9
|
+
import { regexExec } from "./regex.js";
|
|
10
|
+
export async function regexSplit(target, input, limit, constructor, budget, context) {
|
|
11
|
+
if (target === null || typeof target !== "object")
|
|
12
|
+
throw new TypeError("RegExp split requires an object receiver.");
|
|
13
|
+
let string;
|
|
14
|
+
let species;
|
|
15
|
+
let field;
|
|
16
|
+
let flags;
|
|
17
|
+
let matcher;
|
|
18
|
+
let match;
|
|
19
|
+
const result = [];
|
|
20
|
+
const release = retainValues(budget, () => [target, input, limit, string, species, field, flags, matcher, match, result]);
|
|
21
|
+
const read = (value, key) => {
|
|
22
|
+
if (context?.getProperty !== undefined)
|
|
23
|
+
return context.getProperty(value, key);
|
|
24
|
+
const descriptor = getSandboxPropertyDescriptor(value, key, budget);
|
|
25
|
+
return descriptor === undefined ? undefined : readPropertyDescriptor(descriptor, value, context);
|
|
26
|
+
};
|
|
27
|
+
const append = (value) => {
|
|
28
|
+
budget.allocateArrayLength(result.length + 1);
|
|
29
|
+
result.push(value);
|
|
30
|
+
};
|
|
31
|
+
try {
|
|
32
|
+
string = await sandboxString(input, budget, context);
|
|
33
|
+
input = undefined;
|
|
34
|
+
field = await read(target, "constructor");
|
|
35
|
+
species = constructor;
|
|
36
|
+
if (field !== undefined) {
|
|
37
|
+
if (field === null || typeof field !== "object")
|
|
38
|
+
throw new TypeError("Invalid RegExp species constructor.");
|
|
39
|
+
species = await read(field, Symbol.species);
|
|
40
|
+
if (species === null || species === undefined)
|
|
41
|
+
species = constructor;
|
|
42
|
+
}
|
|
43
|
+
field = undefined;
|
|
44
|
+
if (!isSandboxClosure(species) || species.construct === undefined)
|
|
45
|
+
throw new TypeError("RegExp species must be a constructor.");
|
|
46
|
+
field = await read(target, "flags");
|
|
47
|
+
flags = await sandboxString(field, budget, context);
|
|
48
|
+
field = undefined;
|
|
49
|
+
const unicode = flags.includes("u") || flags.includes("v");
|
|
50
|
+
if (!flags.includes("y"))
|
|
51
|
+
flags = budget.allocateString(flags + "y");
|
|
52
|
+
matcher = await invokeBuiltinClosure(species, [target, flags], budget, context, undefined, true);
|
|
53
|
+
const maximum = limit === undefined ? 2 ** 32 - 1 : (await sandboxNumber(limit, budget, context)) >>> 0;
|
|
54
|
+
limit = undefined;
|
|
55
|
+
if (maximum === 0)
|
|
56
|
+
return result;
|
|
57
|
+
if (string.length === 0) {
|
|
58
|
+
match = await regexExec(matcher, string, budget, context);
|
|
59
|
+
if (match === null)
|
|
60
|
+
append(string);
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
let end = 0;
|
|
64
|
+
let index = 0;
|
|
65
|
+
while (index < string.length) {
|
|
66
|
+
budget.visitNode();
|
|
67
|
+
match = undefined;
|
|
68
|
+
await setSandboxProperty(matcher, "lastIndex", index, budget, true, context);
|
|
69
|
+
match = await regexExec(matcher, string, budget, context);
|
|
70
|
+
if (match !== null) {
|
|
71
|
+
field = await read(matcher, "lastIndex");
|
|
72
|
+
const next = Math.min(normalizeLastIndex(await sandboxNumber(field, budget, context)), string.length);
|
|
73
|
+
field = undefined;
|
|
74
|
+
if (next !== end) {
|
|
75
|
+
append(budget.allocateString(string.slice(end, index)));
|
|
76
|
+
if (result.length === maximum)
|
|
77
|
+
return result;
|
|
78
|
+
end = next;
|
|
79
|
+
field = await read(match, "length");
|
|
80
|
+
const length = normalizeLastIndex(await sandboxNumber(field, budget, context));
|
|
81
|
+
field = undefined;
|
|
82
|
+
for (let capture = 1; capture < length; capture++) {
|
|
83
|
+
budget.visitNode();
|
|
84
|
+
field = await read(match, String(capture));
|
|
85
|
+
append(field);
|
|
86
|
+
field = undefined;
|
|
87
|
+
if (result.length === maximum)
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
index = end;
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
index += unicode && (string.codePointAt(index) ?? 0) > 0xffff ? 2 : 1;
|
|
95
|
+
}
|
|
96
|
+
append(budget.allocateString(string.slice(end)));
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
release();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -11,4 +11,4 @@ export declare function callRegexMethod(target: SandboxValue, methodName: RegexM
|
|
|
11
11
|
export declare function regexExec(target: SandboxValue, input: string, budget: Budget, context?: SandboxCallContext): Promise<SandboxValue>;
|
|
12
12
|
export declare function regexToString(target: SandboxValue, budget: Budget, context?: SandboxCallContext): Promise<string>;
|
|
13
13
|
export declare function executeRegex(target: SandboxRegex, input: string, lastIndex: number): RegexMatch | null;
|
|
14
|
-
export declare function toMatchArray(match: RegexMatch | null, input: string): SandboxValue;
|
|
14
|
+
export declare function toMatchArray(match: RegexMatch | null, input: string, budget?: Budget): SandboxValue;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createSandboxClosure, getSandboxRegexPattern, getRegexProperties, isSandboxClosure, isSandboxRegex } from "../values.js";
|
|
2
2
|
import { matchRegex } from "../regex/engine.js";
|
|
3
3
|
import { invokeBuiltinClosure } from "../builtin-call.js";
|
|
4
|
-
import { getSandboxPropertyDescriptor, getSandboxPrototype, hasExplicitSandboxPrototype } from "../object-model.js";
|
|
4
|
+
import { getSandboxPropertyDescriptor, getSandboxPrototype, hasExplicitSandboxPrototype, setSandboxPrototype } from "../object-model.js";
|
|
5
5
|
import { readPropertyDescriptor } from "../accessors.js";
|
|
6
6
|
import { retainValues } from "../resources.js";
|
|
7
7
|
import { sandboxNumber, sandboxString } from "../string-coercion.js";
|
|
@@ -160,7 +160,7 @@ export async function callRegexMethod(target, methodName, args, budget, context)
|
|
|
160
160
|
cursor = target.lastIndex;
|
|
161
161
|
const lastIndex = await sandboxNumber(cursor, budget, context);
|
|
162
162
|
const match = executeRegex(target, input, lastIndex);
|
|
163
|
-
return toMatchArray(match, input);
|
|
163
|
+
return toMatchArray(match, input, budget);
|
|
164
164
|
}
|
|
165
165
|
finally {
|
|
166
166
|
budget.setRetainedValues(retained, undefined);
|
|
@@ -218,16 +218,27 @@ export async function regexToString(target, budget, context) {
|
|
|
218
218
|
export function executeRegex(target, input, lastIndex) {
|
|
219
219
|
const pattern = getSandboxRegexPattern(target);
|
|
220
220
|
const match = matchRegex(pattern, input, lastIndex);
|
|
221
|
-
if (pattern.flags.global) {
|
|
221
|
+
if (pattern.flags.global || pattern.flags.sticky) {
|
|
222
222
|
target.lastIndex = match === null ? 0 : match.index + match.text.length;
|
|
223
223
|
}
|
|
224
224
|
return match;
|
|
225
225
|
}
|
|
226
|
-
export function toMatchArray(match, input) {
|
|
226
|
+
export function toMatchArray(match, input, budget) {
|
|
227
227
|
if (match === null) {
|
|
228
228
|
return null;
|
|
229
229
|
}
|
|
230
|
+
budget?.allocateArrayLength(match.captures.length + 1);
|
|
230
231
|
const result = [match.text, ...match.captures];
|
|
231
|
-
|
|
232
|
+
if (match.groups !== undefined)
|
|
233
|
+
setSandboxPrototype(match.groups, null, budget);
|
|
234
|
+
if (match.indicesGroups !== undefined)
|
|
235
|
+
setSandboxPrototype(match.indicesGroups, null, budget);
|
|
236
|
+
Object.assign(result, { index: match.index, input, groups: match.groups });
|
|
237
|
+
if (match.indices !== undefined) {
|
|
238
|
+
budget?.allocateArrayLength(match.indices.length);
|
|
239
|
+
budget?.allocateArrayLength(2);
|
|
240
|
+
Object.assign(match.indices, { groups: match.indicesGroups });
|
|
241
|
+
Object.assign(result, { indices: match.indices });
|
|
242
|
+
}
|
|
232
243
|
return result;
|
|
233
244
|
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import type { Budget } from "../budget.js";
|
|
2
2
|
import { type SandboxRegExpIterator } from "../regexp-iterator.js";
|
|
3
|
-
import { type SandboxValue } from "../values.js";
|
|
3
|
+
import { type SandboxCallContext, type SandboxValue } from "../values.js";
|
|
4
4
|
export declare function nextRegExpIterator(iterator: SandboxRegExpIterator, budget?: Budget): {
|
|
5
5
|
value: SandboxValue;
|
|
6
6
|
done: boolean;
|
|
7
7
|
};
|
|
8
|
+
export declare function nextObservableRegExpIterator(iterator: SandboxRegExpIterator, budget: Budget, context: SandboxCallContext): Promise<{
|
|
9
|
+
value: SandboxValue;
|
|
10
|
+
done: boolean;
|
|
11
|
+
}>;
|
|
8
12
|
export declare function getRegExpIteratorMember(property: PropertyKey, budget: Budget): SandboxValue;
|