poe-code 14.0.73 → 14.0.75

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.
Files changed (47) hide show
  1. package/dist/index.js +2732 -1188
  2. package/dist/index.js.map +4 -4
  3. package/dist/metafile.json +1 -1
  4. package/package.json +1 -1
  5. package/packages/safe-js/dist/chunks/{chunk-I2Z37MKZ.js → chunk-BAJI3K4B.js} +2 -2
  6. package/packages/safe-js/dist/chunks/{chunk-XKCTB5FR.js → chunk-EOTY4PCT.js} +2902 -1425
  7. package/packages/safe-js/dist/chunks/chunk-EOTY4PCT.js.map +7 -0
  8. package/packages/safe-js/dist/cli.js +2 -2
  9. package/packages/safe-js/dist/core.js +1 -1
  10. package/packages/safe-js/dist/graph-depth.js +3 -0
  11. package/packages/safe-js/dist/index.js +2 -2
  12. package/packages/safe-js/dist/interp/cancel.js +3 -0
  13. package/packages/safe-js/dist/interp/globals/misc.js +2 -1
  14. package/packages/safe-js/dist/interp/globals/object.js +3 -0
  15. package/packages/safe-js/dist/interp/globals/regex.js +196 -9
  16. package/packages/safe-js/dist/interp/interpreter.js +14 -7
  17. package/packages/safe-js/dist/interp/iteration.js +9 -1
  18. package/packages/safe-js/dist/interp/methods/regex-split.d.ts +3 -0
  19. package/packages/safe-js/dist/interp/methods/regex-split.js +102 -0
  20. package/packages/safe-js/dist/interp/methods/regex.d.ts +8 -4
  21. package/packages/safe-js/dist/interp/methods/regex.js +141 -24
  22. package/packages/safe-js/dist/interp/methods/regexp-iterator.d.ts +12 -0
  23. package/packages/safe-js/dist/interp/methods/regexp-iterator.js +101 -0
  24. package/packages/safe-js/dist/interp/methods/string.d.ts +2 -0
  25. package/packages/safe-js/dist/interp/methods/string.js +415 -121
  26. package/packages/safe-js/dist/interp/object-model.d.ts +3 -0
  27. package/packages/safe-js/dist/interp/object-model.js +43 -10
  28. package/packages/safe-js/dist/interp/regex/compile-guard.js +26 -4
  29. package/packages/safe-js/dist/interp/regex/engine.d.ts +4 -0
  30. package/packages/safe-js/dist/interp/regex/engine.js +230 -30
  31. package/packages/safe-js/dist/interp/regex/parse.d.ts +42 -4
  32. package/packages/safe-js/dist/interp/regex/parse.js +429 -25
  33. package/packages/safe-js/dist/interp/regexp-iterator.d.ts +16 -0
  34. package/packages/safe-js/dist/interp/regexp-iterator.js +23 -0
  35. package/packages/safe-js/dist/interp/string-coercion.js +11 -7
  36. package/packages/safe-js/dist/interp/values.d.ts +2 -1
  37. package/packages/safe-js/dist/interp/values.js +39 -2
  38. package/packages/safe-js/dist/snapshot/dump-format.js +35 -3
  39. package/packages/safe-js/dist/snapshot/replay-data.d.ts +12 -1
  40. package/packages/safe-js/dist/snapshot/replay-data.js +42 -1
  41. package/packages/safe-js/dist/snapshot/replay-inputs.js +17 -0
  42. package/packages/safe-js/dist/snapshot/restore.js +23 -1
  43. package/packages/safe-js/dist/snapshot/serialize.d.ts +13 -2
  44. package/packages/safe-js/dist/snapshot/serialize.js +30 -11
  45. package/packages/safe-js/dist/snapshot/validation.js +22 -2
  46. package/packages/safe-js/dist/chunks/chunk-XKCTB5FR.js.map +0 -7
  47. /package/packages/safe-js/dist/chunks/{chunk-I2Z37MKZ.js.map → chunk-BAJI3K4B.js.map} +0 -0
@@ -1,22 +1,84 @@
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 { getSandboxDataProperty } from "../object-model.js";
4
+ import { getSandboxPropertyDescriptor, getSandboxPrototype, hasExplicitSandboxPrototype, setSandboxPrototype } from "../object-model.js";
5
+ import { readPropertyDescriptor } from "../accessors.js";
6
+ import { retainValues } from "../resources.js";
5
7
  import { sandboxNumber, sandboxString } from "../string-coercion.js";
6
- const regexMethodNames = new Set(["exec", "test"]);
7
- const regexFlagProperties = {
8
+ import { setSandboxProperty } from "../interpreter.js";
9
+ export async function regexSearch(target, input, budget, context) {
10
+ if (target === null || typeof target !== "object")
11
+ throw new TypeError("RegExp search requires an object receiver.");
12
+ let string;
13
+ let previous;
14
+ let result;
15
+ const release = retainValues(budget, () => [target, input, string, previous, result]);
16
+ const read = (value, key) => {
17
+ if (context?.getProperty !== undefined)
18
+ return context.getProperty(value, key);
19
+ const descriptor = getSandboxPropertyDescriptor(value, key, budget);
20
+ return descriptor === undefined ? undefined : readPropertyDescriptor(descriptor, value, context);
21
+ };
22
+ try {
23
+ string = await sandboxString(input, budget, context);
24
+ input = undefined;
25
+ previous = await read(target, "lastIndex");
26
+ if (!Object.is(previous, 0))
27
+ await setSandboxProperty(target, "lastIndex", 0, budget, true, context);
28
+ result = await regexExec(target, string, budget, context);
29
+ if (!Object.is(await read(target, "lastIndex"), previous))
30
+ await setSandboxProperty(target, "lastIndex", previous, budget, true, context);
31
+ return result === null ? -1 : await read(result, "index");
32
+ }
33
+ finally {
34
+ release();
35
+ }
36
+ }
37
+ const regexMethodNames = new Set(["exec", "test", "toString"]);
38
+ export const regexFlagProperties = {
8
39
  hasIndices: "d", global: "g", ignoreCase: "i", multiline: "m",
9
40
  dotAll: "s", unicode: "u", unicodeSets: "v", sticky: "y"
10
41
  };
11
42
  export function isRegexMethodName(property) {
12
43
  return typeof property === "string" && regexMethodNames.has(property);
13
44
  }
14
- export function getRegexMember(target, property, budget) {
45
+ export function getRegexMember(target, property, budget, context) {
15
46
  if (property === "source")
16
47
  return escapeRegexSource(target.source, budget);
17
48
  if (property === "flags") {
18
- const flags = [..."gims"].filter((flag) => target.flags.includes(flag)).join("");
19
- return budget === undefined ? flags : budget.allocateString(flags);
49
+ let flags = "";
50
+ const entries = Object.entries(regexFlagProperties);
51
+ const release = retainValues(budget, () => [target, flags]);
52
+ const read = (index) => {
53
+ if (index === entries.length)
54
+ return budget.allocateString(flags);
55
+ budget.visitNode();
56
+ const [key, flag] = entries[index];
57
+ const descriptor = context?.getProperty === undefined
58
+ ? getSandboxPropertyDescriptor(target, key, budget) : undefined;
59
+ const value = context?.getProperty !== undefined
60
+ ? context.getProperty(target, key)
61
+ : descriptor !== undefined
62
+ ? readPropertyDescriptor(descriptor, target, context)
63
+ : target.flags.includes(flag);
64
+ const append = (value) => {
65
+ if (value)
66
+ flags += flag;
67
+ return read(index + 1);
68
+ };
69
+ return value instanceof Promise ? value.then(append) : append(value);
70
+ };
71
+ try {
72
+ const result = read(0);
73
+ if (result instanceof Promise)
74
+ return result.finally(release);
75
+ release();
76
+ return result;
77
+ }
78
+ catch (error) {
79
+ release();
80
+ throw error;
81
+ }
20
82
  }
21
83
  if (property === "lastIndex")
22
84
  return target.lastIndex;
@@ -27,7 +89,7 @@ export function getRegexMember(target, property, budget) {
27
89
  }
28
90
  return createSandboxClosure({
29
91
  sandbox: true,
30
- name: `RegExp#${property}`,
92
+ name: property === "toString" ? "toString" : `RegExp#${property}`,
31
93
  call: (args, context) => callRegexMethod(context?.thisValue, property, args, budget, context)
32
94
  });
33
95
  }
@@ -66,9 +128,9 @@ function escapeRegexSource(source, budget) {
66
128
  text = text === "" ? "(?:)" : text;
67
129
  return budget === undefined ? text : budget.allocateString(text);
68
130
  }
69
- export function setRegexMember(target, property, value) {
131
+ export function setRegexMember(target, property, value, budget) {
70
132
  const properties = getRegexProperties(target);
71
- if (!Object.hasOwn(properties, property) &&
133
+ if (!hasExplicitSandboxPrototype(target) && getSandboxPrototype(target, budget) === null && !Object.hasOwn(properties, property) &&
72
134
  (property === "source" || property === "flags" || Object.hasOwn(regexFlagProperties, property))) {
73
135
  throw new TypeError(`RegExp#${String(property)} is not writable.`);
74
136
  }
@@ -76,6 +138,8 @@ export function setRegexMember(target, property, value) {
76
138
  throw new TypeError(`RegExp#${String(property)} is not writable.`);
77
139
  }
78
140
  export async function callRegexMethod(target, methodName, args, budget, context) {
141
+ if (methodName === "toString")
142
+ return regexToString(target, budget, context);
79
143
  if (target === null || typeof target !== "object" || (methodName === "exec" && !isSandboxRegex(target))) {
80
144
  throw new TypeError(`RegExp#${methodName} requires ${methodName === "exec" ? "a regex" : "an object"} receiver.`);
81
145
  }
@@ -86,42 +150,95 @@ export async function callRegexMethod(target, methodName, args, budget, context)
86
150
  try {
87
151
  const input = await sandboxString(args[0], budget, context);
88
152
  if (methodName === "test") {
89
- const exec = context?.getProperty === undefined
90
- ? getSandboxDataProperty(target, "exec", budget) : await context.getProperty(target, "exec");
91
- if (isSandboxClosure(exec)) {
92
- const result = await invokeBuiltinClosure(exec, [input], budget, context, target);
93
- if (result !== null && typeof result !== "object") {
94
- throw new TypeError("RegExp#test exec must return an object or null.");
95
- }
96
- return result !== null;
97
- }
153
+ budget.setRetainedValues(retained, undefined);
154
+ return await regexExec(target, input, budget, context) !== null;
98
155
  }
99
- if (!isSandboxRegex(target))
100
- throw new TypeError("RegExp execution requires a regex receiver.");
101
156
  if (typeof args[0] !== "string")
102
157
  convertedInput = input;
158
+ if (!isSandboxRegex(target))
159
+ throw new TypeError("RegExp execution requires a regex receiver.");
103
160
  cursor = target.lastIndex;
104
161
  const lastIndex = await sandboxNumber(cursor, budget, context);
105
162
  const match = executeRegex(target, input, lastIndex);
106
- return methodName === "test" ? match !== null : toMatchArray(match, input);
163
+ return toMatchArray(match, input, budget);
107
164
  }
108
165
  finally {
109
166
  budget.setRetainedValues(retained, undefined);
110
167
  }
111
168
  }
169
+ export async function regexExec(target, input, budget, context) {
170
+ let exec;
171
+ const release = retainValues(budget, () => [target, input, exec]);
172
+ try {
173
+ const descriptor = context?.getProperty === undefined
174
+ ? getSandboxPropertyDescriptor(target, "exec", budget) : undefined;
175
+ exec = await (context?.getProperty !== undefined ? context.getProperty(target, "exec")
176
+ : descriptor === undefined ? undefined : readPropertyDescriptor(descriptor, target, context));
177
+ if (isSandboxClosure(exec)) {
178
+ const result = await invokeBuiltinClosure(exec, [input], budget, context, target);
179
+ if (result !== null && typeof result !== "object")
180
+ throw new TypeError("RegExp exec must return an object or null.");
181
+ return result;
182
+ }
183
+ return await callRegexMethod(target, "exec", [input], budget, context);
184
+ }
185
+ finally {
186
+ release();
187
+ }
188
+ }
189
+ export async function regexToString(target, budget, context) {
190
+ if (target === null || typeof target !== "object")
191
+ throw new TypeError("RegExp#toString requires an object receiver.");
192
+ const read = (key) => {
193
+ if (context?.getProperty !== undefined)
194
+ return context.getProperty(target, key);
195
+ const descriptor = getSandboxPropertyDescriptor(target, key, budget);
196
+ if (descriptor !== undefined)
197
+ return readPropertyDescriptor(descriptor, target, context);
198
+ return isSandboxRegex(target) ? getRegexMember(target, key, budget, context) : undefined;
199
+ };
200
+ let sourceValue;
201
+ let flagsValue;
202
+ let source;
203
+ let flags;
204
+ const release = retainValues(budget, () => [target, sourceValue, flagsValue, source, flags]);
205
+ try {
206
+ sourceValue = await read("source");
207
+ source = await sandboxString(sourceValue, budget, context);
208
+ sourceValue = undefined;
209
+ flagsValue = await read("flags");
210
+ flags = await sandboxString(flagsValue, budget, context);
211
+ flagsValue = undefined;
212
+ return budget.allocateString(`/${source}/${flags}`);
213
+ }
214
+ finally {
215
+ release();
216
+ }
217
+ }
112
218
  export function executeRegex(target, input, lastIndex) {
113
219
  const pattern = getSandboxRegexPattern(target);
114
220
  const match = matchRegex(pattern, input, lastIndex);
115
- if (pattern.flags.global) {
221
+ if (pattern.flags.global || pattern.flags.sticky) {
116
222
  target.lastIndex = match === null ? 0 : match.index + match.text.length;
117
223
  }
118
224
  return match;
119
225
  }
120
- export function toMatchArray(match, input) {
226
+ export function toMatchArray(match, input, budget) {
121
227
  if (match === null) {
122
228
  return null;
123
229
  }
230
+ budget?.allocateArrayLength(match.captures.length + 1);
124
231
  const result = [match.text, ...match.captures];
125
- Object.assign(result, { index: match.index, input, groups: undefined });
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
+ }
126
243
  return result;
127
244
  }
@@ -0,0 +1,12 @@
1
+ import type { Budget } from "../budget.js";
2
+ import { type SandboxRegExpIterator } from "../regexp-iterator.js";
3
+ import { type SandboxCallContext, type SandboxValue } from "../values.js";
4
+ export declare function nextRegExpIterator(iterator: SandboxRegExpIterator, budget?: Budget): {
5
+ value: SandboxValue;
6
+ done: boolean;
7
+ };
8
+ export declare function nextObservableRegExpIterator(iterator: SandboxRegExpIterator, budget: Budget, context: SandboxCallContext): Promise<{
9
+ value: SandboxValue;
10
+ done: boolean;
11
+ }>;
12
+ export declare function getRegExpIteratorMember(property: PropertyKey, budget: Budget): SandboxValue;
@@ -0,0 +1,101 @@
1
+ import { isSandboxRegExpIterator, regexpIteratorState } from "../regexp-iterator.js";
2
+ import { createSandboxClosure, isSandboxRegex } from "../values.js";
3
+ import { executeRegex, regexExec, toMatchArray } from "./regex.js";
4
+ import { getSandboxPropertyDescriptor, hasRegexPropertyOverride } from "../object-model.js";
5
+ import { readPropertyDescriptor } from "../accessors.js";
6
+ import { setSandboxProperty } from "../interpreter.js";
7
+ import { sandboxNumber, sandboxString } from "../string-coercion.js";
8
+ import { normalizeLastIndex } from "../regex/engine.js";
9
+ import { retainValues } from "../resources.js";
10
+ export function nextRegExpIterator(iterator, budget) {
11
+ const state = regexpIteratorState(iterator);
12
+ budget?.visitNode();
13
+ if (state.exhausted)
14
+ return { value: undefined, done: true };
15
+ const matcher = state.matcher;
16
+ if (!isSandboxRegex(matcher))
17
+ throw new TypeError("Custom RegExp iterator execution requires a sandbox context.");
18
+ const input = state.input;
19
+ const match = executeRegex(matcher, input, Number(matcher.lastIndex));
20
+ if (match === null || !(state.global ?? matcher.flags.includes("g"))) {
21
+ state.exhausted = true;
22
+ state.matcher = undefined;
23
+ state.input = undefined;
24
+ }
25
+ if (match === null)
26
+ return { value: undefined, done: true };
27
+ if (!state.exhausted && match.text.length === 0) {
28
+ const index = Number(matcher.lastIndex);
29
+ const unicode = state.unicode ?? (matcher.flags.includes("u") || matcher.flags.includes("v"));
30
+ const codePoint = input.codePointAt(index);
31
+ matcher.lastIndex = index + (unicode && codePoint !== undefined && codePoint > 0xffff ? 2 : 1);
32
+ }
33
+ return { value: toMatchArray(match, input, budget), done: false };
34
+ }
35
+ export async function nextObservableRegExpIterator(iterator, budget, context) {
36
+ const state = regexpIteratorState(iterator);
37
+ if (state.exhausted)
38
+ return { value: undefined, done: true };
39
+ const matcher = state.matcher;
40
+ if (isSandboxRegex(matcher) && !hasRegexPropertyOverride(matcher, ["exec"], budget) &&
41
+ (matcher.lastIndex === null || typeof matcher.lastIndex !== "object"))
42
+ return nextRegExpIterator(iterator, budget);
43
+ const input = state.input;
44
+ let result;
45
+ let field;
46
+ const release = retainValues(budget, () => [iterator, matcher, input, result, field]);
47
+ const read = (value, key) => {
48
+ if (context.getProperty !== undefined)
49
+ return context.getProperty(value, key);
50
+ const descriptor = getSandboxPropertyDescriptor(value, key, budget);
51
+ return descriptor === undefined ? undefined : readPropertyDescriptor(descriptor, value, context);
52
+ };
53
+ try {
54
+ budget.visitNode();
55
+ result = await regexExec(matcher, input, budget, context);
56
+ const global = state.global ?? (isSandboxRegex(matcher) && matcher.flags.includes("g"));
57
+ if (result === null || !global) {
58
+ state.exhausted = true;
59
+ state.matcher = undefined;
60
+ state.input = undefined;
61
+ return result === null ? { value: undefined, done: true } : { value: result, done: false };
62
+ }
63
+ field = await read(result, "0");
64
+ const text = await sandboxString(field, budget, context);
65
+ field = undefined;
66
+ if (text.length === 0) {
67
+ field = await read(matcher, "lastIndex");
68
+ const index = normalizeLastIndex(await sandboxNumber(field, budget, context));
69
+ field = undefined;
70
+ const unicode = state.unicode ?? (isSandboxRegex(matcher) && (matcher.flags.includes("u") || matcher.flags.includes("v")));
71
+ const point = input.codePointAt(index);
72
+ await setSandboxProperty(matcher, "lastIndex", index + (unicode && point !== undefined && point > 0xffff ? 2 : 1), budget, true, context);
73
+ }
74
+ return { value: result, done: false };
75
+ }
76
+ finally {
77
+ release();
78
+ }
79
+ }
80
+ export function getRegExpIteratorMember(property, budget) {
81
+ if (property === Symbol.toStringTag)
82
+ return "RegExp String Iterator";
83
+ if (property === Symbol.iterator)
84
+ return createSandboxClosure({
85
+ sandbox: true,
86
+ name: "[Symbol.iterator]",
87
+ call: (_args, context) => context?.thisValue
88
+ });
89
+ if (property !== "next")
90
+ return undefined;
91
+ return createSandboxClosure({
92
+ sandbox: true,
93
+ name: "next",
94
+ call: (_args, context) => {
95
+ const receiver = context?.thisValue;
96
+ if (!isSandboxRegExpIterator(receiver))
97
+ throw new TypeError("RegExp string iterator next requires a matching receiver.");
98
+ return context === undefined ? nextRegExpIterator(receiver, budget) : nextObservableRegExpIterator(receiver, budget, context);
99
+ }
100
+ });
101
+ }
@@ -9,4 +9,6 @@ export declare function getStringIndex(property: string | number): number | unde
9
9
  export declare function isStringMethodName(property: string | number): property is StringMethodName;
10
10
  export declare function validateStringMethodArguments(_methodName: StringMethodName, _args: readonly Expression[]): void;
11
11
  export declare function callStringMethod(value: SandboxValue, methodName: StringMethodName, args: readonly SandboxValue[], budget: Budget, callClosure?: (closure: SandboxClosure, args: readonly SandboxValue[]) => Promise<SandboxValue>, parent?: CompileScope, context?: SandboxCallContext): SandboxValue | Promise<SandboxValue>;
12
+ export declare function regexReplace(input: SandboxValue, regex: SandboxValue, replacementInput: SandboxValue, budget: Budget, callClosure: (closure: SandboxClosure, args: readonly SandboxValue[]) => Promise<SandboxValue>, context?: SandboxCallContext): Promise<string>;
13
+ export declare function regexMatch(input: SandboxValue, regex: SandboxValue, budget: Budget, context?: SandboxCallContext): Promise<SandboxValue>;
12
14
  export {};