poe-code 13.0.3 → 13.0.5

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 (57) hide show
  1. package/dist/index.js +14421 -13628
  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-73LWNNUG.js → chunk-BI5UBZ7A.js} +14508 -13744
  6. package/packages/safe-js/dist/chunks/chunk-BI5UBZ7A.js.map +7 -0
  7. package/packages/safe-js/dist/chunks/{chunk-QCJ7UAMC.js → chunk-FH5X7CUS.js} +2 -2
  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/index.d.ts +11 -3
  11. package/packages/safe-js/dist/index.js +14 -6
  12. package/packages/safe-js/dist/index.js.map +4 -4
  13. package/packages/safe-js/dist/interp/async.d.ts +2 -0
  14. package/packages/safe-js/dist/interp/async.js +31 -15
  15. package/packages/safe-js/dist/interp/budget.d.ts +29 -0
  16. package/packages/safe-js/dist/interp/budget.js +143 -0
  17. package/packages/safe-js/dist/interp/globals/console-json.d.ts +2 -1
  18. package/packages/safe-js/dist/interp/globals/console-json.js +24 -6
  19. package/packages/safe-js/dist/interp/globals/regex.d.ts +2 -1
  20. package/packages/safe-js/dist/interp/globals/regex.js +24 -3
  21. package/packages/safe-js/dist/interp/host-bridge.d.ts +2 -1
  22. package/packages/safe-js/dist/interp/host-bridge.js +98 -55
  23. package/packages/safe-js/dist/interp/host-call.d.ts +3 -2
  24. package/packages/safe-js/dist/interp/host-call.js +91 -52
  25. package/packages/safe-js/dist/interp/interpreter.d.ts +4 -1
  26. package/packages/safe-js/dist/interp/interpreter.js +115 -79
  27. package/packages/safe-js/dist/interp/methods/string.d.ts +2 -1
  28. package/packages/safe-js/dist/interp/methods/string.js +111 -100
  29. package/packages/safe-js/dist/interp/regex/compile-guard.d.ts +33 -0
  30. package/packages/safe-js/dist/interp/regex/compile-guard.js +179 -0
  31. package/packages/safe-js/dist/interp/regex/parse.d.ts +2 -1
  32. package/packages/safe-js/dist/interp/regex/parse.js +87 -16
  33. package/packages/safe-js/dist/interp/values.d.ts +7 -2
  34. package/packages/safe-js/dist/interp/values.js +95 -9
  35. package/packages/safe-js/dist/modules/registry.d.ts +2 -1
  36. package/packages/safe-js/dist/modules/registry.js +1 -0
  37. package/packages/safe-js/dist/parse/hash.d.ts +2 -1
  38. package/packages/safe-js/dist/parse/hash.js +7 -4
  39. package/packages/safe-js/dist/parse/parser.d.ts +5 -3
  40. package/packages/safe-js/dist/parse/parser.js +53 -27
  41. package/packages/safe-js/dist/parse/tokenizer.d.ts +2 -0
  42. package/packages/safe-js/dist/parse/tokenizer.js +48 -26
  43. package/packages/safe-js/dist/parse.d.ts +3 -1
  44. package/packages/safe-js/dist/parse.js +3 -1
  45. package/packages/safe-js/dist/restore.d.ts +2 -1
  46. package/packages/safe-js/dist/restore.js +3 -3
  47. package/packages/safe-js/dist/run.js +289 -263
  48. package/packages/safe-js/dist/snapshot/migration.d.ts +3 -2
  49. package/packages/safe-js/dist/snapshot/migration.js +12 -5
  50. package/packages/safe-js/dist/snapshot/replay-data.d.ts +2 -1
  51. package/packages/safe-js/dist/snapshot/replay-data.js +172 -162
  52. package/packages/safe-js/dist/snapshot/replay-inputs.d.ts +2 -1
  53. package/packages/safe-js/dist/snapshot/replay-inputs.js +18 -11
  54. package/packages/safe-js/dist/snapshot/restore.d.ts +2 -2
  55. package/packages/safe-js/dist/snapshot/restore.js +142 -113
  56. package/packages/safe-js/dist/chunks/chunk-73LWNNUG.js.map +0 -7
  57. /package/packages/safe-js/dist/chunks/{chunk-QCJ7UAMC.js.map → chunk-FH5X7CUS.js.map} +0 -0
@@ -5,6 +5,8 @@ import { formatParseError } from "./format-error.js";
5
5
  import { createExportDefaultDeclaration, createExportNamedDeclaration } from "./parse-export.js";
6
6
  import { createImportMeta, isImportMetaTokenSequence } from "./parse-import-meta.js";
7
7
  import { parseRegex } from "../interp/regex/parse.js";
8
+ import { CompileScope, RegexCompileGuard } from "../interp/regex/compile-guard.js";
9
+ import { SandboxError } from "../interp/budget.js";
8
10
  const MAX_CONDITIONAL_EXPRESSION_DEPTH = 256;
9
11
  const MAX_IF_STATEMENT_DEPTH = 2_048;
10
12
  export class DisallowedSyntaxError extends Error {
@@ -37,9 +39,10 @@ const TOP_LEVEL_STATEMENT_KEYWORDS = new Set([
37
39
  "try",
38
40
  "while"
39
41
  ]);
40
- export function parse(source, filename = "<input>") {
42
+ export function parse(source, filename = "<input>", owner) {
43
+ const compilation = new CompileScope(owner);
41
44
  try {
42
- const result = assignIds(parseTokens(tokenize(source, { allowRegexLiterals: true })));
45
+ const result = assignIds(parseTokens(tokenize(source, { allowRegexLiterals: true, compilation }), compilation));
43
46
  const regexLiteral = findRegexLiteral(result);
44
47
  if (regexLiteral !== undefined) {
45
48
  throw new Error(`Regular expression literals are not supported at line ${regexLiteral.span.start.line}, column ${regexLiteral.span.start.column}.`);
@@ -48,7 +51,7 @@ export function parse(source, filename = "<input>") {
48
51
  return result;
49
52
  }
50
53
  catch (error) {
51
- if (error instanceof DisallowedSyntaxError) {
54
+ if (error instanceof DisallowedSyntaxError || error instanceof SandboxError) {
52
55
  throw error;
53
56
  }
54
57
  if (error instanceof Error) {
@@ -56,13 +59,17 @@ export function parse(source, filename = "<input>") {
56
59
  }
57
60
  throw error;
58
61
  }
62
+ finally {
63
+ compilation.dispose();
64
+ }
59
65
  }
60
- export function parseModule(source, filename = "<input>") {
66
+ export function parseModule(source, filename = "<input>", owner) {
67
+ const compilation = new CompileScope(owner);
61
68
  try {
62
- return assignIds(parseModuleTokens(tokenize(source, { allowRegexLiterals: true })));
69
+ return assignIds(parseModuleTokens(tokenize(source, { allowRegexLiterals: true, compilation }), compilation));
63
70
  }
64
71
  catch (error) {
65
- if (error instanceof DisallowedSyntaxError) {
72
+ if (error instanceof DisallowedSyntaxError || error instanceof SandboxError) {
66
73
  throw error;
67
74
  }
68
75
  if (error instanceof Error) {
@@ -70,15 +77,19 @@ export function parseModule(source, filename = "<input>") {
70
77
  }
71
78
  throw error;
72
79
  }
80
+ finally {
81
+ compilation.dispose();
82
+ }
73
83
  }
74
- export function parseExecutableModule(source, filename = "<input>") {
84
+ export function parseExecutableModule(source, filename = "<input>", owner) {
85
+ const compilation = new CompileScope(owner);
75
86
  try {
76
- const result = assignIds(parseModuleTokens(tokenize(source, { allowRegexLiterals: true })));
87
+ const result = assignIds(parseModuleTokens(tokenize(source, { allowRegexLiterals: true, compilation }), compilation));
77
88
  throwIfImportMetaAssignment(result);
78
89
  return result;
79
90
  }
80
91
  catch (error) {
81
- if (error instanceof DisallowedSyntaxError) {
92
+ if (error instanceof DisallowedSyntaxError || error instanceof SandboxError) {
82
93
  throw error;
83
94
  }
84
95
  if (error instanceof Error) {
@@ -86,18 +97,22 @@ export function parseExecutableModule(source, filename = "<input>") {
86
97
  }
87
98
  throw error;
88
99
  }
100
+ finally {
101
+ compilation.dispose();
102
+ }
89
103
  }
90
- function parseTokens(tokens) {
91
- return new Parser(tokens).parseTopLevel();
104
+ function parseTokens(tokens, compilation) {
105
+ return new Parser(tokens, compilation).parseTopLevel();
92
106
  }
93
- function parseModuleTokens(tokens) {
94
- return new Parser(tokens).parseModule();
107
+ function parseModuleTokens(tokens, compilation) {
108
+ return new Parser(tokens, compilation).parseModule();
95
109
  }
96
- function parseExpressionTokens(tokens) {
97
- return new Parser(tokens).parseExpressionOnly();
110
+ function parseExpressionTokens(tokens, compilation) {
111
+ return new Parser(tokens, compilation).parseExpressionOnly();
98
112
  }
99
113
  class Parser {
100
114
  tokens;
115
+ compilation;
101
116
  index = 0;
102
117
  breakableDepth = 0;
103
118
  conditionalExpressionDepth = 0;
@@ -107,8 +122,9 @@ class Parser {
107
122
  scopes = [new Map()];
108
123
  functionScopes = new WeakSet();
109
124
  varNames = new WeakMap();
110
- constructor(tokens) {
125
+ constructor(tokens, compilation) {
111
126
  this.tokens = tokens;
127
+ this.compilation = compilation;
112
128
  this.functionScopes.add(this.scopes[0]);
113
129
  }
114
130
  parseTopLevel() {
@@ -1646,7 +1662,7 @@ class Parser {
1646
1662
  continue;
1647
1663
  }
1648
1664
  if (this.currentToken().type === "template") {
1649
- const quasi = createTemplateLiteral(this.currentToken(), { allowMalformedEscapes: true });
1665
+ const quasi = createTemplateLiteral(this.currentToken(), { allowMalformedEscapes: true }, this.compilation);
1650
1666
  this.index += 1;
1651
1667
  expression = {
1652
1668
  node: {
@@ -1727,14 +1743,14 @@ class Parser {
1727
1743
  if (token.type === "regex") {
1728
1744
  this.index += 1;
1729
1745
  return {
1730
- node: createRegexLiteral(token),
1746
+ node: createRegexLiteral(token, this.compilation),
1731
1747
  parenthesized: false
1732
1748
  };
1733
1749
  }
1734
1750
  if (token.type === "template") {
1735
1751
  this.index += 1;
1736
1752
  return {
1737
- node: createTemplateLiteral(token, { allowMalformedEscapes: false }),
1753
+ node: createTemplateLiteral(token, { allowMalformedEscapes: false }, this.compilation),
1738
1754
  parenthesized: false
1739
1755
  };
1740
1756
  }
@@ -2918,10 +2934,16 @@ function createStringLiteral(token) {
2918
2934
  span: createTokenSpan(token)
2919
2935
  };
2920
2936
  }
2921
- function createRegexLiteral(token) {
2937
+ function createRegexLiteral(token, parent) {
2938
+ const compilation = new CompileScope(parent?.owner);
2939
+ const guard = new RegexCompileGuard(compilation);
2922
2940
  const lastSlash = token.value.lastIndexOf("/");
2923
2941
  try {
2924
- parseRegex(token.value.slice(1, lastSlash), token.value.slice(lastSlash + 1));
2942
+ guard.checkLength(Math.max(0, lastSlash - 1));
2943
+ guard.checkLength(token.value.length - lastSlash - 1, true);
2944
+ guard.allocate(Math.max(0, token.value.length - 2));
2945
+ guard.work(Math.max(0, token.value.length - 2));
2946
+ parseRegex(token.value.slice(1, lastSlash), token.value.slice(lastSlash + 1), compilation);
2925
2947
  }
2926
2948
  catch (error) {
2927
2949
  if (error instanceof SyntaxError) {
@@ -2933,6 +2955,10 @@ function createRegexLiteral(token) {
2933
2955
  }
2934
2956
  throw error;
2935
2957
  }
2958
+ finally {
2959
+ guard.close();
2960
+ compilation.dispose();
2961
+ }
2936
2962
  return {
2937
2963
  type: "RegexLiteral",
2938
2964
  raw: token.value,
@@ -2983,7 +3009,7 @@ function createLiteralFromToken(token) {
2983
3009
  }
2984
3010
  return createKeywordLiteral(token);
2985
3011
  }
2986
- function createTemplateLiteral(token, options = { allowMalformedEscapes: false }) {
3012
+ function createTemplateLiteral(token, options = { allowMalformedEscapes: false }, compilation) {
2987
3013
  const raw = token.value;
2988
3014
  const expressions = [];
2989
3015
  const quasis = [];
@@ -2999,7 +3025,7 @@ function createTemplateLiteral(token, options = { allowMalformedEscapes: false }
2999
3025
  quasis.push(createTemplateElement(token.start, raw, quasiStart, cursor, false, options));
3000
3026
  const expressionStart = cursor + 2;
3001
3027
  const expressionEnd = findTemplateExpressionEnd(raw, expressionStart);
3002
- expressions.push(parseEmbeddedExpression(raw.slice(expressionStart, expressionEnd), positionWithinRaw(token.start, raw, expressionStart)));
3028
+ expressions.push(parseEmbeddedExpression(raw.slice(expressionStart, expressionEnd), positionWithinRaw(token.start, raw, expressionStart), compilation));
3003
3029
  quasiStart = expressionEnd + 1;
3004
3030
  cursor = expressionEnd + 1;
3005
3031
  continue;
@@ -3360,15 +3386,15 @@ function decodeHexEscape(value, start) {
3360
3386
  end: index + 2
3361
3387
  };
3362
3388
  }
3363
- function parseEmbeddedExpression(source, base) {
3364
- const tokens = tokenize(source, { allowRegexLiterals: true }).map((token) => ({
3389
+ function parseEmbeddedExpression(source, base, compilation) {
3390
+ const tokens = tokenize(source, { allowRegexLiterals: true, compilation }).map((token) => ({
3365
3391
  ...token,
3366
3392
  start: rebasePosition(token.start, base),
3367
3393
  end: rebasePosition(token.end, base)
3368
3394
  }));
3369
- return parseExpressionTokens(tokens);
3395
+ return parseExpressionTokens(tokens, compilation);
3370
3396
  }
3371
- function findRegexLiteral(node) {
3397
+ export function findRegexLiteral(node) {
3372
3398
  if (node === null || node === undefined) {
3373
3399
  return undefined;
3374
3400
  }
@@ -1,3 +1,4 @@
1
+ import { type CompileScope } from "../interp/regex/compile-guard.js";
1
2
  export type Position = {
2
3
  line: number;
3
4
  column: number;
@@ -19,6 +20,7 @@ export type Comment = {
19
20
  export type TokenizeOptions = {
20
21
  allowRegexLiterals?: boolean;
21
22
  comments?: Comment[];
23
+ compilation?: CompileScope;
22
24
  };
23
25
  export declare function tokenize(source: string, options?: TokenizeOptions): Token[];
24
26
  export declare function collectComments(source: string): Comment[];
@@ -1,3 +1,4 @@
1
+ import { RegexCompileGuard } from "../interp/regex/compile-guard.js";
1
2
  const KEYWORDS = new Set([
2
3
  "const",
3
4
  "let",
@@ -646,37 +647,58 @@ class Lexer {
646
647
  return undefined;
647
648
  }
648
649
  scanRegexLiteral(start) {
649
- this.advance();
650
- let inCharacterClass = false;
651
- while (!this.isAtEnd()) {
652
- const char = this.currentChar();
653
- if (char === "\\") {
654
- this.advance();
655
- if (!this.isAtEnd()) {
656
- this.advance();
650
+ const guard = new RegexCompileGuard(this.options.compilation);
651
+ try {
652
+ guard.work(1);
653
+ this.advance();
654
+ const patternStart = this.index;
655
+ let inCharacterClass = false;
656
+ const advancePattern = () => {
657
+ const width = this.currentChar() === "\r" && this.peekChar(1) === "\n" ? 2 : 1;
658
+ guard.checkLength(this.index - patternStart + width);
659
+ guard.work(width);
660
+ this.advance();
661
+ };
662
+ while (!this.isAtEnd()) {
663
+ const char = this.currentChar();
664
+ if (char === "\\") {
665
+ advancePattern();
666
+ if (!this.isAtEnd())
667
+ advancePattern();
668
+ continue;
657
669
  }
658
- continue;
659
- }
660
- if (char === "[" && !inCharacterClass) {
661
- inCharacterClass = true;
662
- this.advance();
663
- continue;
664
- }
665
- if (char === "]" && inCharacterClass) {
666
- inCharacterClass = false;
667
- this.advance();
668
- continue;
669
- }
670
- if (char === "/" && !inCharacterClass) {
671
- this.advance();
672
- while (!this.isAtEnd() && isAsciiLetter(this.currentChar())) {
670
+ if (char === "[" && !inCharacterClass) {
671
+ inCharacterClass = true;
672
+ advancePattern();
673
+ continue;
674
+ }
675
+ if (char === "]" && inCharacterClass) {
676
+ inCharacterClass = false;
677
+ advancePattern();
678
+ continue;
679
+ }
680
+ if (char === "/" && !inCharacterClass) {
681
+ guard.work(1);
673
682
  this.advance();
683
+ const flagsStart = this.index;
684
+ while (!this.isAtEnd() && isAsciiLetter(this.currentChar())) {
685
+ guard.checkLength(this.index - flagsStart + 1, true);
686
+ guard.work(1);
687
+ this.advance();
688
+ }
689
+ break;
674
690
  }
675
- break;
691
+ advancePattern();
676
692
  }
677
- this.advance();
693
+ guard.allocate(this.index - start.offset);
694
+ guard.work(this.index - start.offset);
695
+ const raw = this.source.slice(start.offset, this.index);
696
+ guard.retainScratch();
697
+ return raw;
698
+ }
699
+ finally {
700
+ guard.close();
678
701
  }
679
- return this.source.slice(start.offset, this.index);
680
702
  }
681
703
  pushToken(type, start, value) {
682
704
  const previousToken = this.lastSignificantToken();
@@ -1,2 +1,4 @@
1
- export { DisallowedSyntaxError, parse } from "./parse/parser.js";
1
+ import { type ParseResult as ParsedNode } from "./parse/parser.js";
2
+ export { DisallowedSyntaxError } from "./parse/parser.js";
3
+ export declare const parse: (source: string, filename?: string) => ParsedNode;
2
4
  export type { ArrayPattern, ArrayExpression, ArrowFunctionExpression, AssignmentExpression, AssignmentPattern, AssignmentProperty, AwaitExpression, BinaryExpression, BlockStatement, BooleanLiteral, BreakStatement, CallExpression, CatchClause, ConditionalExpression, ContinueStatement, DoWhileStatement, EmptyStatement, Expression, ExpressionStatement, ExportDefaultDeclaration, ExportNamedDeclaration, ImportDeclaration, ImportDefaultSpecifier, ImportNamespaceSpecifier, ImportSpecifier, ForInStatement, ForOfStatement, ForStatement, FunctionDeclaration, FunctionExpression, Identifier, IfStatement, LogicalExpression, MemberExpression, MetaProperty, NewExpression, NullLiteral, NumericLiteral, ObjectExpression, ObjectPattern, ParseResult, PatternTarget, Property, RegexLiteral, RestElement, ReturnStatement, SequenceExpression, SourceSpan, SpreadElement, Statement, StringLiteral, SwitchCase, SwitchStatement, TaggedTemplateExpression, TemplateElement, TemplateLiteral, ThisExpression, ThrowStatement, TryStatement, UnaryExpression, UndefinedLiteral, UpdateExpression, UpdateTarget, VariableDeclaration, VariableDeclarationKind, VariableDeclarator, WhileStatement } from "./parse/parser.js";
@@ -1 +1,3 @@
1
- export { DisallowedSyntaxError, parse } from "./parse/parser.js";
1
+ import { parse as parseInternal } from "./parse/parser.js";
2
+ export { DisallowedSyntaxError } from "./parse/parser.js";
3
+ export const parse = parseInternal;
@@ -1,3 +1,4 @@
1
+ import type { CompileOwner } from "./interp/budget.js";
1
2
  import { type SnapshotMigration } from "./snapshot/migration.js";
2
3
  export type SafeJSSnapshot = {
3
4
  version?: number;
@@ -22,4 +23,4 @@ export declare class SnapshotMismatchError extends Error {
22
23
  readonly expectedHash: string;
23
24
  constructor(expectedHash: string, actualHash: string);
24
25
  }
25
- export declare function restore<TSnapshot extends SafeJSSnapshot>(snapshot: TSnapshot, options: RestoreOptions): TSnapshot;
26
+ export declare function restore<TSnapshot extends SafeJSSnapshot>(snapshot: TSnapshot, options: RestoreOptions, owner?: CompileOwner): TSnapshot;
@@ -15,10 +15,10 @@ export class SnapshotMismatchError extends Error {
15
15
  replaceErrorStack(this);
16
16
  }
17
17
  }
18
- export function restore(snapshot, options) {
18
+ export function restore(snapshot, options, owner) {
19
19
  assertSnapshotInactive(snapshot);
20
20
  validateDumpEnvelope(snapshot);
21
- validateSnapshotMigration(snapshot.migration, snapshot.sourceHash);
21
+ validateSnapshotMigration(snapshot.migration, snapshot.sourceHash, owner);
22
22
  if (snapshot.executionSemantics !== EXECUTION_SEMANTICS &&
23
23
  snapshot.executionSemantics !== "jobs-v6" &&
24
24
  (snapshot.executionSemantics !== undefined ||
@@ -27,7 +27,7 @@ export function restore(snapshot, options) {
27
27
  snapshot.initialInputs !== undefined)) {
28
28
  throw new SnapshotValidationError("unsupportedVersion", "$.executionSemantics", "incompatible execution semantics; resume with the SafeJS version that created this snapshot. Migration requires explicit reconciliation, not changing its version marker.");
29
29
  }
30
- const currentSourceHash = hashSource(options.source);
30
+ const currentSourceHash = hashSource(options.source, owner);
31
31
  if (snapshot.sourceHash !== currentSourceHash) {
32
32
  throw new SnapshotMismatchError(snapshot.sourceHash, currentSourceHash);
33
33
  }