@poe-platform/safe-js 0.1.721 → 0.1.722

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 (85) hide show
  1. package/README.md +36 -6
  2. package/dist/config-mutations/types.d.ts +3 -1
  3. package/dist/safe-js/chunks/{chunk-B4M6QVUV.js → chunk-3QQYJ4RQ.js} +3 -2
  4. package/dist/safe-js/chunks/chunk-3QQYJ4RQ.js.map +7 -0
  5. package/dist/safe-js/chunks/{chunk-BHYBD6SY.js → chunk-55RIIUGG.js} +23 -7
  6. package/dist/safe-js/chunks/chunk-55RIIUGG.js.map +7 -0
  7. package/dist/safe-js/chunks/{chunk-A4L72WXV.js → chunk-7SBQ7WTV.js} +10 -11
  8. package/dist/safe-js/chunks/chunk-7SBQ7WTV.js.map +7 -0
  9. package/dist/safe-js/chunks/{chunk-DNA7BMBY.js → chunk-BNIEPGDU.js} +8520 -7312
  10. package/dist/safe-js/chunks/{chunk-DNA7BMBY.js.map → chunk-BNIEPGDU.js.map} +4 -4
  11. package/dist/safe-js/chunks/{chunk-HYD4K4HN.js → chunk-D3GC5QPZ.js} +63 -1
  12. package/dist/safe-js/chunks/chunk-D3GC5QPZ.js.map +7 -0
  13. package/dist/safe-js/chunks/{chunk-Q7B6JIMI.js → chunk-EH5A2EQI.js} +404 -117
  14. package/dist/safe-js/chunks/chunk-EH5A2EQI.js.map +7 -0
  15. package/dist/safe-js/chunks/{chunk-4CX3HYRY.js → chunk-FA5CQO6V.js} +2 -2
  16. package/dist/safe-js/chunks/{chunk-LPBTSTDG.js → chunk-GCOLKRMY.js} +4 -4
  17. package/dist/safe-js/chunks/{chunk-GMPZBMPA.js → chunk-K3ZRBAG5.js} +3 -3
  18. package/dist/safe-js/chunks/{chunk-JNLY7IMV.js → chunk-QL2ALAE6.js} +4 -4
  19. package/dist/safe-js/chunks/{chunk-ILYJBA2D.js → chunk-RYVHEOHM.js} +1109 -100
  20. package/dist/safe-js/chunks/chunk-RYVHEOHM.js.map +7 -0
  21. package/dist/safe-js/chunks/{chunk-BEXRQET4.js → chunk-S2GFVXSI.js} +3 -3
  22. package/dist/safe-js/chunks/{chunk-Y4LNCDCP.js → chunk-WF7HYDJ4.js} +4 -5
  23. package/dist/safe-js/chunks/{chunk-Y4LNCDCP.js.map → chunk-WF7HYDJ4.js.map} +2 -2
  24. package/dist/safe-js/chunks/{chunk-IS7YUCOF.js → chunk-XHSOM5CG.js} +2 -2
  25. package/dist/safe-js/chunks/{cli-runtime-YK2WE33M.js → cli-runtime-6QPGM3TX.js} +14 -14
  26. package/dist/safe-js/chunks/{dump-ATWBOZWV.js → dump-TU6SYRFD.js} +4 -4
  27. package/dist/safe-js/chunks/{fs-D72Y52I5.js → fs-HTZT32MQ.js} +4 -4
  28. package/dist/safe-js/chunks/harness-RYAMI444.js +10 -0
  29. package/dist/safe-js/chunks/mcp-DO2IRFGQ.js +11 -0
  30. package/dist/safe-js/chunks/migration-file-K7UH5ZG6.js +12 -0
  31. package/dist/safe-js/chunks/restore-7LRP4BM3.js +13 -0
  32. package/dist/safe-js/chunks/run-6SETM7SV.js +17 -0
  33. package/dist/safe-js/chunks/runtime-modules-MCQS2SHQ.js +10 -0
  34. package/dist/safe-js/cli.js +2 -2
  35. package/dist/safe-js/core.js +7 -7
  36. package/dist/safe-js/index.js +14 -14
  37. package/dist/safe-js/interp/async.d.ts +4 -1
  38. package/dist/safe-js/interp/budget.d.ts +12 -6
  39. package/dist/safe-js/interp/collection-iterator.d.ts +1 -1
  40. package/dist/safe-js/interp/host-bridge.d.ts +1 -0
  41. package/dist/safe-js/interp/host-capabilities.d.ts +13 -4
  42. package/dist/safe-js/interp/interpreter.d.ts +5 -1
  43. package/dist/safe-js/interp/intl-numberformat.d.ts +2 -2
  44. package/dist/safe-js/interp/jobs.d.ts +8 -0
  45. package/dist/safe-js/interp/scope.d.ts +9 -2
  46. package/dist/safe-js/interp/typed-array.d.ts +2 -2
  47. package/dist/safe-js/interp/values.d.ts +1 -0
  48. package/dist/safe-js/modules/registry.d.ts +4 -1
  49. package/dist/safe-js/modules/source-graph.d.ts +19 -1
  50. package/dist/safe-js/parse/compact-spans.d.ts +18 -0
  51. package/dist/safe-js/parse/dynamic-source.d.ts +3 -1
  52. package/dist/safe-js/parse/function-source.d.ts +1 -1
  53. package/dist/safe-js/parse/parser.d.ts +8 -3
  54. package/dist/safe-js/parse/tokenizer.d.ts +4 -0
  55. package/dist/safe-js/realm.d.ts +16 -3
  56. package/dist/safe-js/restore.d.ts +1 -0
  57. package/dist/safe-js/run.d.ts +10 -0
  58. package/package.json +2 -2
  59. package/dist/safe-js/chunks/chunk-A4L72WXV.js.map +0 -7
  60. package/dist/safe-js/chunks/chunk-B4M6QVUV.js.map +0 -7
  61. package/dist/safe-js/chunks/chunk-BHYBD6SY.js.map +0 -7
  62. package/dist/safe-js/chunks/chunk-HYD4K4HN.js.map +0 -7
  63. package/dist/safe-js/chunks/chunk-ILYJBA2D.js.map +0 -7
  64. package/dist/safe-js/chunks/chunk-Q7B6JIMI.js.map +0 -7
  65. package/dist/safe-js/chunks/harness-LUYCGWHZ.js +0 -10
  66. package/dist/safe-js/chunks/mcp-IWKZB2R2.js +0 -11
  67. package/dist/safe-js/chunks/migration-file-IXO5MLP4.js +0 -12
  68. package/dist/safe-js/chunks/restore-SI7HOC6C.js +0 -13
  69. package/dist/safe-js/chunks/run-SHI2PYR6.js +0 -17
  70. package/dist/safe-js/chunks/runtime-modules-OO72HTVF.js +0 -10
  71. /package/dist/safe-js/chunks/{chunk-4CX3HYRY.js.map → chunk-FA5CQO6V.js.map} +0 -0
  72. /package/dist/safe-js/chunks/{chunk-LPBTSTDG.js.map → chunk-GCOLKRMY.js.map} +0 -0
  73. /package/dist/safe-js/chunks/{chunk-GMPZBMPA.js.map → chunk-K3ZRBAG5.js.map} +0 -0
  74. /package/dist/safe-js/chunks/{chunk-JNLY7IMV.js.map → chunk-QL2ALAE6.js.map} +0 -0
  75. /package/dist/safe-js/chunks/{chunk-BEXRQET4.js.map → chunk-S2GFVXSI.js.map} +0 -0
  76. /package/dist/safe-js/chunks/{chunk-IS7YUCOF.js.map → chunk-XHSOM5CG.js.map} +0 -0
  77. /package/dist/safe-js/chunks/{cli-runtime-YK2WE33M.js.map → cli-runtime-6QPGM3TX.js.map} +0 -0
  78. /package/dist/safe-js/chunks/{dump-ATWBOZWV.js.map → dump-TU6SYRFD.js.map} +0 -0
  79. /package/dist/safe-js/chunks/{fs-D72Y52I5.js.map → fs-HTZT32MQ.js.map} +0 -0
  80. /package/dist/safe-js/chunks/{harness-LUYCGWHZ.js.map → harness-RYAMI444.js.map} +0 -0
  81. /package/dist/safe-js/chunks/{mcp-IWKZB2R2.js.map → mcp-DO2IRFGQ.js.map} +0 -0
  82. /package/dist/safe-js/chunks/{migration-file-IXO5MLP4.js.map → migration-file-K7UH5ZG6.js.map} +0 -0
  83. /package/dist/safe-js/chunks/{restore-SI7HOC6C.js.map → restore-7LRP4BM3.js.map} +0 -0
  84. /package/dist/safe-js/chunks/{run-SHI2PYR6.js.map → run-6SETM7SV.js.map} +0 -0
  85. /package/dist/safe-js/chunks/{runtime-modules-OO72HTVF.js.map → runtime-modules-MCQS2SHQ.js.map} +0 -0
@@ -157,12 +157,11 @@ function releaseTemplateObjects(budget) {
157
157
  }
158
158
 
159
159
  // packages/safe-js/src/interp/budget.ts
160
- var REGEX_STEP_LIMIT = 2e3;
161
160
  var REGEX_COMPILE_LIMITS = Object.freeze({
162
- sourceLength: 4096,
163
- flagsLength: 8,
164
- depth: 64,
165
- allocations: 16384
161
+ sourceLength: Infinity,
162
+ flagsLength: Infinity,
163
+ depth: Infinity,
164
+ allocations: Infinity
166
165
  });
167
166
  var DEADLINE_CHECK_INTERVAL = 1024;
168
167
  var SandboxError = class extends Error {
@@ -204,6 +203,8 @@ var BudgetAccounting = class {
204
203
  allChecksSuspended = 0;
205
204
  deadlineChecksSuspended = 0;
206
205
  visitsUntilDeadlineCheck = DEADLINE_CHECK_INTERVAL;
206
+ pendingDeadlines;
207
+ earliestPendingDeadline;
207
208
  retainedDataSize = 0;
208
209
  retainedData = /* @__PURE__ */ new Map();
209
210
  retainedValueSources = /* @__PURE__ */ new Map();
@@ -214,6 +215,8 @@ var BudgetAccounting = class {
214
215
  provisionalScopes = 0;
215
216
  compileTickets = /* @__PURE__ */ new Map();
216
217
  completedCompileTickets = /* @__PURE__ */ new Set();
218
+ reconciliationHolds = 0;
219
+ deferredCompileDiscards = /* @__PURE__ */ new Set();
217
220
  realmViews;
218
221
  constructor(options = {}) {
219
222
  this.deadline = normalizeDeadline(options.deadline);
@@ -221,6 +224,12 @@ var BudgetAccounting = class {
221
224
  maxSteps: normalizeLimit("maxSteps", options.maxSteps),
222
225
  maxCallDepth: normalizeLimit("maxCallDepth", options.maxCallDepth),
223
226
  stringLength: normalizeLimit("stringLength", options.stringLength),
227
+ ...options.regexSourceLength === void 0 ? {} : {
228
+ regexSourceLength: normalizeRegexLimit("regexSourceLength", options.regexSourceLength)
229
+ },
230
+ ...options.regexCompileAllocations === void 0 ? {} : {
231
+ regexCompileAllocations: normalizeRegexLimit("regexCompileAllocations", options.regexCompileAllocations)
232
+ },
224
233
  arrayLength: normalizeLimit("arrayLength", options.arrayLength),
225
234
  dataSize: normalizeLimit("dataSize", options.dataSize)
226
235
  });
@@ -269,6 +278,36 @@ var Budget = class _Budget {
269
278
  set currentCallDepth(value) {
270
279
  this.accounting.currentCallDepth = value;
271
280
  }
281
+ // Pending host operations keep their elapsed deadline active during sampled
282
+ // synchronous work. Linked private records need no observable native hooks.
283
+ acquireDeadline(deadline, onExceeded) {
284
+ if (!Number.isFinite(deadline)) throw new TypeError("Deadline must be a finite timestamp.");
285
+ const accounting = this.accounting;
286
+ const pending = {
287
+ deadline,
288
+ onExceeded,
289
+ next: accounting.pendingDeadlines,
290
+ active: true
291
+ };
292
+ if (pending.next !== void 0) pending.next.previous = pending;
293
+ accounting.pendingDeadlines = pending;
294
+ if (accounting.earliestPendingDeadline === void 0 || pending.deadline < accounting.earliestPendingDeadline.deadline)
295
+ accounting.earliestPendingDeadline = pending;
296
+ return () => {
297
+ if (!pending.active) return;
298
+ pending.active = false;
299
+ if (pending.previous === void 0) accounting.pendingDeadlines = pending.next;
300
+ else pending.previous.next = pending.next;
301
+ if (pending.next !== void 0) pending.next.previous = pending.previous;
302
+ pending.previous = pending.next = void 0;
303
+ pending.onExceeded = void 0;
304
+ if (accounting.earliestPendingDeadline !== pending) return;
305
+ accounting.earliestPendingDeadline = void 0;
306
+ for (let next = accounting.pendingDeadlines; next !== void 0; next = next.next)
307
+ if (accounting.earliestPendingDeadline === void 0 || next.deadline < accounting.earliestPendingDeadline.deadline)
308
+ accounting.earliestPendingDeadline = next;
309
+ };
310
+ }
272
311
  forkRealm() {
273
312
  const view = new _Budget();
274
313
  view.accounting = this.accounting;
@@ -311,14 +350,17 @@ var Budget = class _Budget {
311
350
  }
312
351
  }
313
352
  allocateString(value) {
314
- if (this.accounting.allChecksSuspended === 0 && this.accounting.limits.stringLength !== void 0 && value.length > this.accounting.limits.stringLength) {
353
+ this.allocateStringLength(value.length);
354
+ return value;
355
+ }
356
+ allocateStringLength(length) {
357
+ if (this.accounting.allChecksSuspended === 0 && this.accounting.limits.stringLength !== void 0 && length > this.accounting.limits.stringLength) {
315
358
  throw new SandboxError({
316
359
  budget: "stringLength",
317
- current: value.length,
360
+ current: length,
318
361
  limit: this.accounting.limits.stringLength
319
362
  });
320
363
  }
321
- return value;
322
364
  }
323
365
  allocateArrayLength(length) {
324
366
  if (this.accounting.allChecksSuspended === 0 && this.accounting.limits.arrayLength !== void 0 && length > this.accounting.limits.arrayLength) {
@@ -333,7 +375,8 @@ var Budget = class _Budget {
333
375
  this.allocateArrayLength(count);
334
376
  }
335
377
  reconcileDataUsage(usage) {
336
- const total = usage + this.accounting.retainedDataSize;
378
+ const measured = usage + this.accounting.retainedDataSize;
379
+ const total = this.reconciliationDeferred ? Math.max(measured, this.accounting.currentDataSize) : measured;
337
380
  this.checkDataUsage(total);
338
381
  this.accounting.currentDataSize = total;
339
382
  this.accounting.peakDataSize = Math.max(this.accounting.peakDataSize, total);
@@ -355,6 +398,23 @@ var Budget = class _Budget {
355
398
  if (values === void 0) this.accounting.retainedValueSources.delete(owner);
356
399
  else this.accounting.retainedValueSources.set(owner, values);
357
400
  }
401
+ get reconciliationDeferred() {
402
+ return this.accounting.reconciliationHolds > 0;
403
+ }
404
+ deferReconciliation() {
405
+ this.accounting.reconciliationHolds++;
406
+ const generation = this.accounting.compileGeneration;
407
+ let released = false;
408
+ return () => {
409
+ if (released) return;
410
+ released = true;
411
+ if (generation !== this.accounting.compileGeneration) return;
412
+ if (--this.accounting.reconciliationHolds !== 0) return;
413
+ for (const ticket of this.accounting.deferredCompileDiscards)
414
+ this.accounting.completedCompileTickets.add(ticket);
415
+ this.accounting.deferredCompileDiscards.clear();
416
+ };
417
+ }
358
418
  *retainedValues() {
359
419
  for (const values of this.accounting.retainedValueSources.values()) {
360
420
  const retained = values();
@@ -395,6 +455,7 @@ var Budget = class _Budget {
395
455
  if (ticket.owner.generation !== this.accounting.compileGeneration || !this.accounting.compileTickets.has(ticket)) {
396
456
  throw new SandboxError("reentry");
397
457
  }
458
+ if (this.reconciliationDeferred) usage = Math.max(usage, this.compileTicketUsage(ticket));
398
459
  this.setRetainedDataUsage(ticket, usage);
399
460
  this.accounting.compileTickets.set(ticket, usage);
400
461
  }
@@ -402,6 +463,10 @@ var Budget = class _Budget {
402
463
  if (ticket.owner.generation !== this.accounting.compileGeneration) return;
403
464
  const usage = this.accounting.compileTickets.get(ticket);
404
465
  if (usage === void 0) return;
466
+ if (this.reconciliationDeferred) {
467
+ this.accounting.deferredCompileDiscards.add(ticket);
468
+ return;
469
+ }
405
470
  this.accounting.compileTickets.delete(ticket);
406
471
  this.accounting.completedCompileTickets.delete(ticket);
407
472
  this.accounting.retainedData.delete(ticket);
@@ -409,6 +474,19 @@ var Budget = class _Budget {
409
474
  this.accounting.currentDataSize -= usage;
410
475
  }
411
476
  reconcileCompileData(usage, included, transferred = included, retainedOwner, complete = false) {
477
+ if (this.reconciliationDeferred) {
478
+ if (retainedOwner !== void 0) this.setRetainedDataUsage(retainedOwner, usage);
479
+ else {
480
+ let includedUsage2 = 0;
481
+ for (const ticket of included) includedUsage2 += this.compileTicketUsage(ticket);
482
+ const measured2 = usage + this.accounting.retainedDataSize - includedUsage2;
483
+ const total2 = Math.max(measured2, this.accounting.currentDataSize);
484
+ this.checkDataUsage(total2);
485
+ this.accounting.currentDataSize = total2;
486
+ this.accounting.peakDataSize = Math.max(this.accounting.peakDataSize, total2);
487
+ }
488
+ return /* @__PURE__ */ new Set();
489
+ }
412
490
  let includedUsage = 0;
413
491
  let transferredUsage = 0;
414
492
  let discardedUsage = 0;
@@ -472,8 +550,10 @@ var Budget = class _Budget {
472
550
  released = true;
473
551
  if (generation !== this.accounting.compileGeneration) return;
474
552
  this.accounting.provisionalScopes -= 1;
475
- if (!commit)
476
- this.accounting.currentDataSize = previous + this.accounting.retainedDataSize - previousRetained;
553
+ if (!commit) {
554
+ const restored = previous + this.accounting.retainedDataSize - previousRetained;
555
+ this.accounting.currentDataSize = this.reconciliationDeferred ? Math.max(restored, this.accounting.currentDataSize) : restored;
556
+ }
477
557
  };
478
558
  }
479
559
  enterCall() {
@@ -495,6 +575,8 @@ var Budget = class _Budget {
495
575
  this.accounting.provisionalScopes = 0;
496
576
  this.accounting.compileTickets.clear();
497
577
  this.accounting.completedCompileTickets.clear();
578
+ this.accounting.reconciliationHolds = 0;
579
+ this.accounting.deferredCompileDiscards.clear();
498
580
  this.accounting.stepsUsed = 0;
499
581
  this.accounting.peakCallDepth = 0;
500
582
  this.accounting.currentCallDepth = 0;
@@ -530,18 +612,26 @@ var Budget = class _Budget {
530
612
  };
531
613
  }
532
614
  checkDeadline() {
533
- if (this.accounting.allChecksSuspended > 0 || this.accounting.deadlineChecksSuspended > 0 || this.accounting.deadline === void 0) {
615
+ const pending = this.accounting.earliestPendingDeadline;
616
+ const deadline = this.accounting.deadline === void 0 ? pending?.deadline : Math.min(this.accounting.deadline, pending?.deadline ?? Infinity);
617
+ if (this.accounting.allChecksSuspended > 0 || this.accounting.deadlineChecksSuspended > 0 || deadline === void 0) {
534
618
  return;
535
619
  }
536
620
  const now = Date.now();
537
- if (now <= this.accounting.deadline) {
621
+ if (now <= deadline) {
538
622
  return;
539
623
  }
540
- throw new SandboxError({
624
+ const reason = new SandboxError({
541
625
  budget: "deadline",
542
626
  current: now,
543
- limit: this.accounting.deadline
627
+ limit: deadline
544
628
  });
629
+ if (pending?.deadline === deadline) {
630
+ const notify = pending.onExceeded;
631
+ pending.onExceeded = void 0;
632
+ notify?.(reason);
633
+ }
634
+ throw reason;
545
635
  }
546
636
  checkDataUsage(usage) {
547
637
  if (this.accounting.allChecksSuspended === 0 && this.accounting.limits.dataSize !== void 0 && usage > this.accounting.limits.dataSize) {
@@ -553,7 +643,7 @@ var Budget = class _Budget {
553
643
  }
554
644
  }
555
645
  checkSampledDeadline(units) {
556
- if (this.accounting.allChecksSuspended > 0 || this.accounting.deadlineChecksSuspended > 0 || this.accounting.deadline === void 0) {
646
+ if (this.accounting.allChecksSuspended > 0 || this.accounting.deadlineChecksSuspended > 0 || this.accounting.deadline === void 0 && this.accounting.earliestPendingDeadline === void 0) {
557
647
  return;
558
648
  }
559
649
  this.accounting.visitsUntilDeadlineCheck -= units;
@@ -586,14 +676,6 @@ var Budget = class _Budget {
586
676
  };
587
677
  }
588
678
  };
589
- function allocateRegexSteps(steps) {
590
- if (!Number.isInteger(steps) || steps < 0) {
591
- throw new Error("steps must be a non-negative integer.");
592
- }
593
- if (steps > REGEX_STEP_LIMIT) {
594
- throw new SandboxError({ budget: "steps", current: steps, limit: REGEX_STEP_LIMIT });
595
- }
596
- }
597
679
  function normalizeDeadline(deadline) {
598
680
  if (deadline === void 0) {
599
681
  return void 0;
@@ -609,6 +691,12 @@ function normalizeLimit(name, value) {
609
691
  }
610
692
  return value;
611
693
  }
694
+ function normalizeRegexLimit(name, value) {
695
+ if (value === void 0) return void 0;
696
+ if (!Number.isSafeInteger(value) || value < 1)
697
+ throw new RangeError(`${name} must be a positive safe integer.`);
698
+ return value;
699
+ }
612
700
 
613
701
  // packages/safe-js/src/interp/regex/compile-guard.ts
614
702
  var compiledData = /* @__PURE__ */ new WeakMap();
@@ -649,7 +737,7 @@ var RegexCompileGuard = class {
649
737
  ticket;
650
738
  retained = false;
651
739
  checkLength(length, flags = false) {
652
- const hard = flags ? REGEX_COMPILE_LIMITS.flagsLength : REGEX_COMPILE_LIMITS.sourceLength;
740
+ const hard = flags ? REGEX_COMPILE_LIMITS.flagsLength : this.scope?.owner?.budget.limits.regexSourceLength ?? REGEX_COMPILE_LIMITS.sourceLength;
653
741
  const limit = Math.min(hard, this.scope?.owner?.budget.limits.stringLength ?? hard);
654
742
  if (length > limit) throw new SandboxError({ budget: "stringLength", current: length, limit });
655
743
  }
@@ -660,11 +748,12 @@ var RegexCompileGuard = class {
660
748
  }
661
749
  allocate(units) {
662
750
  const next = this.allocations + units;
663
- if (next > REGEX_COMPILE_LIMITS.allocations) {
751
+ const limit = this.scope?.owner?.budget.limits.regexCompileAllocations ?? REGEX_COMPILE_LIMITS.allocations;
752
+ if (next > limit) {
664
753
  throw new SandboxError({
665
754
  budget: "dataSize",
666
755
  current: next,
667
- limit: REGEX_COMPILE_LIMITS.allocations
756
+ limit
668
757
  });
669
758
  }
670
759
  this.work(units);
@@ -977,6 +1066,753 @@ function findNumberEnd(value, startIndex) {
977
1066
  return index;
978
1067
  }
979
1068
 
1069
+ // packages/safe-js/src/parse/compact-spans.ts
1070
+ var positionOwners = /* @__PURE__ */ new WeakMap();
1071
+ var getOwner = WeakMap.prototype.get.bind(positionOwners);
1072
+ var setOwner = WeakMap.prototype.set.bind(positionOwners);
1073
+ var cacheSize = 514;
1074
+ var writableSpan = /* @__PURE__ */ Symbol("compiler span writability");
1075
+ var CompactSourcePositions = class {
1076
+ sourceLength;
1077
+ lines = [0];
1078
+ positions = /* @__PURE__ */ new Map();
1079
+ makeSpan;
1080
+ constructor(source) {
1081
+ this.sourceLength = source.length;
1082
+ for (let offset = 0; offset < source.length; offset++) {
1083
+ const code = source.charCodeAt(offset);
1084
+ if (code === 13 && source.charCodeAt(offset + 1) === 10) offset++;
1085
+ if (code === 10 || code === 13 || code === 8232 || code === 8233)
1086
+ this.lines.push(offset + 1);
1087
+ }
1088
+ const owner = this;
1089
+ class Span {
1090
+ #start;
1091
+ #end;
1092
+ constructor(start, end) {
1093
+ this.#start = start;
1094
+ this.#end = end;
1095
+ Object.defineProperties(this, descriptors);
1096
+ }
1097
+ get start() {
1098
+ return typeof this.#start === "number" ? owner.position(this.#start) : this.#start.assigned;
1099
+ }
1100
+ set start(value) {
1101
+ if (Object.isFrozen(this)) throw new TypeError("Cannot assign to a frozen source span.");
1102
+ this.#start = getOwner(value) === owner ? value.offset : { assigned: value };
1103
+ }
1104
+ get end() {
1105
+ return typeof this.#end === "number" ? owner.position(this.#end) : this.#end.assigned;
1106
+ }
1107
+ set end(value) {
1108
+ if (Object.isFrozen(this)) throw new TypeError("Cannot assign to a frozen source span.");
1109
+ this.#end = getOwner(value) === owner ? value.offset : { assigned: value };
1110
+ }
1111
+ }
1112
+ const descriptors = {
1113
+ start: {
1114
+ ...Object.getOwnPropertyDescriptor(Span.prototype, "start"),
1115
+ enumerable: true
1116
+ },
1117
+ end: {
1118
+ ...Object.getOwnPropertyDescriptor(Span.prototype, "end"),
1119
+ enumerable: true
1120
+ },
1121
+ // Sealed accessor-only objects otherwise report as frozen. This private
1122
+ // data field preserves the distinction for the mutable endpoint setters.
1123
+ [writableSpan]: { value: true, writable: true, configurable: true }
1124
+ };
1125
+ delete Span.prototype.start;
1126
+ delete Span.prototype.end;
1127
+ this.makeSpan = (start, end) => new Span(start, end);
1128
+ }
1129
+ position(offset) {
1130
+ this.assertOffset(offset);
1131
+ const cached = this.positions.get(offset);
1132
+ if (cached !== void 0) return cached;
1133
+ let low = 0, high = this.lines.length;
1134
+ while (low + 1 < high) {
1135
+ const middle = low + Math.floor((high - low) / 2);
1136
+ if (this.lines[middle] <= offset) low = middle;
1137
+ else high = middle;
1138
+ }
1139
+ const position = Object.freeze({
1140
+ line: low + 1,
1141
+ column: offset - this.lines[low] + 1,
1142
+ offset
1143
+ });
1144
+ setOwner(position, this);
1145
+ if (this.positions.size === cacheSize)
1146
+ this.positions.delete(this.positions.keys().next().value);
1147
+ this.positions.set(offset, position);
1148
+ return position;
1149
+ }
1150
+ span(start, end) {
1151
+ this.assertOffset(start);
1152
+ this.assertOffset(end);
1153
+ return this.makeSpan(start, end);
1154
+ }
1155
+ compatiblePosition(position) {
1156
+ if (!Number.isSafeInteger(position.offset) || position.offset < 0 || position.offset > this.sourceLength)
1157
+ return void 0;
1158
+ const point = this.position(position.offset);
1159
+ return point.line === position.line && point.column === position.column ? point : void 0;
1160
+ }
1161
+ assertOffset(offset) {
1162
+ if (!Number.isSafeInteger(offset) || offset < 0 || offset > this.sourceLength)
1163
+ throw new RangeError("Source coordinate offset is outside its source.");
1164
+ }
1165
+ };
1166
+ function compactDerivedPosition(base, position) {
1167
+ return getOwner(base)?.compatiblePosition(position);
1168
+ }
1169
+ function compactSourceSpan(start, end) {
1170
+ const owner = getOwner(start);
1171
+ return owner !== void 0 && getOwner(end) === owner ? owner.span(start.offset, end.offset) : void 0;
1172
+ }
1173
+
1174
+ // packages/safe-js/src/parse/function-source.ts
1175
+ var functionSources = /* @__PURE__ */ new WeakMap();
1176
+ var templateSources = /* @__PURE__ */ new WeakMap();
1177
+ var functionStrictness = /* @__PURE__ */ new WeakMap();
1178
+ var evalFunctionDeclarations = /* @__PURE__ */ new WeakSet();
1179
+ var dynamicSourceRecords = /* @__PURE__ */ new WeakSet();
1180
+ var dynamicNodeSources = /* @__PURE__ */ new WeakMap();
1181
+ var dynamicValueSources = /* @__PURE__ */ new WeakMap();
1182
+
1183
+ // packages/safe-js/src/parse/compact-module-ast.ts
1184
+ var chunkLength = 65536;
1185
+ var scalarMask = 268435455;
1186
+ var handles = /* @__PURE__ */ new WeakMap();
1187
+ var mutableRecord = /* @__PURE__ */ Symbol("compiler record writability");
1188
+ var recordToken = /* @__PURE__ */ Symbol("compiler traversal authority");
1189
+ var defineCompilerProperty = Reflect.defineProperty;
1190
+ var NativeRowMap = Map;
1191
+ var nativeIndexMap = {
1192
+ get: Function.prototype.call.bind(Map.prototype.get),
1193
+ has: Function.prototype.call.bind(Map.prototype.has),
1194
+ set: Function.prototype.call.bind(Map.prototype.set),
1195
+ delete: Function.prototype.call.bind(Map.prototype.delete),
1196
+ clear: Function.prototype.call.bind(Map.prototype.clear),
1197
+ keys: Function.prototype.call.bind(Map.prototype.keys),
1198
+ size: Function.prototype.call.bind(
1199
+ Object.getOwnPropertyDescriptor(Map.prototype, "size").get
1200
+ )
1201
+ };
1202
+ var CodeRecord = class {
1203
+ constructor(token, owner, row) {
1204
+ this.owner = owner;
1205
+ this.row = row;
1206
+ if (token !== recordToken) throw new TypeError("Foreign compiler traversal authority.");
1207
+ Object.freeze(this);
1208
+ }
1209
+ owner;
1210
+ row;
1211
+ #brand = true;
1212
+ static authentic(value) {
1213
+ return #brand in value && value.#brand;
1214
+ }
1215
+ };
1216
+ function record(value) {
1217
+ if (value === null || typeof value !== "object") return void 0;
1218
+ return CodeRecord.authentic(value) ? value : handles.get(value);
1219
+ }
1220
+ var CompactModuleAst = class {
1221
+ constructor(source) {
1222
+ this.source = source;
1223
+ this.positions = new CompactSourcePositions(source);
1224
+ this.maxWords = Math.min(scalarMask - 1, Math.max(1024, source.length * 24 + 1024));
1225
+ }
1226
+ source;
1227
+ chunks = [];
1228
+ shapes = [];
1229
+ shapeIDs = /* @__PURE__ */ new Map();
1230
+ strings = [];
1231
+ stringIDs = /* @__PURE__ */ new Map();
1232
+ numbers = [];
1233
+ cache = /* @__PURE__ */ new Map();
1234
+ boundaries = /* @__PURE__ */ new Set();
1235
+ persistentBoundaries = /* @__PURE__ */ new Set();
1236
+ overrides = /* @__PURE__ */ new WeakMap();
1237
+ finished = false;
1238
+ positions;
1239
+ maxWords;
1240
+ used = 0;
1241
+ bodies = 0;
1242
+ dynamicSource;
1243
+ statistics() {
1244
+ return {
1245
+ words: this.used,
1246
+ bufferBytes: this.chunks.reduce((sum, c) => sum + c.byteLength, 0),
1247
+ bodies: this.bodies,
1248
+ materializedRecords: this.cache.size,
1249
+ strings: this.strings.length
1250
+ };
1251
+ }
1252
+ finish() {
1253
+ this.finished = true;
1254
+ if (this.chunks.length) {
1255
+ const last = this.chunks.length - 1;
1256
+ this.chunks[last] = this.chunks[last].slice(0, (this.used - 1) % chunkLength + 1);
1257
+ }
1258
+ this.stringIDs.clear();
1259
+ this.shapeIDs.clear();
1260
+ this.persistentBoundaries.clear();
1261
+ }
1262
+ /** Retirement consumes unobserved parser arrays after syntax validation. */
1263
+ pack(root, body = true, retire = false, persistent = true) {
1264
+ if (this.finished) throw new TypeError("Compiler body storage is finished.");
1265
+ const seen = /* @__PURE__ */ new WeakMap();
1266
+ const pending = [];
1267
+ const encode = (value) => {
1268
+ if (value === null || typeof value !== "object") return this.scalar(value);
1269
+ const existing = record(value);
1270
+ if (existing?.owner === this) {
1271
+ if (retire && !this.overrides.has(value)) {
1272
+ this.cache.delete(existing.row);
1273
+ if (!this.persistentBoundaries.has(existing.row)) this.boundaries.delete(existing.row);
1274
+ }
1275
+ return existing.row + 1;
1276
+ }
1277
+ const previous = seen.get(value);
1278
+ if (previous !== void 0) return previous + 1;
1279
+ let kind, row, values = [];
1280
+ const array = Array.isArray(value);
1281
+ const keys = array ? [] : Object.keys(value).filter((key) => key !== "nodeId");
1282
+ if (array) {
1283
+ kind = 0;
1284
+ row = this.reserve(2 + value.length);
1285
+ values = value;
1286
+ this.write(row, kind);
1287
+ this.write(row + 1, value.length);
1288
+ } else if (keys.length === 2 && keys[0] === "start" && keys[1] === "end") {
1289
+ const span = value, start = span.start, end = span.end;
1290
+ const startPoint = this.positions.compatiblePosition(start);
1291
+ const endPoint = this.positions.compatiblePosition(end);
1292
+ if (startPoint && endPoint) {
1293
+ kind = 1;
1294
+ row = this.reserve(3);
1295
+ this.write(row, kind);
1296
+ this.write(row + 1, start.offset);
1297
+ this.write(row + 2, end.offset);
1298
+ } else {
1299
+ kind = 2;
1300
+ row = this.reserve(7);
1301
+ this.write(row, kind);
1302
+ [start.line, start.column, start.offset, end.line, end.column, end.offset].forEach(
1303
+ (n, i) => this.write(row + 1 + i, n)
1304
+ );
1305
+ }
1306
+ } else {
1307
+ values = keys.map((key2) => value[key2]);
1308
+ if ("nodeId" in value || typeof value.type === "string" && "span" in value) {
1309
+ keys.push("@id");
1310
+ values.push(value.nodeId);
1311
+ const metadata = functionSources.get(value);
1312
+ if (metadata) {
1313
+ if (metadata.text !== this.source)
1314
+ throw new TypeError("Foreign compiler function source.");
1315
+ keys.push("@start", "@end", "@strict");
1316
+ values.push(
1317
+ metadata.start,
1318
+ metadata.end,
1319
+ functionStrictness.get(value)
1320
+ );
1321
+ }
1322
+ const template = templateSources.get(value);
1323
+ if (template !== void 0) {
1324
+ if (template !== this.source) throw new TypeError("Foreign compiler template source.");
1325
+ keys.push("@template");
1326
+ values.push(true);
1327
+ }
1328
+ }
1329
+ const key = JSON.stringify(keys);
1330
+ let shape = this.shapeIDs.get(key);
1331
+ if (shape === void 0) {
1332
+ shape = this.shapes.length;
1333
+ this.shapes.push(this.shape(keys));
1334
+ this.shapeIDs.set(key, shape);
1335
+ }
1336
+ kind = shape + 3;
1337
+ row = this.reserve(1 + values.length);
1338
+ this.write(row, kind);
1339
+ }
1340
+ seen.set(value, row);
1341
+ if (value.type === "VariableDeclarator") {
1342
+ this.boundaries.add(row);
1343
+ this.persistentBoundaries.add(row);
1344
+ }
1345
+ if (kind === 0 || kind >= 3) {
1346
+ const type = value.type;
1347
+ const bodyIndex = [
1348
+ "FunctionDeclaration",
1349
+ "FunctionExpression",
1350
+ "ArrowFunctionExpression"
1351
+ ].includes(String(type)) ? keys.indexOf("body") : -1;
1352
+ pending.push({
1353
+ row,
1354
+ kind,
1355
+ values,
1356
+ index: 0,
1357
+ bodyIndex: bodyIndex >= 0 ? bodyIndex : void 0
1358
+ });
1359
+ }
1360
+ return row + 1;
1361
+ };
1362
+ const reference = encode(root);
1363
+ while (pending.length) {
1364
+ const frame = pending[pending.length - 1];
1365
+ if (frame.index === frame.values.length) {
1366
+ pending.pop();
1367
+ continue;
1368
+ }
1369
+ const index = frame.index++;
1370
+ const child = encode(frame.values[index]);
1371
+ if (retire && frame.kind === 0)
1372
+ defineCompilerProperty(frame.values, index, { value: void 0 });
1373
+ this.write(frame.row + (frame.kind === 0 ? 2 : 1) + index, child);
1374
+ if (index === frame.bodyIndex && child >>> 28 === 0) {
1375
+ this.boundaries.add(child - 1);
1376
+ this.persistentBoundaries.add(child - 1);
1377
+ }
1378
+ }
1379
+ this.boundaries.add(reference - 1);
1380
+ if (persistent) this.persistentBoundaries.add(reference - 1);
1381
+ if (body) this.bodies++;
1382
+ return this.decode(reference);
1383
+ }
1384
+ /** Install source metadata and index numeric rows without publishing every node. */
1385
+ dynamicNodes(root, source) {
1386
+ if (!this.finished) throw new TypeError("Unfinished compiler storage.");
1387
+ if (source.body !== this.source) throw new TypeError("Foreign compiler dynamic source text.");
1388
+ if (this.dynamicSource && this.dynamicSource !== source)
1389
+ throw new TypeError("Foreign compiler dynamic source owner.");
1390
+ this.dynamicSource = source;
1391
+ const rows = new NativeRowMap(), seen = /* @__PURE__ */ new Set(), pending = [root];
1392
+ while (pending.length) {
1393
+ const row = pending.pop();
1394
+ if (seen.has(row)) continue;
1395
+ seen.add(row);
1396
+ const kind = this.read(row);
1397
+ if (kind === 0) {
1398
+ for (let i = 0, n = this.read(row + 1); i < n; i++) {
1399
+ const ref = this.read(row + 2 + i);
1400
+ if (ref >>> 28 === 0) pending.push((ref & scalarMask) - 1);
1401
+ }
1402
+ } else if (kind >= 3) {
1403
+ const keys = this.shapes[kind - 3].keys;
1404
+ const idIndex = keys.indexOf("@id"), typeIndex = keys.indexOf("type");
1405
+ if (idIndex >= 0 && typeIndex >= 0) {
1406
+ const id = this.decode(this.read(row + 1 + idIndex));
1407
+ const type = this.decode(this.read(row + 1 + typeIndex));
1408
+ if (typeof id === "number" && type !== "Module") nativeIndexMap.set(rows, id, row);
1409
+ }
1410
+ for (let i = 0; i < keys.length; i++) {
1411
+ if (keys[i].startsWith("@")) continue;
1412
+ const ref = this.read(row + 1 + i);
1413
+ if (ref >>> 28 === 0) pending.push((ref & scalarMask) - 1);
1414
+ }
1415
+ }
1416
+ }
1417
+ for (const node of this.cache.values()) {
1418
+ const id = node.nodeId;
1419
+ if (typeof id === "number" && nativeIndexMap.has(rows, id))
1420
+ dynamicNodeSources.set(node, source);
1421
+ }
1422
+ return new CompactNodeIndex(recordToken, rows, (row) => this.object(row));
1423
+ }
1424
+ scalar(value) {
1425
+ if (value === void 0) return 268435456;
1426
+ if (value === null) return 536870912;
1427
+ if (typeof value === "boolean") return 805306368 + (value ? 1 : 0);
1428
+ if (typeof value === "string") {
1429
+ let id = this.stringIDs.get(value);
1430
+ if (id === void 0) {
1431
+ id = this.strings.length;
1432
+ this.strings.push(value);
1433
+ this.stringIDs.set(value, id);
1434
+ }
1435
+ return 1073741824 + id;
1436
+ }
1437
+ if (typeof value === "number") {
1438
+ if (Number.isInteger(value) && !Object.is(value, -0) && Math.abs(value) <= scalarMask)
1439
+ return (value < 0 ? 1610612736 : 1342177280) + Math.abs(value);
1440
+ const id = this.numbers.length;
1441
+ this.numbers.push(value);
1442
+ return 1879048192 + id;
1443
+ }
1444
+ throw new TypeError("Unsupported compiler scalar.");
1445
+ }
1446
+ reserve(length) {
1447
+ const row = this.used, next = row + length;
1448
+ if (next > this.maxWords)
1449
+ throw new SandboxError({
1450
+ budget: "dataSize",
1451
+ current: next,
1452
+ limit: this.maxWords
1453
+ });
1454
+ this.used = next;
1455
+ this.write(next - 1, 0);
1456
+ return row;
1457
+ }
1458
+ read(index) {
1459
+ return this.chunks[Math.floor(index / chunkLength)][index % chunkLength];
1460
+ }
1461
+ write(index, value) {
1462
+ const chunk = Math.floor(index / chunkLength);
1463
+ this.chunks[chunk] ??= new Uint32Array(chunkLength);
1464
+ this.chunks[chunk][index % chunkLength] = value;
1465
+ }
1466
+ decode(reference, raw = false) {
1467
+ const tag = reference >>> 28, payload = reference & scalarMask;
1468
+ switch (tag) {
1469
+ case 0:
1470
+ return raw ? new CodeRecord(recordToken, this, payload - 1) : this.object(payload - 1);
1471
+ case 1:
1472
+ return void 0;
1473
+ case 2:
1474
+ return null;
1475
+ case 3:
1476
+ return payload !== 0;
1477
+ case 4:
1478
+ return this.strings[payload];
1479
+ case 5:
1480
+ return payload;
1481
+ case 6:
1482
+ return -payload;
1483
+ case 7:
1484
+ return this.numbers[payload];
1485
+ default:
1486
+ throw new TypeError("Invalid compiler reference.");
1487
+ }
1488
+ }
1489
+ shape(keys) {
1490
+ const descriptors = {};
1491
+ const owner = this;
1492
+ for (let i = 0; i < keys.length; i++) {
1493
+ const key = keys[i];
1494
+ if (key === "@id") {
1495
+ descriptors.nodeId = {
1496
+ value: void 0,
1497
+ writable: true,
1498
+ enumerable: false,
1499
+ configurable: true
1500
+ };
1501
+ continue;
1502
+ }
1503
+ if (key.startsWith("@")) continue;
1504
+ const name = key;
1505
+ descriptors[name] = {
1506
+ enumerable: key !== "@id",
1507
+ configurable: true,
1508
+ get() {
1509
+ const handle = handles.get(this);
1510
+ if (handle?.owner !== owner || owner.shapes[owner.read(handle.row) - 3]?.descriptors !== descriptors)
1511
+ throw new TypeError("Foreign compiler record receiver.");
1512
+ const assigned = owner.overrides.get(this);
1513
+ return assigned?.has(name) ? assigned.get(name) : owner.decode(owner.read(handle.row + 1 + i));
1514
+ },
1515
+ set(value) {
1516
+ const handle = handles.get(this);
1517
+ if (handle?.owner !== owner || owner.shapes[owner.read(handle.row) - 3]?.descriptors !== descriptors)
1518
+ throw new TypeError("Foreign compiler record receiver.");
1519
+ if (Object.isFrozen(this))
1520
+ throw new TypeError("Cannot assign to a frozen compiler record.");
1521
+ let assigned = owner.overrides.get(this);
1522
+ if (!assigned) {
1523
+ assigned = /* @__PURE__ */ new Map();
1524
+ owner.overrides.set(this, assigned);
1525
+ }
1526
+ assigned.set(name, value);
1527
+ }
1528
+ };
1529
+ }
1530
+ descriptors[mutableRecord] = {
1531
+ value: true,
1532
+ writable: true,
1533
+ configurable: true
1534
+ };
1535
+ function CompilerRecord() {
1536
+ Object.defineProperties(this, descriptors);
1537
+ }
1538
+ CompilerRecord.prototype = Object.prototype;
1539
+ return {
1540
+ keys,
1541
+ descriptors,
1542
+ create: () => Reflect.construct(CompilerRecord, [])
1543
+ };
1544
+ }
1545
+ attachMetadata(output, row, shape) {
1546
+ const metadata = (name) => {
1547
+ const index = shape.keys.indexOf(name);
1548
+ return index < 0 ? void 0 : this.decode(this.read(row + 1 + index));
1549
+ };
1550
+ const id = metadata("@id");
1551
+ if (id !== void 0 && this.dynamicSource && shape.keys.includes("type")) {
1552
+ const type = metadata("type");
1553
+ if (type !== "Module") dynamicNodeSources.set(output, this.dynamicSource);
1554
+ }
1555
+ if (id !== void 0)
1556
+ Object.defineProperty(output, "nodeId", {
1557
+ value: id,
1558
+ writable: true,
1559
+ enumerable: false,
1560
+ configurable: true
1561
+ });
1562
+ const start = metadata("@start");
1563
+ if (start !== void 0) {
1564
+ functionSources.set(output, {
1565
+ text: this.source,
1566
+ start,
1567
+ end: metadata("@end")
1568
+ });
1569
+ const strict = metadata("@strict");
1570
+ if (strict !== void 0)
1571
+ functionStrictness.set(
1572
+ output,
1573
+ strict
1574
+ );
1575
+ }
1576
+ if (metadata("@template") === true)
1577
+ templateSources.set(output, this.source);
1578
+ }
1579
+ object(row) {
1580
+ const cached = this.cache.get(row);
1581
+ if (cached !== void 0) return cached;
1582
+ const tasks = [];
1583
+ const make = (index) => {
1584
+ const cached2 = this.cache.get(index);
1585
+ if (cached2) return cached2;
1586
+ const kind = this.read(index);
1587
+ let output2;
1588
+ if (kind === 0) {
1589
+ const array = [];
1590
+ array.length = this.read(index + 1);
1591
+ output2 = array;
1592
+ tasks.push({ row: index, kind, output: output2 });
1593
+ } else if (kind === 1)
1594
+ output2 = this.positions.span(this.read(index + 1), this.read(index + 2));
1595
+ else if (kind === 2)
1596
+ output2 = {
1597
+ start: {
1598
+ line: this.read(index + 1),
1599
+ column: this.read(index + 2),
1600
+ offset: this.read(index + 3)
1601
+ },
1602
+ end: {
1603
+ line: this.read(index + 4),
1604
+ column: this.read(index + 5),
1605
+ offset: this.read(index + 6)
1606
+ }
1607
+ };
1608
+ else {
1609
+ const shape = this.shapes[kind - 3];
1610
+ if (this.boundaries.has(index)) {
1611
+ output2 = shape.create();
1612
+ handles.set(output2, new CodeRecord(recordToken, this, index));
1613
+ this.attachMetadata(output2, index, shape);
1614
+ } else {
1615
+ output2 = {};
1616
+ tasks.push({ row: index, kind, output: output2 });
1617
+ }
1618
+ }
1619
+ this.cache.set(index, output2);
1620
+ if (!this.finished) handles.set(output2, new CodeRecord(recordToken, this, index));
1621
+ return output2;
1622
+ };
1623
+ const value = (ref) => ref >>> 28 === 0 ? make((ref & scalarMask) - 1) : this.decode(ref);
1624
+ const output = make(row);
1625
+ while (tasks.length) {
1626
+ const { row: index, kind, output: target } = tasks.pop();
1627
+ if (kind === 0) {
1628
+ const array = target;
1629
+ for (let i = 0; i < array.length; i++) array[i] = value(this.read(index + 2 + i));
1630
+ } else {
1631
+ const shape = this.shapes[kind - 3];
1632
+ for (let i = 0; i < shape.keys.length; i++) {
1633
+ const key = shape.keys[i];
1634
+ if (!key.startsWith("@"))
1635
+ Object.defineProperty(target, key, {
1636
+ value: value(this.read(index + 1 + i)),
1637
+ writable: true,
1638
+ enumerable: true,
1639
+ configurable: true
1640
+ });
1641
+ }
1642
+ this.attachMetadata(target, index, shape);
1643
+ }
1644
+ }
1645
+ return output;
1646
+ }
1647
+ // Compiler passes use these private-owner records, not the decoded AST cache.
1648
+ isArray(row) {
1649
+ return this.read(row) === 0;
1650
+ }
1651
+ *entries(row) {
1652
+ const kind = this.read(row), cached = this.cache.get(row);
1653
+ if (cached) {
1654
+ for (const key of Object.keys(cached)) yield [key, this.field(row, key)];
1655
+ return;
1656
+ }
1657
+ if (kind === 0) {
1658
+ for (let i = 0, n = this.read(row + 1); i < n; i++)
1659
+ yield [String(i), this.decode(this.read(row + 2 + i), true)];
1660
+ } else if (kind === 1) {
1661
+ yield ["start", this.positions.position(this.read(row + 1))];
1662
+ yield ["end", this.positions.position(this.read(row + 2))];
1663
+ } else if (kind === 2) {
1664
+ yield [
1665
+ "start",
1666
+ {
1667
+ line: this.read(row + 1),
1668
+ column: this.read(row + 2),
1669
+ offset: this.read(row + 3)
1670
+ }
1671
+ ];
1672
+ yield [
1673
+ "end",
1674
+ {
1675
+ line: this.read(row + 4),
1676
+ column: this.read(row + 5),
1677
+ offset: this.read(row + 6)
1678
+ }
1679
+ ];
1680
+ } else if (kind >= 3) {
1681
+ const keys = this.shapes[kind - 3].keys;
1682
+ for (let i = 0; i < keys.length; i++) {
1683
+ const key = keys[i];
1684
+ if (!key.startsWith("@")) yield [key, this.decode(this.read(row + 1 + i), true)];
1685
+ }
1686
+ }
1687
+ }
1688
+ field(row, key) {
1689
+ const kind = this.read(row), cached = this.cache.get(row);
1690
+ if (cached) {
1691
+ const descriptor = Object.getOwnPropertyDescriptor(cached, key);
1692
+ if (!descriptor) return void 0;
1693
+ if ("value" in descriptor) return descriptor.value;
1694
+ const assigned = this.overrides.get(cached);
1695
+ if (assigned?.has(key)) return assigned.get(key);
1696
+ if (kind < 3) return Reflect.get(cached, key);
1697
+ if (descriptor.get !== this.shapes[kind - 3].descriptors[key]?.get)
1698
+ return Reflect.get(cached, key);
1699
+ }
1700
+ if (kind < 3) return void 0;
1701
+ const keys = this.shapes[kind - 3].keys, index = keys.indexOf(key === "nodeId" ? "@id" : key);
1702
+ return index < 0 ? void 0 : this.decode(this.read(row + 1 + index), true);
1703
+ }
1704
+ assignId(row, id) {
1705
+ const keys = this.shapes[this.read(row) - 3].keys, index = keys.indexOf("@id");
1706
+ if (index < 0) throw new TypeError("Compiler record is not an AST node.");
1707
+ this.write(row + 1 + index, this.scalar(id));
1708
+ const cached = this.cache.get(row);
1709
+ if (cached)
1710
+ Object.defineProperty(cached, "nodeId", {
1711
+ value: id,
1712
+ writable: true,
1713
+ enumerable: false,
1714
+ configurable: true
1715
+ });
1716
+ }
1717
+ offsets(row) {
1718
+ const span = this.field(row, "span");
1719
+ if (!(span instanceof CodeRecord)) return void 0;
1720
+ const kind = this.read(span.row);
1721
+ return kind === 1 ? [this.read(span.row + 1), this.read(span.row + 2)] : kind === 2 ? [this.read(span.row + 3), this.read(span.row + 6)] : void 0;
1722
+ }
1723
+ };
1724
+ function compilerField(value, key) {
1725
+ const handle = record(value);
1726
+ return handle ? handle.owner.field(handle.row, key) : value !== null && typeof value === "object" ? value[key] : void 0;
1727
+ }
1728
+ function compilerIsArray(value) {
1729
+ const handle = record(value);
1730
+ return handle ? handle.owner.isArray(handle.row) : Array.isArray(value);
1731
+ }
1732
+ function* compilerEntries(value) {
1733
+ const handle = record(value);
1734
+ if (handle) yield* handle.owner.entries(handle.row);
1735
+ else yield* Object.entries(value);
1736
+ }
1737
+ function* compilerElements(value) {
1738
+ if (value === null || typeof value !== "object") return;
1739
+ if (Array.isArray(value)) {
1740
+ yield* value;
1741
+ return;
1742
+ }
1743
+ for (const [, child] of compilerEntries(value)) yield child;
1744
+ }
1745
+ function compilerAssignId(value, id) {
1746
+ const handle = record(value);
1747
+ if (handle) handle.owner.assignId(handle.row, id);
1748
+ else
1749
+ Object.defineProperty(value, "nodeId", {
1750
+ value: id,
1751
+ writable: true,
1752
+ enumerable: false,
1753
+ configurable: true
1754
+ });
1755
+ }
1756
+ function compilerOffsets(value) {
1757
+ const handle = record(value);
1758
+ if (handle) return handle.owner.offsets(handle.row);
1759
+ const span = compilerField(value, "span");
1760
+ return span ? [span.start.offset, span.end.offset] : void 0;
1761
+ }
1762
+ var CompactNodeIndex = class extends Map {
1763
+ #rows;
1764
+ #decode;
1765
+ constructor(token, rows, decode) {
1766
+ super();
1767
+ if (token !== recordToken) throw new TypeError("Foreign compiler index authority.");
1768
+ this.#rows = rows;
1769
+ this.#decode = decode;
1770
+ }
1771
+ get size() {
1772
+ return nativeIndexMap.size(this.#rows);
1773
+ }
1774
+ has(key) {
1775
+ return nativeIndexMap.has(this.#rows, key);
1776
+ }
1777
+ get(key) {
1778
+ if (nativeIndexMap.has(this, key)) return nativeIndexMap.get(this, key);
1779
+ const row = nativeIndexMap.get(this.#rows, key);
1780
+ return row === void 0 ? void 0 : this.#decode(row);
1781
+ }
1782
+ set(key, value) {
1783
+ if (!nativeIndexMap.has(this.#rows, key)) nativeIndexMap.set(this.#rows, key, -1);
1784
+ nativeIndexMap.set(this, key, value);
1785
+ return this;
1786
+ }
1787
+ delete(key) {
1788
+ nativeIndexMap.delete(this, key);
1789
+ return nativeIndexMap.delete(this.#rows, key);
1790
+ }
1791
+ clear() {
1792
+ nativeIndexMap.clear(this);
1793
+ nativeIndexMap.clear(this.#rows);
1794
+ }
1795
+ keys() {
1796
+ return nativeIndexMap.keys(this.#rows);
1797
+ }
1798
+ *values() {
1799
+ for (const key of this.keys()) yield this.get(key);
1800
+ }
1801
+ *entries() {
1802
+ for (const key of this.keys()) yield [key, this.get(key)];
1803
+ }
1804
+ [Symbol.iterator]() {
1805
+ return this.entries();
1806
+ }
1807
+ forEach(callback, thisArg) {
1808
+ for (const [key, value] of this) callback.call(thisArg, value, key, this);
1809
+ }
1810
+ };
1811
+ function compactDynamicNodes(root, source) {
1812
+ const handle = record(root);
1813
+ return handle?.owner.dynamicNodes(handle.row, source);
1814
+ }
1815
+
980
1816
  // packages/safe-js/src/parse/bindings.ts
981
1817
  function getFunctionLength(params) {
982
1818
  const firstOptional = params.findIndex(
@@ -1072,66 +1908,169 @@ function* hoistedVarDeclarations(nodes) {
1072
1908
 
1073
1909
  // packages/safe-js/src/parse/private-names.ts
1074
1910
  function validatePrivateNames(root, inheritedNames) {
1075
- const pending = [{
1076
- value: root,
1077
- scope: inheritedNames === void 0 ? void 0 : { names: new Set(inheritedNames) }
1078
- }];
1911
+ const pending = [
1912
+ {
1913
+ value: root,
1914
+ scope: inheritedNames === void 0 ? void 0 : { names: new Set(inheritedNames) }
1915
+ }
1916
+ ];
1079
1917
  while (pending.length > 0) {
1080
1918
  const { value, scope, declaration } = pending.pop();
1081
1919
  if (value === null || typeof value !== "object") continue;
1082
- if (Array.isArray(value)) {
1083
- for (const entry of value) pending.push({ value: entry, scope });
1920
+ if (compilerIsArray(value)) {
1921
+ for (const entry of compilerElements(value)) pending.push({ value: entry, scope });
1084
1922
  continue;
1085
1923
  }
1086
- const node = value;
1087
- if (node.type === "ClassDeclaration" || node.type === "ClassExpression") {
1088
- const klass = value;
1089
- pending.push({ value: klass.superClass, scope });
1924
+ const type = compilerField(value, "type");
1925
+ if (type === "ClassDeclaration" || type === "ClassExpression") {
1926
+ pending.push({ value: compilerField(value, "superClass"), scope });
1090
1927
  const inner = { names: /* @__PURE__ */ new Set(), parent: scope };
1091
1928
  const declarations = /* @__PURE__ */ new Map();
1092
- for (const element of klass.body.body) {
1093
- if (element.type === "StaticBlock" || element.key.type !== "PrivateIdentifier") continue;
1094
- const name = element.key.name;
1929
+ const body = compilerField(value, "body");
1930
+ for (const element of compilerElements(compilerField(body, "body"))) {
1931
+ const key = compilerField(element, "key");
1932
+ if (compilerField(element, "type") === "StaticBlock" || compilerField(key, "type") !== "PrivateIdentifier")
1933
+ continue;
1934
+ const name = compilerField(key, "name");
1095
1935
  if (name === "constructor") throw new Error("Private name #constructor is forbidden.");
1096
- const kind = element.type === "MethodDefinition" ? element.kind : "field";
1936
+ const kind = compilerField(element, "type") === "MethodDefinition" ? compilerField(element, "kind") : "field";
1937
+ const isStatic = compilerField(element, "static");
1097
1938
  const previous = declarations.get(name);
1098
- if (previous !== void 0 && !(previous.static === element.static && (previous.kind === "get" && kind === "set" || previous.kind === "set" && kind === "get")))
1939
+ if (previous !== void 0 && !(previous.static === isStatic && (previous.kind === "get" && kind === "set" || previous.kind === "set" && kind === "get")))
1099
1940
  throw new Error(`Duplicate private name #${name}.`);
1100
- declarations.set(name, { kind: previous === void 0 ? kind : "pair", static: element.static });
1941
+ declarations.set(name, {
1942
+ kind: previous === void 0 ? kind : "pair",
1943
+ static: isStatic
1944
+ });
1101
1945
  inner.names.add(name);
1102
1946
  }
1103
- pending.push({ value: klass.body, scope: inner });
1947
+ pending.push({ value: body, scope: inner });
1104
1948
  continue;
1105
1949
  }
1106
- if (node.type === "PrivateIdentifier") {
1950
+ if (type === "PrivateIdentifier") {
1107
1951
  if (declaration) continue;
1952
+ const name = String(compilerField(value, "name"));
1108
1953
  let owner = scope;
1109
- while (owner !== void 0 && !owner.names.has(String(node.name))) owner = owner.parent;
1110
- if (owner === void 0) throw new Error(`Undeclared private name #${String(node.name)}.`);
1954
+ while (owner !== void 0 && !owner.names.has(name)) owner = owner.parent;
1955
+ if (owner === void 0) throw new Error(`Undeclared private name #${name}.`);
1111
1956
  continue;
1112
1957
  }
1113
- if (node.type === "MemberExpression") {
1114
- const property = node.property;
1115
- if (property.type === "PrivateIdentifier" && node.object.type === "Super")
1958
+ if (type === "MemberExpression") {
1959
+ const property = compilerField(value, "property");
1960
+ if (compilerField(property, "type") === "PrivateIdentifier" && compilerField(compilerField(value, "object"), "type") === "Super")
1116
1961
  throw new Error("super cannot access a private name.");
1117
1962
  }
1118
- if (node.type === "UnaryExpression" && node.operator === "delete") {
1119
- const argument = node.argument;
1120
- if (argument.type === "MemberExpression" && argument.property.type === "PrivateIdentifier")
1963
+ if (type === "UnaryExpression" && compilerField(value, "operator") === "delete") {
1964
+ const argument = compilerField(value, "argument");
1965
+ if (compilerField(argument, "type") === "MemberExpression" && compilerField(compilerField(argument, "property"), "type") === "PrivateIdentifier")
1121
1966
  throw new Error("Private elements cannot be deleted.");
1122
1967
  }
1123
- for (const [key, child] of Object.entries(node)) {
1968
+ for (const [key, child] of compilerEntries(value)) {
1124
1969
  if (key === "span") continue;
1125
1970
  pending.push({
1126
1971
  value: child,
1127
1972
  scope,
1128
- declaration: key === "key" && (node.type === "MethodDefinition" || node.type === "PropertyDefinition")
1973
+ declaration: key === "key" && (type === "MethodDefinition" || type === "PropertyDefinition")
1129
1974
  });
1130
1975
  }
1131
1976
  }
1132
1977
  }
1133
1978
 
1979
+ // packages/safe-js/src/parse/compact-tokens.ts
1980
+ var types = [
1981
+ "identifier",
1982
+ "private-identifier",
1983
+ "keyword",
1984
+ "escaped-keyword",
1985
+ "numeric",
1986
+ "regex",
1987
+ "string",
1988
+ "template",
1989
+ "punctuator",
1990
+ "eof"
1991
+ ];
1992
+ var stride = 3;
1993
+ var legacyEscape = 256;
1994
+ var tokenCacheSize = 256;
1995
+ var CompactTokens = class {
1996
+ constructor(sourcePositions) {
1997
+ this.sourcePositions = sourcePositions;
1998
+ }
1999
+ sourcePositions;
2000
+ rows = new Uint32Array(1024 * stride);
2001
+ values = [];
2002
+ templates = /* @__PURE__ */ new Map();
2003
+ tokens = /* @__PURE__ */ new Map();
2004
+ last;
2005
+ // Only indexing, iteration, length, push and at are used by the lexer/parser.
2006
+ // Historical tokens are materialized on demand in a bounded cache.
2007
+ indexed = new Proxy([], {
2008
+ get: (target, key, receiver) => {
2009
+ if (key === "length") return this.values.length;
2010
+ if (key === "push") return this.push;
2011
+ const index = arrayIndex(key);
2012
+ return index === void 0 ? Reflect.get(target, key, receiver) : this.get(index);
2013
+ },
2014
+ set: () => {
2015
+ throw new TypeError("Compiler token rows cannot be reassigned.");
2016
+ }
2017
+ });
2018
+ finish() {
2019
+ this.rows = this.rows.slice(0, this.values.length * stride);
2020
+ if (this.last) {
2021
+ this.last.start = this.sourcePositions.position(this.last.start.offset);
2022
+ this.last.end = this.sourcePositions.position(this.last.end.offset);
2023
+ }
2024
+ return this.indexed;
2025
+ }
2026
+ push = (token) => {
2027
+ if (this.last !== void 0) {
2028
+ const previous = this.values.length - 1;
2029
+ if (this.last.legacyEscape) this.rows[previous * stride + 2] |= legacyEscape;
2030
+ if (this.last.templateExpressions !== void 0)
2031
+ this.templates.set(previous, this.last.templateExpressions);
2032
+ }
2033
+ const index = this.values.length;
2034
+ const base = index * stride;
2035
+ if (base + stride > this.rows.length) {
2036
+ const rows = new Uint32Array(this.rows.length * 2);
2037
+ rows.set(this.rows);
2038
+ this.rows = rows;
2039
+ }
2040
+ this.rows.set([token.start.offset, token.end.offset, types.indexOf(token.type)], base);
2041
+ this.values.push(token.value);
2042
+ this.last = token;
2043
+ return index + 1;
2044
+ };
2045
+ get(index) {
2046
+ if (index >= this.values.length) return void 0;
2047
+ if (index === this.values.length - 1) return this.last;
2048
+ const cached = this.tokens.get(index);
2049
+ if (cached !== void 0) return cached;
2050
+ const base = index * stride;
2051
+ const bits = this.rows[base + 2];
2052
+ const token = {
2053
+ type: types[bits & 255],
2054
+ value: this.values[index],
2055
+ start: this.sourcePositions.position(this.rows[base]),
2056
+ end: this.sourcePositions.position(this.rows[base + 1])
2057
+ };
2058
+ if (bits & legacyEscape) token.legacyEscape = true;
2059
+ const expressions = this.templates.get(index);
2060
+ if (expressions !== void 0) token.templateExpressions = expressions;
2061
+ if (this.tokens.size === tokenCacheSize) this.tokens.delete(this.tokens.keys().next().value);
2062
+ this.tokens.set(index, token);
2063
+ return token;
2064
+ }
2065
+ };
2066
+ function arrayIndex(key) {
2067
+ if (typeof key !== "string") return void 0;
2068
+ const index = Number(key);
2069
+ return Number.isSafeInteger(index) && index >= 0 && String(index) === key ? index : void 0;
2070
+ }
2071
+
1134
2072
  // packages/safe-js/src/parse/tokenizer.ts
2073
+ var freezePosition = Object.freeze;
1135
2074
  var KEYWORDS = /* @__PURE__ */ new Set([
1136
2075
  "class",
1137
2076
  "extends",
@@ -1239,26 +2178,33 @@ function tokenize(source, options = {}) {
1239
2178
  const lexer = new Lexer(source, options);
1240
2179
  return lexer.tokenize();
1241
2180
  }
2181
+ function tokenizeCompact(source, options, positions) {
2182
+ const tokens = new CompactTokens(positions);
2183
+ new Lexer(source, { ...options, sharedPositions: true }, tokens.indexed).tokenize();
2184
+ return tokens.finish();
2185
+ }
1242
2186
  function collectComments(source) {
1243
2187
  const comments = [];
1244
2188
  tokenize(source, { allowRegexLiterals: true, statementList: true, comments });
1245
2189
  return comments;
1246
2190
  }
1247
2191
  var Lexer = class {
1248
- constructor(source, options) {
2192
+ constructor(source, options, tokens = []) {
1249
2193
  this.source = source;
1250
2194
  this.options = options;
2195
+ this.tokens = tokens;
1251
2196
  }
1252
2197
  source;
1253
2198
  options;
2199
+ tokens;
1254
2200
  index = 0;
1255
2201
  line = 1;
1256
2202
  column = 1;
1257
- tokens = [];
1258
2203
  groupingState = { stack: [], classHeads: [], tokenCount: 0 };
1259
2204
  lastClosedStatementBoundary = false;
1260
2205
  legacyStringEscape = false;
1261
2206
  lineHasToken = false;
2207
+ lastPosition;
1262
2208
  tokenize() {
1263
2209
  while (!this.isAtEnd()) {
1264
2210
  this.skipTrivia();
@@ -2032,11 +2978,15 @@ var Lexer = class {
2032
2978
  return this.index >= this.source.length;
2033
2979
  }
2034
2980
  position() {
2035
- return {
2981
+ if (this.options.sharedPositions && this.lastPosition?.offset === this.index)
2982
+ return this.lastPosition;
2983
+ const position = {
2036
2984
  line: this.line,
2037
2985
  column: this.column,
2038
2986
  offset: this.index
2039
2987
  };
2988
+ if (!this.options.sharedPositions) return position;
2989
+ return this.lastPosition = freezePosition(position);
2040
2990
  }
2041
2991
  advance() {
2042
2992
  if (this.isAtEnd()) {
@@ -2337,15 +3287,39 @@ function compareBySourceOrder(left, right) {
2337
3287
  function isAstNode(value) {
2338
3288
  return typeof value === "object" && value !== null && "type" in value && typeof value.type === "string" && "span" in value && typeof value.span?.start.offset === "number" && typeof value.span?.end.offset === "number";
2339
3289
  }
2340
-
2341
- // packages/safe-js/src/parse/function-source.ts
2342
- var functionSources = /* @__PURE__ */ new WeakMap();
2343
- var templateSources = /* @__PURE__ */ new WeakMap();
2344
- var functionStrictness = /* @__PURE__ */ new WeakMap();
2345
- var evalFunctionDeclarations = /* @__PURE__ */ new WeakSet();
2346
- var dynamicSourceRecords = /* @__PURE__ */ new WeakSet();
2347
- var dynamicNodeSources = /* @__PURE__ */ new WeakMap();
2348
- var dynamicValueSources = /* @__PURE__ */ new WeakMap();
3290
+ function assignCompactIds(root) {
3291
+ const stack = [root];
3292
+ let nextId = 0;
3293
+ const isNode = (value) => value !== null && typeof value === "object" && typeof compilerField(value, "type") === "string" && compilerOffsets(value) !== void 0;
3294
+ while (stack.length) {
3295
+ const node = stack.pop();
3296
+ if (!isNode(node) || compilerField(node, "nodeId") !== void 0) continue;
3297
+ compilerAssignId(node, nextId++);
3298
+ const type = compilerField(node, "type");
3299
+ const children = [];
3300
+ const add = (value) => {
3301
+ if (isNode(value)) children.push(value);
3302
+ else if (compilerIsArray(value)) {
3303
+ for (const child of compilerElements(value))
3304
+ if (isNode(child)) children.push(child);
3305
+ }
3306
+ };
3307
+ if (type === "UnaryExpression") add(compilerField(node, "argument"));
3308
+ else if (type === "ExpressionStatement")
3309
+ add(compilerField(node, "expression"));
3310
+ else if (type === "Module") add(compilerField(node, "body"));
3311
+ else {
3312
+ for (const [key, child] of compilerEntries(node))
3313
+ if (key !== "nodeId" && key !== "span" && key !== "type") add(child);
3314
+ children.sort((left, right) => {
3315
+ const a = compilerOffsets(left), b = compilerOffsets(right);
3316
+ return a[0] - b[0] || a[1] - b[1];
3317
+ });
3318
+ }
3319
+ for (let i = children.length - 1; i >= 0; i--) stack.push(children[i]);
3320
+ }
3321
+ return root;
3322
+ }
2349
3323
 
2350
3324
  // packages/safe-js/src/parse/syntax-diagnostic.ts
2351
3325
  var syntaxDiagnostics = /* @__PURE__ */ new WeakMap();
@@ -3142,6 +4116,7 @@ function allHexDigits(value) {
3142
4116
  }
3143
4117
 
3144
4118
  // packages/safe-js/src/parse/parser.ts
4119
+ var isFrozenPosition = Object.isFrozen;
3145
4120
  var MAX_CONDITIONAL_EXPRESSION_DEPTH = 256;
3146
4121
  var MAX_IF_STATEMENT_DEPTH = 2048;
3147
4122
  var STRICT_BINDING_NAMES = /* @__PURE__ */ new Set(["eval", "arguments", "implements", "interface", "let", "package", "private", "protected", "public", "static", "yield"]);
@@ -3232,7 +4207,7 @@ function parseModule(source, filename = "<input>", owner) {
3232
4207
  compilation.dispose();
3233
4208
  }
3234
4209
  }
3235
- function parseSourceModule(source, filename = "<input>", owner) {
4210
+ function parseSourceModule(source, filename = "<input>", owner, options = {}) {
3236
4211
  const compilation = new CompileScope(owner);
3237
4212
  const syntax = { imports: [], exports: [], moduleRequests: [] };
3238
4213
  let parser;
@@ -3241,8 +4216,10 @@ function parseSourceModule(source, filename = "<input>", owner) {
3241
4216
  if (limit !== void 0 && source.length > limit)
3242
4217
  throw new SandboxError({ budget: "stringLength", current: source.length, limit });
3243
4218
  owner?.budget.visitNode(source.length);
4219
+ const tokenOptions = { allowRegexLiterals: true, statementList: true, compilation, sharedPositions: options.sharedPositions };
4220
+ const tokens = options.compactAst ? tokenizeCompact(source, tokenOptions, new CompactSourcePositions(source)) : tokenize(source, tokenOptions);
3244
4221
  parser = new Parser(
3245
- tokenize(source, { allowRegexLiterals: true, statementList: true, compilation }),
4222
+ tokens,
3246
4223
  source,
3247
4224
  compilation,
3248
4225
  "top-level",
@@ -3256,7 +4233,10 @@ function parseSourceModule(source, filename = "<input>", owner) {
3256
4233
  true,
3257
4234
  syntax
3258
4235
  );
3259
- const module = assignIds(parser.parseModule());
4236
+ if (options.compactAst) parser.enableCompactAst();
4237
+ const parsed = parser.parseModule();
4238
+ parser.finishAstStorage();
4239
+ const module = (options.compactAst ? assignCompactIds : assignIds)(parsed);
3260
4240
  if (source.includes("#")) validatePrivateNames(module);
3261
4241
  let hasTLA = false;
3262
4242
  const pending = [module];
@@ -3264,9 +4244,10 @@ function parseSourceModule(source, filename = "<input>", owner) {
3264
4244
  const node = pending.pop();
3265
4245
  if (node === null || typeof node !== "object") continue;
3266
4246
  owner?.budget.visitNode();
3267
- if ("type" in node && ["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"].includes(String(node.type))) continue;
3268
- if ("type" in node && (node.type === "AwaitExpression" || "await" in node && node.await === true || node.type === "VariableDeclaration" && "disposal" in node && node.disposal === "async")) hasTLA = true;
3269
- pending.push(...Object.values(node));
4247
+ const type = compilerField(node, "type");
4248
+ if (["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"].includes(String(type))) continue;
4249
+ if (type !== void 0 && (type === "AwaitExpression" || compilerField(node, "await") === true || type === "VariableDeclaration" && compilerField(node, "disposal") === "async")) hasTLA = true;
4250
+ for (const child of compilerElements(node)) pending.push(child);
3270
4251
  }
3271
4252
  return { ...syntax, module, hasTLA, requests: [...new Set(syntax.moduleRequests.map((request) => request.specifier))] };
3272
4253
  } catch (error) {
@@ -3280,7 +4261,7 @@ function parseSourceModule(source, filename = "<input>", owner) {
3280
4261
  compilation.dispose();
3281
4262
  }
3282
4263
  }
3283
- function parseExecutableModule(source, filename = "<input>", owner) {
4264
+ function parseExecutableModule(source, filename = "<input>", owner, importSpecifiers) {
3284
4265
  const compilation = new CompileScope(owner);
3285
4266
  try {
3286
4267
  const result = assignIds(
@@ -3289,7 +4270,10 @@ function parseExecutableModule(source, filename = "<input>", owner) {
3289
4270
  source,
3290
4271
  compilation,
3291
4272
  "top-level",
3292
- { ...ordinaryFunctionContext, newTarget: false, requireAsyncAwait: true }
4273
+ { ...ordinaryFunctionContext, newTarget: false, requireAsyncAwait: true },
4274
+ true,
4275
+ void 0,
4276
+ new Set(importSpecifiers)
3293
4277
  ).parseModule()
3294
4278
  );
3295
4279
  throwIfImportMetaAssignment(result);
@@ -3307,7 +4291,7 @@ function parseExecutableModule(source, filename = "<input>", owner) {
3307
4291
  compilation.dispose();
3308
4292
  }
3309
4293
  }
3310
- function parseEvalScript(source, context = {}, owner, filename = "<eval>") {
4294
+ function parseEvalScript(source, context = {}, owner, filename = "<eval>", options = {}) {
3311
4295
  const compilation = new CompileScope(owner);
3312
4296
  try {
3313
4297
  const limit = owner?.budget.limits.stringLength;
@@ -3315,14 +4299,16 @@ function parseEvalScript(source, context = {}, owner, filename = "<eval>") {
3315
4299
  throw new SandboxError({ budget: "stringLength", current: source.length, limit });
3316
4300
  if (owner !== void 0) for (let index = 0; index < source.length; index++) owner.budget.visitNode();
3317
4301
  const grammar = { await: false, yield: false, strict: context.strict === true };
3318
- const parser = new Parser(tokenize(source, {
4302
+ const tokenOptions = {
3319
4303
  allowRegexLiterals: true,
3320
4304
  statementList: true,
3321
4305
  allowLegacyNumbers: true,
3322
4306
  allowLegacyEscapes: true,
3323
4307
  allowHtmlComments: true,
3324
4308
  compilation
3325
- }), source, compilation, "normal", {
4309
+ };
4310
+ const tokens = options.compactAst ? tokenizeCompact(source, tokenOptions, new CompactSourcePositions(source)) : tokenize(source, tokenOptions);
4311
+ const parser = new Parser(tokens, source, compilation, "normal", {
3326
4312
  grammar,
3327
4313
  newTarget: context.newTarget === true,
3328
4314
  superProperty: context.superProperty === true,
@@ -3332,7 +4318,10 @@ function parseEvalScript(source, context = {}, owner, filename = "<eval>") {
3332
4318
  await: false,
3333
4319
  strictAwait: true
3334
4320
  }, false);
3335
- const node = assignIds(parser.parseScript());
4321
+ if (options.compactAst) parser.enableCompactAst();
4322
+ const parsed = parser.parseScript();
4323
+ parser.finishAstStorage();
4324
+ const node = (options.compactAst ? assignCompactIds : assignIds)(parsed);
3336
4325
  if (source.includes("#")) validatePrivateNames(node, context.privateNames);
3337
4326
  for (const statement of node.body) {
3338
4327
  if (statement.type === "FunctionDeclaration") evalFunctionDeclarations.add(statement);
@@ -3394,7 +4383,7 @@ var ordinaryFunctionContext = {
3394
4383
  await: true
3395
4384
  };
3396
4385
  var Parser = class {
3397
- constructor(tokens, source, compilation, functionContext = "top-level", lexicalContext = { ...ordinaryFunctionContext, newTarget: false }, allowImportMeta = true, moduleSyntax) {
4386
+ constructor(tokens, source, compilation, functionContext = "top-level", lexicalContext = { ...ordinaryFunctionContext, newTarget: false }, allowImportMeta = true, moduleSyntax, importSpecifiers) {
3398
4387
  this.tokens = tokens;
3399
4388
  this.source = source;
3400
4389
  this.compilation = compilation;
@@ -3402,6 +4391,7 @@ var Parser = class {
3402
4391
  this.lexicalContext = lexicalContext;
3403
4392
  this.allowImportMeta = allowImportMeta;
3404
4393
  this.moduleSyntax = moduleSyntax;
4394
+ this.importSpecifiers = importSpecifiers;
3405
4395
  this.functionScopes.add(this.scopes[0]);
3406
4396
  }
3407
4397
  tokens;
@@ -3411,6 +4401,7 @@ var Parser = class {
3411
4401
  lexicalContext;
3412
4402
  allowImportMeta;
3413
4403
  moduleSyntax;
4404
+ importSpecifiers;
3414
4405
  index = 0;
3415
4406
  allowIn = true;
3416
4407
  breakableDepth = 0;
@@ -3425,6 +4416,14 @@ var Parser = class {
3425
4416
  varNames = /* @__PURE__ */ new WeakMap();
3426
4417
  sourceExportNames = /* @__PURE__ */ new Set();
3427
4418
  sourceLocalExports = /* @__PURE__ */ new Map();
4419
+ astStorage;
4420
+ enableCompactAst() {
4421
+ if (this.astStorage) throw new TypeError("Compiler body storage is already enabled.");
4422
+ this.astStorage = new CompactModuleAst(this.source);
4423
+ }
4424
+ finishAstStorage() {
4425
+ this.astStorage?.finish();
4426
+ }
3428
4427
  get position() {
3429
4428
  return (this.tokens[this.index] ?? this.tokens[this.tokens.length - 1]).start;
3430
4429
  }
@@ -3438,6 +4437,8 @@ var Parser = class {
3438
4437
  start: node.span.start.offset,
3439
4438
  end: node.span.end.offset
3440
4439
  });
4440
+ if (this.astStorage && node.type !== "ClassDeclaration" && node.type !== "ClassExpression" && node.body.span.end.offset - node.body.span.start.offset >= 512)
4441
+ node.body = this.astStorage.pack(node.body, true, true);
3441
4442
  return node;
3442
4443
  }
3443
4444
  parseDynamicParameters() {
@@ -3475,7 +4476,8 @@ var Parser = class {
3475
4476
  }
3476
4477
  if (this.isExportToken(token)) {
3477
4478
  const statement2 = this.parseSourceExport();
3478
- if (statement2 !== void 0) body.push(statement2);
4479
+ if (statement2 !== void 0)
4480
+ body.push(this.astStorage?.pack(statement2, false, true) ?? statement2);
3479
4481
  continue;
3480
4482
  }
3481
4483
  }
@@ -3484,26 +4486,29 @@ var Parser = class {
3484
4486
  while (statement.type !== "EmptyStatement" && this.consumePunctuator(";") !== void 0) {
3485
4487
  continue;
3486
4488
  }
4489
+ if (this.astStorage) body[body.length - 1] = this.astStorage.pack(statement, false, true);
3487
4490
  }
3488
4491
  for (const [name, identifier] of this.sourceLocalExports) {
3489
4492
  if (!this.scopes[0].has(name) && !this.varNames.get(this.scopes[0])?.has(name))
3490
4493
  throw new Error(`Export '${name}' is not defined at line ${identifier.span.start.line}, column ${identifier.span.start.column}.`);
3491
4494
  }
3492
4495
  const end = this.currentToken().end;
3493
- return {
4496
+ const module = {
3494
4497
  type: "Module",
3495
4498
  body,
3496
4499
  span: createSpan2(body[0]?.span.start ?? end, body[body.length - 1]?.span.end ?? end)
3497
4500
  };
4501
+ return this.astStorage?.pack(module, false, true) ?? module;
3498
4502
  }
3499
4503
  parseScript() {
3500
4504
  const body = this.parseStatementList(void 0, true);
3501
4505
  const end = this.currentToken().end;
3502
- return {
4506
+ const module = {
3503
4507
  type: "Module",
3504
4508
  body,
3505
4509
  span: createSpan2(body[0]?.span.start ?? end, body[body.length - 1]?.span.end ?? end)
3506
4510
  };
4511
+ return this.astStorage?.pack(module, false, true) ?? module;
3507
4512
  }
3508
4513
  parseExpressionOnly() {
3509
4514
  const expression = this.parseExpression({ allowSequence: true }).node;
@@ -3786,6 +4791,8 @@ var Parser = class {
3786
4791
  while (statement.type !== "EmptyStatement" && this.consumePunctuator(";") !== void 0) {
3787
4792
  if (++semicolons > 1) directivePrologue = false;
3788
4793
  }
4794
+ if (start === void 0 && this.astStorage)
4795
+ body[body.length - 1] = this.astStorage.pack(statement, false, true);
3789
4796
  }
3790
4797
  return body;
3791
4798
  }
@@ -4478,7 +5485,7 @@ var Parser = class {
4478
5485
  }
4479
5486
  this.index += 1;
4480
5487
  const source = createStringLiteral(sourceToken);
4481
- assertBareImportSpecifier(source);
5488
+ if (!this.importSpecifiers?.has(source.value)) assertBareImportSpecifier(source);
4482
5489
  return {
4483
5490
  type: "ImportDeclaration",
4484
5491
  specifiers,
@@ -7389,14 +8396,16 @@ function positionWithinRaw(base, raw, index) {
7389
8396
  }
7390
8397
  column += 1;
7391
8398
  }
7392
- return { line, column, offset };
8399
+ const position = { line, column, offset };
8400
+ return compactDerivedPosition(base, position) ?? position;
7393
8401
  }
7394
8402
  function rebasePosition(position, base) {
7395
- return {
8403
+ const rebased = {
7396
8404
  line: base.line + position.line - 1,
7397
8405
  column: position.line === 1 ? base.column + position.column - 1 : position.column,
7398
8406
  offset: base.offset + position.offset
7399
8407
  };
8408
+ return compactDerivedPosition(base, rebased) ?? rebased;
7400
8409
  }
7401
8410
  function isLiteralPropertyKey(token) {
7402
8411
  return token.type === "numeric" || token.type === "string";
@@ -7416,9 +8425,9 @@ function assertAllowedIdentifierReference(token, strict) {
7416
8425
  }
7417
8426
  }
7418
8427
  function createSpan2(start, end) {
7419
- return {
7420
- start: { ...start },
7421
- end: { ...end }
8428
+ return compactSourceSpan(start, end) ?? {
8429
+ start: isFrozenPosition(start) ? start : { ...start },
8430
+ end: isFrozenPosition(end) ? end : { ...end }
7422
8431
  };
7423
8432
  }
7424
8433
  function hasLineBreakBetween(left, right) {
@@ -7575,10 +8584,6 @@ var numericTypedArrayConstructors = {
7575
8584
  };
7576
8585
 
7577
8586
  export {
7578
- getFunctionLength,
7579
- boundIdentifiers,
7580
- containsParameterExpression,
7581
- hoistedVarDeclarations,
7582
8587
  internalSymbols,
7583
8588
  sandboxErrorNames,
7584
8589
  sandboxErrorTypes,
@@ -7596,18 +8601,22 @@ export {
7596
8601
  SandboxError,
7597
8602
  isFatalSandboxError,
7598
8603
  Budget,
7599
- allocateRegexSteps,
7600
- CompileScope,
7601
- RegexCompileGuard,
7602
- regexCompiledData,
7603
- tokenize,
7604
- collectComments,
7605
8604
  functionSources,
7606
8605
  functionStrictness,
7607
8606
  evalFunctionDeclarations,
7608
8607
  dynamicSourceRecords,
7609
8608
  dynamicNodeSources,
7610
8609
  dynamicValueSources,
8610
+ compactDynamicNodes,
8611
+ getFunctionLength,
8612
+ boundIdentifiers,
8613
+ containsParameterExpression,
8614
+ hoistedVarDeclarations,
8615
+ CompileScope,
8616
+ RegexCompileGuard,
8617
+ regexCompiledData,
8618
+ tokenize,
8619
+ collectComments,
7611
8620
  splitSourceLines,
7612
8621
  ParseError,
7613
8622
  formatParseError,
@@ -7636,4 +8645,4 @@ export {
7636
8645
  Float16Array2 as Float16Array,
7637
8646
  numericTypedArrayConstructors
7638
8647
  };
7639
- //# sourceMappingURL=chunk-ILYJBA2D.js.map
8648
+ //# sourceMappingURL=chunk-RYVHEOHM.js.map