@poe-platform/safe-bash 0.1.434 → 0.1.436

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 (40) hide show
  1. package/dist/safe-bash/browser.js +350 -113
  2. package/dist/safe-bash/browser.js.map +3 -3
  3. package/dist/safe-bash/commands/stream-format/nl.js +1 -1
  4. package/dist/safe-bash/commands/stream-format/nl.js.map +1 -1
  5. package/dist/safe-bash/commands/structured/interpreter.js +10 -10
  6. package/dist/safe-bash/commands/structured/interpreter.js.map +1 -1
  7. package/dist/safe-bash/commands/structured/limits.d.ts +3 -1
  8. package/dist/safe-bash/commands/structured/limits.d.ts.map +1 -1
  9. package/dist/safe-bash/commands/structured/limits.js +16 -5
  10. package/dist/safe-bash/commands/structured/limits.js.map +1 -1
  11. package/dist/safe-bash/commands/structured/values.d.ts +5 -3
  12. package/dist/safe-bash/commands/structured/values.d.ts.map +1 -1
  13. package/dist/safe-bash/commands/structured/values.js +73 -21
  14. package/dist/safe-bash/commands/structured/values.js.map +1 -1
  15. package/dist/safe-bash/commands/text-programs/awk-runtime.js +4 -4
  16. package/dist/safe-bash/commands/text-programs/awk-runtime.js.map +1 -1
  17. package/dist/safe-bash/commands/text-programs/regex.d.ts +2 -1
  18. package/dist/safe-bash/commands/text-programs/regex.d.ts.map +1 -1
  19. package/dist/safe-bash/commands/text-programs/regex.js +230 -93
  20. package/dist/safe-bash/commands/text-programs/regex.js.map +1 -1
  21. package/dist/safe-bash/commands/text-programs/sed.js +1 -1
  22. package/dist/safe-bash/commands/text-programs/sed.js.map +1 -1
  23. package/dist/safe-bash/portable.js +439 -148
  24. package/dist/safe-bash/portable.js.map +3 -3
  25. package/dist/safe-bash/shell/arrays/state.d.ts +6 -1
  26. package/dist/safe-bash/shell/arrays/state.d.ts.map +1 -1
  27. package/dist/safe-bash/shell/arrays/state.js +30 -3
  28. package/dist/safe-bash/shell/arrays/state.js.map +1 -1
  29. package/dist/safe-bash/shell/cleanup.d.ts +1 -1
  30. package/dist/safe-bash/shell/cleanup.d.ts.map +1 -1
  31. package/dist/safe-bash/shell/cleanup.js +7 -3
  32. package/dist/safe-bash/shell/cleanup.js.map +1 -1
  33. package/dist/safe-bash/shell/getopts.d.ts +10 -1
  34. package/dist/safe-bash/shell/getopts.d.ts.map +1 -1
  35. package/dist/safe-bash/shell/getopts.js +55 -6
  36. package/dist/safe-bash/shell/getopts.js.map +1 -1
  37. package/dist/safe-bash/shell/runtime.d.ts.map +1 -1
  38. package/dist/safe-bash/shell/runtime.js +69 -27
  39. package/dist/safe-bash/shell/runtime.js.map +1 -1
  40. package/package.json +2 -2
@@ -9222,7 +9222,7 @@ var InvocationScope = class _InvocationScope {
9222
9222
  failures;
9223
9223
  parent;
9224
9224
  #children = /* @__PURE__ */ new Set();
9225
- #callbacks = [];
9225
+ #callbacks = /* @__PURE__ */ new Map();
9226
9226
  #finalizers = [];
9227
9227
  #work = /* @__PURE__ */ new Set();
9228
9228
  #controller = new AbortController();
@@ -9249,7 +9249,11 @@ var InvocationScope = class _InvocationScope {
9249
9249
  register(cleanup) {
9250
9250
  this.assertOpen();
9251
9251
  if (typeof cleanup !== "function") throw new TypeError("Cleanup must be callable");
9252
- this.#callbacks.push(cleanup);
9252
+ const registration = /* @__PURE__ */ Symbol();
9253
+ this.#callbacks.set(registration, cleanup);
9254
+ return () => {
9255
+ this.#callbacks.delete(registration);
9256
+ };
9253
9257
  }
9254
9258
  run(operation2) {
9255
9259
  this.assertOpen();
@@ -9282,9 +9286,11 @@ var InvocationScope = class _InvocationScope {
9282
9286
  close() {
9283
9287
  if (!this.#drain) {
9284
9288
  this.#drain = Promise.resolve().then(async () => {
9289
+ const callbacks = [...this.#callbacks.values()];
9290
+ this.#callbacks.clear();
9285
9291
  try {
9286
9292
  await Promise.all([
9287
- ...this.#callbacks.splice(0).map((cleanup) => this.cleanup(cleanup)),
9293
+ ...callbacks.map((cleanup) => this.cleanup(cleanup)),
9288
9294
  ...[...this.#children].map((child) => child.close()),
9289
9295
  ...this.#work
9290
9296
  ]);
@@ -9311,6 +9317,39 @@ function throwCleanupFailures(failures) {
9311
9317
 
9312
9318
  // packages/safe-bash/src/shell/getopts.ts
9313
9319
  init_platform();
9320
+ var ownedInputs = /* @__PURE__ */ new WeakMap();
9321
+ function getoptsInputAllocationSize(argumentsCount) {
9322
+ return { bytes: 256 + argumentsCount * 8, slots: argumentsCount + 2 };
9323
+ }
9324
+ async function createGetoptsInput(args, allocation, controls2) {
9325
+ const work = new ScanWork(controls2);
9326
+ if (!Array.isArray(args)) throw new GetoptsError("INVALID_INPUT", "Getopts requires an argument array");
9327
+ const length = args.length;
9328
+ if (length > work.maxArguments) throw new GetoptsError("ARGUMENT_LIMIT", "Getopts argument limit exceeded");
9329
+ const size = getoptsInputAllocationSize(length);
9330
+ const reservation = allocation?.reserve(size.bytes, size.slots);
9331
+ try {
9332
+ const snapshot = [];
9333
+ for (let index = 0; index < length; index++) {
9334
+ const waiting = work.step();
9335
+ if (waiting) await waiting;
9336
+ snapshot.push(args[index]);
9337
+ }
9338
+ await work.flush();
9339
+ if (args.length !== length) throw new GetoptsError("INVALID_INPUT", "Getopts argument extent changed during admission");
9340
+ const input3 = Object.freeze({ args: Object.freeze(snapshot) });
9341
+ reservation?.commit(input3);
9342
+ ownedInputs.set(input3, {});
9343
+ return input3;
9344
+ } catch (error) {
9345
+ try {
9346
+ reservation?.release();
9347
+ } catch (cleanup) {
9348
+ throw new AggregateError([error, cleanup], "Getopts input allocation and release failed");
9349
+ }
9350
+ throw error;
9351
+ }
9352
+ }
9314
9353
  var GetoptsError = class extends Error {
9315
9354
  constructor(code, message3) {
9316
9355
  super(message3);
@@ -9375,6 +9414,9 @@ var ScanWork = class {
9375
9414
  check() {
9376
9415
  this.signal?.throwIfAborted();
9377
9416
  }
9417
+ get inputBytes() {
9418
+ return this.bytes;
9419
+ }
9378
9420
  step() {
9379
9421
  this.check();
9380
9422
  if (this.steps === this.maxSteps) throw new GetoptsError("STEP_LIMIT", "Getopts work step limit exceeded");
@@ -9431,19 +9473,25 @@ async function validateString(value2, work, optstring = false) {
9431
9473
  else work.addBytes(3);
9432
9474
  }
9433
9475
  }
9434
- async function scanGetopts(state, optstring, args, options3) {
9476
+ async function scanGetopts(state, optstring, input3, options3) {
9435
9477
  if (!record2(options3) || typeof options3.reportErrors !== "boolean") throw new GetoptsError("INVALID_INPUT", "Getopts requires explicit diagnostic policy and work controls");
9436
9478
  const work = new ScanWork(options3.work);
9437
9479
  const original = cloneGetoptsState(state);
9480
+ const owned = ownedInputs.get(input3);
9481
+ const args = owned ? input3.args : input3;
9438
9482
  if (!Array.isArray(args)) throw new GetoptsError("INVALID_INPUT", "Getopts requires an argument array");
9439
9483
  if (args.length > work.maxArguments) throw new GetoptsError("ARGUMENT_LIMIT", "Getopts argument limit exceeded");
9440
9484
  const starting = work.step();
9441
9485
  if (starting) await starting;
9442
9486
  await validateString(optstring, work, true);
9443
- for (let argument2 = 0; argument2 < args.length; argument2++) {
9444
- const waiting = work.step();
9445
- if (waiting) await waiting;
9446
- await validateString(args[argument2], work);
9487
+ const specificationBytes = work.inputBytes;
9488
+ if (owned?.bytes !== void 0) work.addBytes(owned.bytes);
9489
+ else {
9490
+ for (let argument2 = 0; argument2 < args.length; argument2++) {
9491
+ const waiting = work.step();
9492
+ if (waiting) await waiting;
9493
+ await validateString(args[argument2], work);
9494
+ }
9447
9495
  }
9448
9496
  const silent = optstring.startsWith(":");
9449
9497
  const specification = new Int8Array(128).fill(-1);
@@ -9459,6 +9507,7 @@ async function scanGetopts(state, optstring, args, options3) {
9459
9507
  const waiting = work.step();
9460
9508
  if (waiting) await waiting;
9461
9509
  await work.flush();
9510
+ if (owned) owned.bytes = work.inputBytes - specificationBytes;
9462
9511
  return { state: active === void 0 ? { index } : { index, active: { ...active } }, kind, status: kind === "end" ? 1 : 0, option: option2, optind: index, argument: argument2, diagnostic: diagnostic4 };
9463
9512
  };
9464
9513
  const end = () => {
@@ -10606,7 +10655,7 @@ var StateMonitor = class {
10606
10655
  monitors.set(raw, this);
10607
10656
  monitors.set(this.proxy, this);
10608
10657
  if (session.monitors) session.monitors.add(this);
10609
- else session.scope.register(async () => {
10658
+ else this.#retireCleanup = session.scope.register(async () => {
10610
10659
  await session.scope.drainWork();
10611
10660
  this.closeValues();
10612
10661
  });
@@ -10625,18 +10674,46 @@ var StateMonitor = class {
10625
10674
  #internalEnrollment;
10626
10675
  #restorations;
10627
10676
  #overlays;
10677
+ #retireCleanup;
10678
+ #positionalRevision = {};
10679
+ #getoptsInput;
10628
10680
  closeValues() {
10629
10681
  this.values.close();
10630
10682
  this.positionals.close();
10683
+ this.invalidateGetoptsInput();
10684
+ this.#retireCleanup?.();
10685
+ this.#retireCleanup = void 0;
10686
+ }
10687
+ get positionalRevision() {
10688
+ return this.#positionalRevision;
10689
+ }
10690
+ get getoptsInput() {
10691
+ return this.#getoptsInput?.input;
10692
+ }
10693
+ retainGetoptsInput(revision, input3, allocation) {
10694
+ this.session.scope.assertOpen();
10695
+ if (revision !== this.#positionalRevision) return false;
10696
+ this.#getoptsInput?.allocation.close();
10697
+ this.#getoptsInput = { input: input3, allocation };
10698
+ return true;
10699
+ }
10700
+ invalidateGetoptsInput() {
10701
+ this.#getoptsInput?.allocation.close();
10702
+ this.#getoptsInput = void 0;
10703
+ this.#positionalRevision = {};
10631
10704
  }
10632
10705
  changedValue(target, field, key) {
10633
10706
  if (field === "state") {
10634
10707
  if (key === "variables") this.values.invalidate();
10635
- if (key === "positional") this.positionals.invalidate();
10708
+ if (key === "positional") {
10709
+ this.positionals.invalidate();
10710
+ this.invalidateGetoptsInput();
10711
+ }
10636
10712
  } else if (field === "variables" && (this.raw.variables === target || this.raw.variables === this.#wrapped.get(target))) {
10637
10713
  this.values.invalidate(String(key));
10638
10714
  } else if (field === "positional" && (this.raw.positional === target || this.raw.positional === this.#wrapped.get(target))) {
10639
10715
  this.positionals.invalidate();
10716
+ this.invalidateGetoptsInput();
10640
10717
  }
10641
10718
  }
10642
10719
  internalOwner() {
@@ -12595,7 +12672,7 @@ var InvocationCancellationOwner = class {
12595
12672
  this.finalized = new Promise((resolve) => {
12596
12673
  this.#resolveFinalized = resolve;
12597
12674
  });
12598
- parent.register(async () => {
12675
+ this.#retireCleanup = parent.register(async () => {
12599
12676
  this.requestClose();
12600
12677
  await this.finalized;
12601
12678
  });
@@ -12605,6 +12682,7 @@ var InvocationCancellationOwner = class {
12605
12682
  #failures;
12606
12683
  #outcomes;
12607
12684
  #publicPromise;
12685
+ #retireCleanup;
12608
12686
  #resolveFinalized;
12609
12687
  #admissionOpen = true;
12610
12688
  #boundary;
@@ -12681,6 +12759,7 @@ var InvocationCancellationOwner = class {
12681
12759
  this.#outcomes.discard(this.#record);
12682
12760
  this.#closeBoundary();
12683
12761
  this.#resolveFinalized();
12762
+ this.#retireCleanup();
12684
12763
  }
12685
12764
  }
12686
12765
  async #finishOnce(barrier, captured) {
@@ -12693,6 +12772,7 @@ var InvocationCancellationOwner = class {
12693
12772
  return selection;
12694
12773
  } finally {
12695
12774
  this.#resolveFinalized();
12775
+ this.#retireCleanup();
12696
12776
  }
12697
12777
  }
12698
12778
  #closeBoundary() {
@@ -14047,10 +14127,18 @@ var Runtime = class _Runtime {
14047
14127
  if (--file.references === 0 && this.outputFiles.get(path) === file) this.outputFiles.delete(path);
14048
14128
  };
14049
14129
  let target2;
14130
+ let outputScope;
14050
14131
  try {
14051
- target2 = await openFileOutput({ fs: this.fs, signal: this.signal, registerCleanup: (cleanup) => io[invocationScope].register(cleanup) }, path, append ? "a" : "w", random ? incremental : void 0);
14132
+ outputScope = io[invocationScope].child();
14133
+ target2 = await openFileOutput({ fs: this.fs, signal: this.signal, registerCleanup: (cleanup) => {
14134
+ outputScope.register(cleanup);
14135
+ } }, path, append ? "a" : "w", random ? incremental : void 0);
14052
14136
  } catch (error) {
14053
- release();
14137
+ try {
14138
+ await outputScope?.close();
14139
+ } finally {
14140
+ release();
14141
+ }
14054
14142
  throw error;
14055
14143
  }
14056
14144
  outputs.add(async (completion) => {
@@ -14066,7 +14154,11 @@ var Runtime = class _Runtime {
14066
14154
  }
14067
14155
  }
14068
14156
  } finally {
14069
- release();
14157
+ try {
14158
+ await outputScope?.close();
14159
+ } finally {
14160
+ release();
14161
+ }
14070
14162
  }
14071
14163
  });
14072
14164
  const output2 = this.budget.sink(target2.sink, this.signal);
@@ -14307,7 +14399,9 @@ var Runtime = class _Runtime {
14307
14399
  fs: this.fs,
14308
14400
  signal: this.commandSignal,
14309
14401
  executionScope: this.budget.executionScope,
14310
- registerCleanup: (cleanup) => scope.register(cleanup),
14402
+ registerCleanup: (cleanup) => {
14403
+ scope.register(cleanup);
14404
+ },
14311
14405
  invoke: (name3, args, options3) => {
14312
14406
  const invocation = this.invoke(name3, args, options3, context2, state, scope);
14313
14407
  void invocation.catch(() => void 0);
@@ -14914,7 +15008,9 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
14914
15008
  stdout: this.budget.sink(incoming.stdout, runtime.signal),
14915
15009
  stderr: this.budget.sink(incoming.stderr, runtime.signal),
14916
15010
  signal: this.commandSignal,
14917
- registerCleanup: (cleanup) => scope.register(cleanup),
15011
+ registerCleanup: (cleanup) => {
15012
+ scope.register(cleanup);
15013
+ },
14918
15014
  invoke: (name2, args, options3) => {
14919
15015
  const invocation = invocationOverride.current ? invocationOverride.current(name2, args, options3) : runtime.invoke(name2, args, options3, context2, child, scope);
14920
15016
  void invocation.catch(() => void 0);
@@ -15492,26 +15588,49 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
15492
15588
  }
15493
15589
  const optstring = context2.args[offset];
15494
15590
  const name2 = context2.args[offset + 1];
15495
- const args = context2.args.length > offset + 2 ? context2.args.slice(offset + 2) : state.positional;
15496
- if (args.length > fields2) this.budget.fail("maxExpansionFields");
15497
- for (let index = 0; index < args.length; index++) {
15498
- this.signal.throwIfAborted();
15499
- admit2(args[index]);
15500
- if ((index + 1) % 128 === 0) await checkpoint();
15501
- }
15502
- const maxBytes = saturatedProduct(bytes3, saturatedSum(args.length, 1));
15503
- const maxSteps = saturatedSum(saturatedProduct(maxBytes, 2), saturatedSum(args.length, 2));
15504
- state.getopts ??= cloneGetoptsBinding(state);
15591
+ const explicit = context2.args.length > offset + 2;
15592
+ const monitor = explicit ? void 0 : stateMonitor(state);
15593
+ const revision = monitor?.positionalRevision;
15594
+ const supplied = explicit ? context2.args.slice(offset + 2) : state.positional;
15595
+ if (supplied.length > fields2) this.budget.fail("maxExpansionFields");
15596
+ const maxBytes = saturatedProduct(bytes3, saturatedSum(supplied.length, 1));
15597
+ const maxSteps = saturatedSum(saturatedProduct(maxBytes, 2), saturatedSum(supplied.length, 2));
15598
+ const work = { maxArguments: fields2, maxBytes, maxSteps, yieldEvery: 128, signal: this.signal, checkpoint };
15599
+ let input3 = monitor?.getoptsInput;
15600
+ let allocation;
15505
15601
  let result2;
15506
15602
  try {
15507
- result2 = await scanGetopts(state.getopts.cursor, optstring, args, {
15508
- reportErrors: state.variables.OPTERR === void 0 || state.variables.OPTERR === "" || decimalIndex(state.variables.OPTERR) !== 0,
15509
- work: { maxArguments: fields2, maxBytes, maxSteps, yieldEvery: 128, signal: this.signal, checkpoint }
15510
- });
15511
- } catch (error) {
15603
+ if (!input3 && monitor) {
15604
+ const size = getoptsInputAllocationSize(supplied.length);
15605
+ const arena = this.budget.values;
15606
+ const usage2 = arena.usage;
15607
+ if (size.bytes + 64 <= arena.maximumBytes - usage2.bytes && size.slots + 1 <= arena.maximumSlots - usage2.slots) {
15608
+ allocation = arena.scope();
15609
+ input3 = await createGetoptsInput(supplied, allocation, work);
15610
+ }
15611
+ }
15612
+ const args = input3?.args ?? supplied;
15613
+ if (!input3 || allocation) for (let index = 0; index < args.length; index++) {
15614
+ this.signal.throwIfAborted();
15615
+ admit2(args[index]);
15616
+ if ((index + 1) % 128 === 0) await checkpoint();
15617
+ }
15618
+ state.getopts ??= cloneGetoptsBinding(state);
15619
+ try {
15620
+ result2 = await scanGetopts(state.getopts.cursor, optstring, input3 ?? args, {
15621
+ reportErrors: state.variables.OPTERR === void 0 || state.variables.OPTERR === "" || decimalIndex(state.variables.OPTERR) !== 0,
15622
+ work
15623
+ });
15624
+ } catch (error) {
15625
+ this.signal.throwIfAborted();
15626
+ if (error instanceof GetoptsError && (error.code === "NON_ASCII_OPTION" || error.code === "INVALID_INPUT")) throw new CommandFailure(`getopts: ${error.message}`, 2);
15627
+ throw error;
15628
+ }
15512
15629
  this.signal.throwIfAborted();
15513
- if (error instanceof GetoptsError && (error.code === "NON_ASCII_OPTION" || error.code === "INVALID_INPUT")) throw new CommandFailure(`getopts: ${error.message}`, 2);
15514
- throw error;
15630
+ if (monitor && monitor.positionalRevision !== revision) throw new CommandFailure("getopts: positional arguments changed during validation", 2);
15631
+ if (allocation && monitor.retainGetoptsInput(revision, input3, allocation)) allocation = void 0;
15632
+ } finally {
15633
+ allocation?.close();
15515
15634
  }
15516
15635
  this.signal.throwIfAborted();
15517
15636
  state.getopts.cursor = result2.state;
@@ -18832,10 +18951,32 @@ function extendedSource(source2) {
18832
18951
  }
18833
18952
  return result2;
18834
18953
  }
18954
+ var NfaStorage = class {
18955
+ constructor(budget) {
18956
+ this.budget = budget;
18957
+ }
18958
+ budget;
18959
+ used = 0;
18960
+ reserve(bytes3) {
18961
+ this.budget.step(0);
18962
+ if (!Number.isSafeInteger(bytes3) || bytes3 < 0 || bytes3 > this.budget.maxBufferBytes - this.used) {
18963
+ throw new ProgramError("regular expression state buffer limit exceeded");
18964
+ }
18965
+ this.used += bytes3;
18966
+ }
18967
+ release(bytes3) {
18968
+ if (!Number.isSafeInteger(bytes3) || bytes3 < 0 || bytes3 > this.used) throw new ProgramError("invalid regular expression state accounting");
18969
+ this.used -= bytes3;
18970
+ }
18971
+ clear() {
18972
+ this.used = 0;
18973
+ }
18974
+ };
18835
18975
  var Pattern = class {
18836
18976
  groupCount;
18837
18977
  code = [];
18838
18978
  anchored;
18979
+ linear;
18839
18980
  constructor(source2, extended = true, ignoreCase = false) {
18840
18981
  if (source2.length > 8192) throw new ProgramError("regular expression exceeds 8192 bytes");
18841
18982
  if (!extended) source2 = extendedSource(source2);
@@ -19002,92 +19143,188 @@ var Pattern = class {
19002
19143
  };
19003
19144
  compile2(root);
19004
19145
  emit2({ kind: "match" });
19146
+ this.linear = this.code.every((instruction) => instruction.kind === "character" || instruction.kind === "begin" || instruction.kind === "end" || instruction.kind === "match");
19005
19147
  }
19006
- find(text3, budget, from = 0) {
19007
- for (let start = from; start <= text3.length && (!this.anchored || start === 0); start++) {
19008
- const positions = /* @__PURE__ */ new Map([[start, [{ pc: 0, captures: [] }]]]);
19009
- let best;
19010
- let bestCaptures = [];
19011
- let queued = 1;
19012
- const preferCaptures = (captures) => {
19013
- for (let index = 1; index <= this.groupCount; index++) {
19014
- const begin = captures[index * 2];
19015
- const end = captures[index * 2 + 1];
19016
- const priorBegin = bestCaptures[index * 2];
19017
- const priorEnd = bestCaptures[index * 2 + 1];
19018
- const length = begin === void 0 || end === void 0 ? -1 : end - begin;
19019
- const priorLength = priorBegin === void 0 || priorEnd === void 0 ? -1 : priorEnd - priorBegin;
19020
- if (length !== priorLength) return length > priorLength;
19021
- }
19022
- return false;
19023
- };
19024
- for (let position = start; positions.size && position <= text3.length; position++) {
19025
- budget.step();
19026
- const pending = positions.get(position)?.reverse() ?? [];
19027
- positions.delete(position);
19028
- queued -= pending.length;
19029
- const visited = /* @__PURE__ */ new Set();
19030
- let stateBytes = 0;
19031
- const enqueue = (destination2, thread) => {
19032
- if (destination2 === position) pending.push(thread);
19033
- else {
19034
- const waiting = positions.get(destination2);
19035
- if (waiting) waiting.push(thread);
19036
- else positions.set(destination2, [thread]);
19037
- queued++;
19038
- }
19039
- if ((queued + pending.length) * (32 + this.groupCount * 16) > budget.maxBufferBytes) throw new ProgramError("regular expression state buffer limit exceeded");
19040
- };
19041
- while (pending.length) {
19042
- budget.step();
19043
- const thread = pending.pop();
19044
- const state = this.groupCount ? `${thread.pc}:${thread.captures.join(",")}` : thread.pc;
19045
- if (visited.has(state)) continue;
19046
- visited.add(state);
19047
- stateBytes += typeof state === "string" ? state.length * 2 + 32 : 16;
19048
- if (stateBytes > budget.maxBufferBytes) throw new ProgramError("regular expression state buffer limit exceeded");
19049
- const instruction = this.code[thread.pc];
19148
+ async find(text3, budget, from = 0) {
19149
+ await budget.checkpoint();
19150
+ let units = 0;
19151
+ const work = (count2 = 1) => {
19152
+ budget.step(count2);
19153
+ units += count2;
19154
+ if (units < 64) return void 0;
19155
+ units %= 64;
19156
+ return budget.checkpoint();
19157
+ };
19158
+ if (this.linear) {
19159
+ for (let start = from; start <= text3.length && (!this.anchored || start === 0); start++) {
19160
+ let position = start;
19161
+ for (const instruction of this.code) {
19162
+ const paused = work(2);
19163
+ if (paused) await paused;
19050
19164
  if (instruction.kind === "character") {
19051
- if (position < text3.length && instruction.accepts(text3[position])) enqueue(position + 1, { pc: thread.pc + 1, captures: thread.captures });
19052
- } else if (instruction.kind === "backreference") {
19053
- const begin = thread.captures[instruction.index * 2];
19054
- const end = thread.captures[instruction.index * 2 + 1];
19055
- if (begin === void 0 || end === void 0 || position + end - begin > text3.length) continue;
19056
- let matches3 = true;
19057
- for (let offset = 0; offset < end - begin; offset++) {
19058
- budget.step();
19059
- const expected = text3[begin + offset];
19060
- const actual = text3[position + offset];
19061
- if (instruction.ignoreCase ? expected.toLowerCase() !== actual.toLowerCase() : expected !== actual) {
19062
- matches3 = false;
19063
- break;
19165
+ if (position >= text3.length || !instruction.accepts(text3[position])) break;
19166
+ position++;
19167
+ } else if (instruction.kind === "begin" && position !== 0 || instruction.kind === "end" && position !== text3.length) break;
19168
+ else if (instruction.kind === "match") {
19169
+ if (position - start > budget.maxBufferBytes) throw new ProgramError("text buffer limit exceeded");
19170
+ const copied = work(position - start);
19171
+ if (copied) await copied;
19172
+ const match = { start, end: position, groups: [text3.slice(start, position)] };
19173
+ await budget.checkpoint();
19174
+ return match;
19175
+ }
19176
+ }
19177
+ }
19178
+ return void 0;
19179
+ }
19180
+ const storage = new NfaStorage(budget);
19181
+ const positionDigits = String(text3.length).length;
19182
+ const instructionDigits = String(this.code.length).length;
19183
+ try {
19184
+ for (let start = from; start <= text3.length && (!this.anchored || start === 0); start++) {
19185
+ storage.reserve(256);
19186
+ const positions = /* @__PURE__ */ new Map([[start, [{ pc: 0, captures: [], bytes: 64 }]]]);
19187
+ let bestEnd;
19188
+ let bestCaptures = [];
19189
+ let bestBytes = 0;
19190
+ try {
19191
+ for (let position = start; positions.size && position <= text3.length; position++) {
19192
+ const advanced = work();
19193
+ if (advanced) await advanced;
19194
+ const pending = positions.get(position);
19195
+ if (!pending) continue;
19196
+ const reversed2 = work(pending.length);
19197
+ if (reversed2) await reversed2;
19198
+ pending.reverse();
19199
+ positions.delete(position);
19200
+ const visited = /* @__PURE__ */ new Set();
19201
+ let stateBytes = 0;
19202
+ const enqueue = (destination2, pc, captures, saveSlot) => {
19203
+ const length = saveSlot === void 0 ? captures.length : Math.max(captures.length, saveSlot + 1);
19204
+ const bytes3 = 64 + length * 8;
19205
+ const waiting = destination2 === position ? pending : positions.get(destination2);
19206
+ storage.reserve(bytes3 + (waiting ? 0 : 64));
19207
+ const saved = saveSlot === void 0 ? captures : [...captures];
19208
+ if (saveSlot !== void 0) saved[saveSlot] = position;
19209
+ const thread = { pc, captures: saved, bytes: bytes3 };
19210
+ if (waiting) waiting.push(thread);
19211
+ else positions.set(destination2, [thread]);
19212
+ };
19213
+ while (pending.length) {
19214
+ const paused = work();
19215
+ if (paused) await paused;
19216
+ const thread = pending.pop();
19217
+ try {
19218
+ let state = thread.pc;
19219
+ let bytes3 = 32;
19220
+ if (this.groupCount) {
19221
+ const joinedLength = Math.max(0, thread.captures.length - 1) + thread.captures.length * positionDigits;
19222
+ const stateLength = instructionDigits + 1 + joinedLength;
19223
+ const serialized2 = work(stateLength);
19224
+ if (serialized2) await serialized2;
19225
+ const reserved2 = 32 + joinedLength * 2 + 64 + stateLength * 2;
19226
+ storage.reserve(reserved2);
19227
+ state = `${thread.pc}:${thread.captures.join(",")}`;
19228
+ bytes3 = 64 + state.length * 2;
19229
+ storage.release(reserved2 - bytes3);
19230
+ } else storage.reserve(bytes3);
19231
+ if (visited.has(state)) {
19232
+ storage.release(bytes3);
19233
+ continue;
19234
+ }
19235
+ visited.add(state);
19236
+ stateBytes += bytes3;
19237
+ const instruction = this.code[thread.pc];
19238
+ if (instruction.kind === "character") {
19239
+ if (position < text3.length && instruction.accepts(text3[position])) enqueue(position + 1, thread.pc + 1, thread.captures);
19240
+ } else if (instruction.kind === "backreference") {
19241
+ const begin = thread.captures[instruction.index * 2];
19242
+ const end = thread.captures[instruction.index * 2 + 1];
19243
+ if (begin === void 0 || end === void 0 || position + end - begin > text3.length) continue;
19244
+ let matches3 = true;
19245
+ for (let offset = 0; offset < end - begin; offset++) {
19246
+ const compared = work();
19247
+ if (compared) await compared;
19248
+ const expected = text3[begin + offset];
19249
+ const actual = text3[position + offset];
19250
+ if (instruction.ignoreCase ? expected.toLowerCase() !== actual.toLowerCase() : expected !== actual) {
19251
+ matches3 = false;
19252
+ break;
19253
+ }
19254
+ }
19255
+ if (matches3) enqueue(position + end - begin, thread.pc + 1, thread.captures);
19256
+ } else if (instruction.kind === "match") {
19257
+ let preferred2 = bestEnd === void 0 || position > bestEnd;
19258
+ if (position === bestEnd) for (let index = 1; index <= this.groupCount; index++) {
19259
+ const compared = work();
19260
+ if (compared) await compared;
19261
+ const begin = thread.captures[index * 2];
19262
+ const end = thread.captures[index * 2 + 1];
19263
+ const priorBegin = bestCaptures[index * 2];
19264
+ const priorEnd = bestCaptures[index * 2 + 1];
19265
+ const length = begin === void 0 || end === void 0 ? -1 : end - begin;
19266
+ const priorLength = priorBegin === void 0 || priorEnd === void 0 ? -1 : priorEnd - priorBegin;
19267
+ if (length !== priorLength) {
19268
+ preferred2 = length > priorLength;
19269
+ break;
19270
+ }
19271
+ }
19272
+ if (preferred2) {
19273
+ const retained = 32 + thread.captures.length * 8;
19274
+ storage.reserve(retained);
19275
+ bestEnd = position;
19276
+ bestCaptures = thread.captures;
19277
+ storage.release(bestBytes);
19278
+ bestBytes = retained;
19279
+ }
19280
+ } else if (instruction.kind === "split") {
19281
+ enqueue(position, instruction.second, thread.captures);
19282
+ enqueue(position, instruction.first, thread.captures);
19283
+ } else if (instruction.kind === "jump") enqueue(position, instruction.target, thread.captures);
19284
+ else if (instruction.kind === "save") {
19285
+ const copied = work(Math.max(thread.captures.length, instruction.slot + 1));
19286
+ if (copied) await copied;
19287
+ enqueue(position, thread.pc + 1, thread.captures, instruction.slot);
19288
+ } else if (instruction.kind === "begin" ? position === 0 : position === text3.length) enqueue(position, thread.pc + 1, thread.captures);
19289
+ } finally {
19290
+ storage.release(thread.bytes);
19064
19291
  }
19065
19292
  }
19066
- if (matches3) enqueue(position + end - begin, { pc: thread.pc + 1, captures: thread.captures });
19067
- } else if (instruction.kind === "match") {
19068
- if (!best || position > best.end || position === best.end && preferCaptures(thread.captures)) {
19069
- const groups = [text3.slice(start, position)];
19070
- for (let index = 1; index <= this.groupCount; index++) {
19071
- const begin = thread.captures[index * 2];
19072
- const end = thread.captures[index * 2 + 1];
19073
- groups.push(begin === void 0 || end === void 0 ? void 0 : text3.slice(begin, end));
19074
- }
19075
- best = { start, end: position, groups };
19076
- bestCaptures = thread.captures;
19293
+ visited.clear();
19294
+ storage.release(stateBytes + 64);
19295
+ }
19296
+ if (bestEnd !== void 0) {
19297
+ let characters = bestEnd - start;
19298
+ for (let index = 1; index <= this.groupCount; index++) {
19299
+ const counted = work();
19300
+ if (counted) await counted;
19301
+ const begin = bestCaptures[index * 2];
19302
+ const end = bestCaptures[index * 2 + 1];
19303
+ if (begin !== void 0 && end !== void 0) characters += end - begin;
19304
+ }
19305
+ const copied = work(characters);
19306
+ if (copied) await copied;
19307
+ storage.reserve(64 + (this.groupCount + 1) * 40 + characters * 2);
19308
+ const groups = [text3.slice(start, bestEnd)];
19309
+ for (let index = 1; index <= this.groupCount; index++) {
19310
+ const materialized = work();
19311
+ if (materialized) await materialized;
19312
+ const begin = bestCaptures[index * 2];
19313
+ const end = bestCaptures[index * 2 + 1];
19314
+ groups.push(begin === void 0 || end === void 0 ? void 0 : text3.slice(begin, end));
19077
19315
  }
19078
- } else if (instruction.kind === "split") {
19079
- pending.push({ pc: instruction.second, captures: thread.captures }, { pc: instruction.first, captures: thread.captures });
19080
- } else if (instruction.kind === "jump") pending.push({ pc: instruction.target, captures: thread.captures });
19081
- else if (instruction.kind === "save") {
19082
- const captures = [...thread.captures];
19083
- captures[instruction.slot] = position;
19084
- pending.push({ pc: thread.pc + 1, captures });
19085
- } else if (instruction.kind === "begin" ? position === 0 : position === text3.length) pending.push({ pc: thread.pc + 1, captures: thread.captures });
19316
+ await budget.checkpoint();
19317
+ return { start, end: bestEnd, groups };
19318
+ }
19319
+ } finally {
19320
+ positions.clear();
19321
+ storage.clear();
19086
19322
  }
19087
19323
  }
19088
- if (best) return best;
19324
+ return void 0;
19325
+ } finally {
19326
+ storage.clear();
19089
19327
  }
19090
- return void 0;
19091
19328
  }
19092
19329
  };
19093
19330
  async function replacementLength(replacement, match, budget, available2) {
@@ -19149,7 +19386,7 @@ async function substitute(text3, pattern, replacement, budget, global, occurrenc
19149
19386
  while (search <= text3.length) {
19150
19387
  await budget.checkpoint();
19151
19388
  budget.step();
19152
- const match = pattern.find(text3, budget, search);
19389
+ const match = await pattern.find(text3, budget, search);
19153
19390
  if (!match) break;
19154
19391
  if (match.start === match.end && match.start === previousEnd) {
19155
19392
  search = match.end + 1;
@@ -19482,7 +19719,7 @@ async function execute(program, context2, files, quiet, budget, separator, outpu
19482
19719
  if (terminated) outputState.unterminatedFiles.delete(path);
19483
19720
  else outputState.unterminatedFiles.add(path);
19484
19721
  };
19485
- const matches3 = async (address) => address.kind === "number" ? number4 === address.number : address.kind === "last" ? (await peekNext()).done === true : getPattern(address.pattern).find(pattern, budget) !== void 0;
19722
+ const matches3 = async (address) => address.kind === "number" ? number4 === address.number : address.kind === "last" ? (await peekNext()).done === true : await getPattern(address.pattern).find(pattern, budget) !== void 0;
19486
19723
  for (let pc = 0; pc < program.length; ) {
19487
19724
  budget.step();
19488
19725
  await budget.checkpoint();
@@ -22920,7 +23157,7 @@ var AwkRuntime = class {
22920
23157
  let search = 0;
22921
23158
  while (search <= value2.length) {
22922
23159
  await this.budget.checkpoint();
22923
- const match = matcher.find(value2, this.budget, search);
23160
+ const match = await matcher.find(value2, this.budget, search);
22924
23161
  if (!match) break;
22925
23162
  if (match.start === match.end) {
22926
23163
  search = match.end + 1;
@@ -23022,7 +23259,7 @@ var AwkRuntime = class {
23022
23259
  case "string":
23023
23260
  return string(expression.value);
23024
23261
  case "regex":
23025
- return numeric(expression.pattern.find(this.record, this.budget) ? 1 : 0);
23262
+ return numeric(await expression.pattern.find(this.record, this.budget) ? 1 : 0);
23026
23263
  case "variable":
23027
23264
  return this.get(expression.name);
23028
23265
  case "field":
@@ -23064,7 +23301,7 @@ var AwkRuntime = class {
23064
23301
  if (operator === "&&" && !truth(left)) return numeric(0);
23065
23302
  if (operator === "||" && truth(left)) return numeric(1);
23066
23303
  if (operator === "~" || operator === "!~") {
23067
- const matched = (await this.regex(expression.right)).find(this.asText(left), this.budget) !== void 0;
23304
+ const matched = await (await this.regex(expression.right)).find(this.asText(left), this.budget) !== void 0;
23068
23305
  return numeric((operator === "~" ? matched : !matched) ? 1 : 0);
23069
23306
  }
23070
23307
  const right = await this.scalarExpression(expression.right);
@@ -23206,7 +23443,7 @@ var AwkRuntime = class {
23206
23443
  }
23207
23444
  if (name2 === "match") {
23208
23445
  const value2 = this.asText(await this.scalarExpression(args[0]));
23209
- const matched = (await this.regex(args[1])).find(value2, this.budget);
23446
+ const matched = await (await this.regex(args[1])).find(value2, this.budget);
23210
23447
  this.set("RSTART", numeric(matched ? matched.start + 1 : 0));
23211
23448
  this.set("RLENGTH", numeric(matched ? matched.end - matched.start : -1));
23212
23449
  return this.get("RSTART");
@@ -23684,6 +23921,7 @@ var Budget8 = class {
23684
23921
  signal;
23685
23922
  steps = 0;
23686
23923
  nextYield = 1024;
23924
+ lastYield = monotonicNow();
23687
23925
  inputBytes = 0;
23688
23926
  outputBytes = 0;
23689
23927
  results = 0;
@@ -23693,12 +23931,13 @@ var Budget8 = class {
23693
23931
  this.steps += count2;
23694
23932
  if (this.steps > this.limits.maxSteps) throw new JqLimitError("maxSteps");
23695
23933
  }
23696
- async tick() {
23697
- this.step();
23698
- if (this.steps >= this.nextYield) {
23699
- this.nextYield = this.steps + 1024;
23934
+ async tick(count2 = 1) {
23935
+ this.step(count2);
23936
+ if (this.steps >= this.nextYield || monotonicNow() - this.lastYield >= 25) {
23700
23937
  await yieldTurn(this.signal);
23701
23938
  this.signal.throwIfAborted();
23939
+ this.nextYield = this.steps + 1024;
23940
+ this.lastYield = monotonicNow();
23702
23941
  }
23703
23942
  }
23704
23943
  collection(size) {
@@ -23747,6 +23986,11 @@ function object() {
23747
23986
  function objectKeys(value2) {
23748
23987
  return keyOrders.get(value2)?.slice() ?? Object.keys(value2);
23749
23988
  }
23989
+ function* objectKeyIterator(value2) {
23990
+ const keys = keyOrders.get(value2);
23991
+ if (keys) yield* keys;
23992
+ else for (const key in value2) if (Object.hasOwn(value2, key)) yield key;
23993
+ }
23750
23994
  function objectSize(value2) {
23751
23995
  return keyOrders.get(value2)?.length ?? Object.keys(value2).length;
23752
23996
  }
@@ -24261,36 +24505,83 @@ function describe(value2, budget) {
24261
24505
  const text3 = bytes3.length < 15 ? bytes3.toString() : `${bytes3.subarray(0, 11).toString()}...`;
24262
24506
  return `${type(value2)} (${text3})`;
24263
24507
  }
24264
- function stringCompare(left, right) {
24265
- const leftPoints = Array.from(left, (character) => character.codePointAt(0));
24266
- const rightPoints = Array.from(right, (character) => character.codePointAt(0));
24267
- for (let index = 0; index < Math.min(leftPoints.length, rightPoints.length); index++) {
24268
- if (leftPoints[index] !== rightPoints[index]) return leftPoints[index] < rightPoints[index] ? -1 : 1;
24508
+ async function stringCompare(left, right, budget) {
24509
+ await budget.tick(1 + Math.ceil(Math.min(left.length, right.length) / 32));
24510
+ let leftOffset = 0;
24511
+ let rightOffset = 0;
24512
+ let points = 0;
24513
+ while (leftOffset < left.length && rightOffset < right.length) {
24514
+ if (points++ % 32 === 0) await budget.tick(0);
24515
+ const leftPoint = left.codePointAt(leftOffset);
24516
+ const rightPoint = right.codePointAt(rightOffset);
24517
+ if (leftPoint !== rightPoint) return leftPoint < rightPoint ? -1 : 1;
24518
+ leftOffset += leftPoint > 65535 ? 2 : 1;
24519
+ rightOffset += rightPoint > 65535 ? 2 : 1;
24520
+ }
24521
+ return leftOffset < left.length ? 1 : rightOffset < right.length ? -1 : 0;
24522
+ }
24523
+ async function stableSort(items, budget, comparator) {
24524
+ await budget.tick(0);
24525
+ budget.collection(items.length);
24526
+ if (items.length < 2) return;
24527
+ await budget.tick(items.length);
24528
+ const scratch = new Array(items.length);
24529
+ let source2 = items;
24530
+ let target = scratch;
24531
+ for (let width = 1; width < items.length; width *= 2) {
24532
+ for (let start = 0; start < items.length; start += width * 2) {
24533
+ const middle = Math.min(start + width, items.length);
24534
+ const end = Math.min(start + width * 2, items.length);
24535
+ let left = start;
24536
+ let right = middle;
24537
+ for (let index = start; index < end; index++) {
24538
+ await budget.tick();
24539
+ if (left < middle && (right >= end || await comparator(source2[left], source2[right]) <= 0)) target[index] = source2[left++];
24540
+ else target[index] = source2[right++];
24541
+ }
24542
+ }
24543
+ const previous = source2;
24544
+ source2 = target;
24545
+ target = previous;
24546
+ }
24547
+ if (source2 !== items) for (let index = 0; index < items.length; index++) {
24548
+ await budget.tick();
24549
+ items[index] = source2[index];
24550
+ }
24551
+ }
24552
+ async function sortedKeys(value2, budget) {
24553
+ await budget.tick(0);
24554
+ const keys = [];
24555
+ for (const key of objectKeyIterator(value2)) {
24556
+ await budget.tick();
24557
+ budget.collection(keys.length + 1);
24558
+ keys.push(key);
24269
24559
  }
24270
- return Math.sign(leftPoints.length - rightPoints.length);
24560
+ await stableSort(keys, budget, (left, right) => stringCompare(left, right, budget));
24561
+ return keys;
24271
24562
  }
24272
- function compare2(left, right, budget) {
24273
- budget.step();
24563
+ async function compare2(left, right, budget) {
24564
+ await budget.tick();
24274
24565
  const rank2 = (value2) => value2 === null ? 0 : value2 === false ? 1 : value2 === true ? 2 : isNumber(value2) ? 3 : typeof value2 === "string" ? 4 : Array.isArray(value2) ? 5 : 6;
24275
24566
  const difference = rank2(left) - rank2(right);
24276
24567
  if (difference) return Math.sign(difference);
24277
24568
  if (isNumber(left) && isNumber(right)) return compareNumbers(left, right, budget);
24569
+ if (typeof left === "string" && typeof right === "string") return stringCompare(left, right, budget);
24278
24570
  if (left === right && !Array.isArray(left) && !isObject(left)) return 0;
24279
- if (typeof left === "string" && typeof right === "string") return stringCompare(left, right);
24280
24571
  if (Array.isArray(left) && Array.isArray(right)) {
24281
24572
  for (let index = 0; index < Math.min(left.length, right.length); index++) {
24282
- const result2 = compare2(left[index], right[index], budget);
24573
+ const result2 = await compare2(left[index], right[index], budget);
24283
24574
  if (result2) return result2;
24284
24575
  }
24285
24576
  return Math.sign(left.length - right.length);
24286
24577
  }
24287
24578
  if (isObject(left) && isObject(right)) {
24288
- const keys = objectKeys(left).sort(stringCompare);
24289
- const otherKeys = objectKeys(right).sort(stringCompare);
24290
- const keyDifference = compare2(keys, otherKeys, budget);
24579
+ const keys = await sortedKeys(left, budget);
24580
+ const otherKeys = await sortedKeys(right, budget);
24581
+ const keyDifference = await compare2(keys, otherKeys, budget);
24291
24582
  if (keyDifference) return keyDifference;
24292
24583
  for (const key of keys) {
24293
- const result2 = compare2(left[key], right[key], budget);
24584
+ const result2 = await compare2(left[key], right[key], budget);
24294
24585
  if (result2) return result2;
24295
24586
  }
24296
24587
  }
@@ -24367,12 +24658,12 @@ function contains(value2, sought, budget) {
24367
24658
  if (isObject(value2) && isObject(sought)) return objectKeys(sought).every((key) => Object.hasOwn(value2, key) && contains(value2[key], sought[key], budget));
24368
24659
  return type(value2) === type(sought) && equal(value2, sought, budget);
24369
24660
  }
24370
- function binary(operator, left, right, budget) {
24661
+ async function binary(operator, left, right, budget) {
24371
24662
  budget.step();
24372
24663
  if (["==", "!=", "<", "<=", ">", ">="].includes(operator)) {
24373
24664
  if (operator === "==") return equal(left, right, budget);
24374
24665
  if (operator === "!=") return !equal(left, right, budget);
24375
- const order = compare2(left, right, budget);
24666
+ const order = await compare2(left, right, budget);
24376
24667
  switch (operator) {
24377
24668
  case "<":
24378
24669
  return order < 0;
@@ -24409,7 +24700,7 @@ function binary(operator, left, right, budget) {
24409
24700
  const result2 = copyObject(left);
24410
24701
  for (const key of objectKeys(right)) {
24411
24702
  const value2 = right[key];
24412
- put(result2, key, Object.hasOwn(left, key) && isObject(left[key]) && isObject(value2) ? binary("*", left[key], value2, budget) : value2);
24703
+ put(result2, key, Object.hasOwn(left, key) && isObject(left[key]) && isObject(value2) ? await binary("*", left[key], value2, budget) : value2);
24413
24704
  }
24414
24705
  budget.collection(objectKeys(result2).length);
24415
24706
  return result2;
@@ -24626,7 +24917,7 @@ var Interpreter = class _Interpreter {
24626
24917
  }
24627
24918
  for await (const right of this.run(ast.right, input3)) {
24628
24919
  for await (const left of this.run(ast.left, input3)) {
24629
- const result2 = binary(operator, left, right, this.budget);
24920
+ const result2 = await binary(operator, left, right, this.budget);
24630
24921
  this.budget.value(result2);
24631
24922
  yield result2;
24632
24923
  }
@@ -24731,7 +25022,7 @@ var Interpreter = class _Interpreter {
24731
25022
  for await (const path of this.paths(left, input3)) {
24732
25023
  let previous = result3;
24733
25024
  for (const key of path) previous = indexValue(previous, key);
24734
- const assigned = operator === "=" ? value2 : operator === "//=" ? truth2(previous) ? previous : value2 : binary(operator.slice(0, -1), previous, value2, this.budget);
25025
+ const assigned = operator === "=" ? value2 : operator === "//=" ? truth2(previous) ? previous : value2 : await binary(operator.slice(0, -1), previous, value2, this.budget);
24735
25026
  result3 = this.set(result3, path, assigned);
24736
25027
  this.budget.value(result3);
24737
25028
  }
@@ -24760,10 +25051,10 @@ var Interpreter = class _Interpreter {
24760
25051
  this.budget.value(result2);
24761
25052
  }
24762
25053
  }
24763
- deletions.sort((first, second) => -compare2(first, second, this.budget));
25054
+ await stableSort(deletions, this.budget, async (first, second) => -await compare2(first, second, this.budget));
24764
25055
  let lastDeletion;
24765
25056
  for (const path of deletions) {
24766
- if (!lastDeletion || compare2(lastDeletion, path, this.budget) !== 0) result2 = this.set(result2, path, deleted);
25057
+ if (!lastDeletion || await compare2(lastDeletion, path, this.budget) !== 0) result2 = this.set(result2, path, deleted);
24767
25058
  lastDeletion = path;
24768
25059
  }
24769
25060
  this.budget.value(result2);
@@ -24821,7 +25112,7 @@ var Interpreter = class _Interpreter {
24821
25112
  }
24822
25113
  if (name2 === "keys" || name2 === "keys_unsorted") {
24823
25114
  if (Array.isArray(input3)) yield input3.map((_, index) => index);
24824
- else if (isObject(input3)) yield name2 === "keys" ? objectKeys(input3).sort(stringCompare) : objectKeys(input3);
25115
+ else if (isObject(input3)) yield name2 === "keys" ? await sortedKeys(input3, budget) : objectKeys(input3);
24825
25116
  else throw new JqError("keys requires an object or array");
24826
25117
  return;
24827
25118
  }
@@ -24873,12 +25164,12 @@ var Interpreter = class _Interpreter {
24873
25164
  for (const [, item] of entries(input3, budget)) {
24874
25165
  await budget.tick();
24875
25166
  if (!first && separator !== null) {
24876
- if (typeof separator !== "string") binary("+", result2, separator, budget);
25167
+ if (typeof separator !== "string") await binary("+", result2, separator, budget);
24877
25168
  if (typeof separator !== "string") throw new JqError("join separator must be a string or null when used");
24878
25169
  append(separator, separatorBytes);
24879
25170
  }
24880
25171
  first = false;
24881
- if (isObject(item) || Array.isArray(item)) binary("+", result2, item, budget);
25172
+ if (isObject(item) || Array.isArray(item)) await binary("+", result2, item, budget);
24882
25173
  const text3 = item === null ? "" : typeof item === "string" ? item : stringify(item, budget);
24883
25174
  append(text3, budget.value(text3));
24884
25175
  }
@@ -25016,7 +25307,7 @@ var Interpreter = class _Interpreter {
25016
25307
  let result2 = null;
25017
25308
  for (const item of input3) {
25018
25309
  await budget.tick();
25019
- result2 = binary("+", result2, item, budget);
25310
+ result2 = await binary("+", result2, item, budget);
25020
25311
  budget.value(result2);
25021
25312
  }
25022
25313
  yield result2;
@@ -25031,7 +25322,7 @@ var Interpreter = class _Interpreter {
25031
25322
  if (keyBytes2 > budget.limits.maxValueBytes) throw new JqLimitError("maxValueBytes");
25032
25323
  keyed.push({ value: value2, key });
25033
25324
  }
25034
- keyed.sort((left, right) => compare2(left.key, right.key, budget));
25325
+ await stableSort(keyed, budget, (left, right) => compare2(left.key, right.key, budget));
25035
25326
  if (name2 === "min" || name2 === "min_by" || name2 === "max" || name2 === "max_by") {
25036
25327
  yield keyed[name2.startsWith("min") ? 0 : keyed.length - 1]?.value ?? null;
25037
25328
  return;
@@ -32014,7 +32305,7 @@ function createNlCommand(limits) {
32014
32305
  if (numbered) blanks = 0;
32015
32306
  } else if (current === "t") numbered = record4.length > 0;
32016
32307
  else if (current === "n") numbered = false;
32017
- else numbered = current.find(bytes3.toString("latin1"), budget) !== void 0;
32308
+ else numbered = await current.find(bytes3.toString("latin1"), budget) !== void 0;
32018
32309
  if (numbered) {
32019
32310
  if (number4 < -(1n << 63n) || number4 >= 1n << 63n) throw new UsageError("line number overflow");
32020
32311
  let label = number4.toString();