@poe-platform/safe-bash 0.1.433 → 0.1.435

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 (35) hide show
  1. package/dist/safe-bash/browser.js +236 -90
  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 +325 -125
  24. package/dist/safe-bash/portable.js.map +3 -3
  25. package/dist/safe-bash/shell/arrays/state.d.ts.map +1 -1
  26. package/dist/safe-bash/shell/arrays/state.js +8 -2
  27. package/dist/safe-bash/shell/arrays/state.js.map +1 -1
  28. package/dist/safe-bash/shell/cleanup.d.ts +1 -1
  29. package/dist/safe-bash/shell/cleanup.d.ts.map +1 -1
  30. package/dist/safe-bash/shell/cleanup.js +7 -3
  31. package/dist/safe-bash/shell/cleanup.js.map +1 -1
  32. package/dist/safe-bash/shell/runtime.d.ts.map +1 -1
  33. package/dist/safe-bash/shell/runtime.js +21 -6
  34. package/dist/safe-bash/shell/runtime.js.map +1 -1
  35. 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
  ]);
@@ -10606,7 +10612,7 @@ var StateMonitor = class {
10606
10612
  monitors.set(raw, this);
10607
10613
  monitors.set(this.proxy, this);
10608
10614
  if (session.monitors) session.monitors.add(this);
10609
- else session.scope.register(async () => {
10615
+ else this.#retireCleanup = session.scope.register(async () => {
10610
10616
  await session.scope.drainWork();
10611
10617
  this.closeValues();
10612
10618
  });
@@ -10625,9 +10631,12 @@ var StateMonitor = class {
10625
10631
  #internalEnrollment;
10626
10632
  #restorations;
10627
10633
  #overlays;
10634
+ #retireCleanup;
10628
10635
  closeValues() {
10629
10636
  this.values.close();
10630
10637
  this.positionals.close();
10638
+ this.#retireCleanup?.();
10639
+ this.#retireCleanup = void 0;
10631
10640
  }
10632
10641
  changedValue(target, field, key) {
10633
10642
  if (field === "state") {
@@ -12595,7 +12604,7 @@ var InvocationCancellationOwner = class {
12595
12604
  this.finalized = new Promise((resolve) => {
12596
12605
  this.#resolveFinalized = resolve;
12597
12606
  });
12598
- parent.register(async () => {
12607
+ this.#retireCleanup = parent.register(async () => {
12599
12608
  this.requestClose();
12600
12609
  await this.finalized;
12601
12610
  });
@@ -12605,6 +12614,7 @@ var InvocationCancellationOwner = class {
12605
12614
  #failures;
12606
12615
  #outcomes;
12607
12616
  #publicPromise;
12617
+ #retireCleanup;
12608
12618
  #resolveFinalized;
12609
12619
  #admissionOpen = true;
12610
12620
  #boundary;
@@ -12681,6 +12691,7 @@ var InvocationCancellationOwner = class {
12681
12691
  this.#outcomes.discard(this.#record);
12682
12692
  this.#closeBoundary();
12683
12693
  this.#resolveFinalized();
12694
+ this.#retireCleanup();
12684
12695
  }
12685
12696
  }
12686
12697
  async #finishOnce(barrier, captured) {
@@ -12693,6 +12704,7 @@ var InvocationCancellationOwner = class {
12693
12704
  return selection;
12694
12705
  } finally {
12695
12706
  this.#resolveFinalized();
12707
+ this.#retireCleanup();
12696
12708
  }
12697
12709
  }
12698
12710
  #closeBoundary() {
@@ -14047,10 +14059,18 @@ var Runtime = class _Runtime {
14047
14059
  if (--file.references === 0 && this.outputFiles.get(path) === file) this.outputFiles.delete(path);
14048
14060
  };
14049
14061
  let target2;
14062
+ let outputScope;
14050
14063
  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);
14064
+ outputScope = io[invocationScope].child();
14065
+ target2 = await openFileOutput({ fs: this.fs, signal: this.signal, registerCleanup: (cleanup) => {
14066
+ outputScope.register(cleanup);
14067
+ } }, path, append ? "a" : "w", random ? incremental : void 0);
14052
14068
  } catch (error) {
14053
- release();
14069
+ try {
14070
+ await outputScope?.close();
14071
+ } finally {
14072
+ release();
14073
+ }
14054
14074
  throw error;
14055
14075
  }
14056
14076
  outputs.add(async (completion) => {
@@ -14066,7 +14086,11 @@ var Runtime = class _Runtime {
14066
14086
  }
14067
14087
  }
14068
14088
  } finally {
14069
- release();
14089
+ try {
14090
+ await outputScope?.close();
14091
+ } finally {
14092
+ release();
14093
+ }
14070
14094
  }
14071
14095
  });
14072
14096
  const output2 = this.budget.sink(target2.sink, this.signal);
@@ -14307,7 +14331,9 @@ var Runtime = class _Runtime {
14307
14331
  fs: this.fs,
14308
14332
  signal: this.commandSignal,
14309
14333
  executionScope: this.budget.executionScope,
14310
- registerCleanup: (cleanup) => scope.register(cleanup),
14334
+ registerCleanup: (cleanup) => {
14335
+ scope.register(cleanup);
14336
+ },
14311
14337
  invoke: (name3, args, options3) => {
14312
14338
  const invocation = this.invoke(name3, args, options3, context2, state, scope);
14313
14339
  void invocation.catch(() => void 0);
@@ -14914,7 +14940,9 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
14914
14940
  stdout: this.budget.sink(incoming.stdout, runtime.signal),
14915
14941
  stderr: this.budget.sink(incoming.stderr, runtime.signal),
14916
14942
  signal: this.commandSignal,
14917
- registerCleanup: (cleanup) => scope.register(cleanup),
14943
+ registerCleanup: (cleanup) => {
14944
+ scope.register(cleanup);
14945
+ },
14918
14946
  invoke: (name2, args, options3) => {
14919
14947
  const invocation = invocationOverride.current ? invocationOverride.current(name2, args, options3) : runtime.invoke(name2, args, options3, context2, child, scope);
14920
14948
  void invocation.catch(() => void 0);
@@ -18832,10 +18860,32 @@ function extendedSource(source2) {
18832
18860
  }
18833
18861
  return result2;
18834
18862
  }
18863
+ var NfaStorage = class {
18864
+ constructor(budget) {
18865
+ this.budget = budget;
18866
+ }
18867
+ budget;
18868
+ used = 0;
18869
+ reserve(bytes3) {
18870
+ this.budget.step(0);
18871
+ if (!Number.isSafeInteger(bytes3) || bytes3 < 0 || bytes3 > this.budget.maxBufferBytes - this.used) {
18872
+ throw new ProgramError("regular expression state buffer limit exceeded");
18873
+ }
18874
+ this.used += bytes3;
18875
+ }
18876
+ release(bytes3) {
18877
+ if (!Number.isSafeInteger(bytes3) || bytes3 < 0 || bytes3 > this.used) throw new ProgramError("invalid regular expression state accounting");
18878
+ this.used -= bytes3;
18879
+ }
18880
+ clear() {
18881
+ this.used = 0;
18882
+ }
18883
+ };
18835
18884
  var Pattern = class {
18836
18885
  groupCount;
18837
18886
  code = [];
18838
18887
  anchored;
18888
+ linear;
18839
18889
  constructor(source2, extended = true, ignoreCase = false) {
18840
18890
  if (source2.length > 8192) throw new ProgramError("regular expression exceeds 8192 bytes");
18841
18891
  if (!extended) source2 = extendedSource(source2);
@@ -19002,92 +19052,188 @@ var Pattern = class {
19002
19052
  };
19003
19053
  compile2(root);
19004
19054
  emit2({ kind: "match" });
19055
+ this.linear = this.code.every((instruction) => instruction.kind === "character" || instruction.kind === "begin" || instruction.kind === "end" || instruction.kind === "match");
19005
19056
  }
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];
19057
+ async find(text3, budget, from = 0) {
19058
+ await budget.checkpoint();
19059
+ let units = 0;
19060
+ const work = (count2 = 1) => {
19061
+ budget.step(count2);
19062
+ units += count2;
19063
+ if (units < 64) return void 0;
19064
+ units %= 64;
19065
+ return budget.checkpoint();
19066
+ };
19067
+ if (this.linear) {
19068
+ for (let start = from; start <= text3.length && (!this.anchored || start === 0); start++) {
19069
+ let position = start;
19070
+ for (const instruction of this.code) {
19071
+ const paused = work(2);
19072
+ if (paused) await paused;
19050
19073
  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;
19074
+ if (position >= text3.length || !instruction.accepts(text3[position])) break;
19075
+ position++;
19076
+ } else if (instruction.kind === "begin" && position !== 0 || instruction.kind === "end" && position !== text3.length) break;
19077
+ else if (instruction.kind === "match") {
19078
+ if (position - start > budget.maxBufferBytes) throw new ProgramError("text buffer limit exceeded");
19079
+ const copied = work(position - start);
19080
+ if (copied) await copied;
19081
+ const match = { start, end: position, groups: [text3.slice(start, position)] };
19082
+ await budget.checkpoint();
19083
+ return match;
19084
+ }
19085
+ }
19086
+ }
19087
+ return void 0;
19088
+ }
19089
+ const storage = new NfaStorage(budget);
19090
+ const positionDigits = String(text3.length).length;
19091
+ const instructionDigits = String(this.code.length).length;
19092
+ try {
19093
+ for (let start = from; start <= text3.length && (!this.anchored || start === 0); start++) {
19094
+ storage.reserve(256);
19095
+ const positions = /* @__PURE__ */ new Map([[start, [{ pc: 0, captures: [], bytes: 64 }]]]);
19096
+ let bestEnd;
19097
+ let bestCaptures = [];
19098
+ let bestBytes = 0;
19099
+ try {
19100
+ for (let position = start; positions.size && position <= text3.length; position++) {
19101
+ const advanced = work();
19102
+ if (advanced) await advanced;
19103
+ const pending = positions.get(position);
19104
+ if (!pending) continue;
19105
+ const reversed2 = work(pending.length);
19106
+ if (reversed2) await reversed2;
19107
+ pending.reverse();
19108
+ positions.delete(position);
19109
+ const visited = /* @__PURE__ */ new Set();
19110
+ let stateBytes = 0;
19111
+ const enqueue = (destination2, pc, captures, saveSlot) => {
19112
+ const length = saveSlot === void 0 ? captures.length : Math.max(captures.length, saveSlot + 1);
19113
+ const bytes3 = 64 + length * 8;
19114
+ const waiting = destination2 === position ? pending : positions.get(destination2);
19115
+ storage.reserve(bytes3 + (waiting ? 0 : 64));
19116
+ const saved = saveSlot === void 0 ? captures : [...captures];
19117
+ if (saveSlot !== void 0) saved[saveSlot] = position;
19118
+ const thread = { pc, captures: saved, bytes: bytes3 };
19119
+ if (waiting) waiting.push(thread);
19120
+ else positions.set(destination2, [thread]);
19121
+ };
19122
+ while (pending.length) {
19123
+ const paused = work();
19124
+ if (paused) await paused;
19125
+ const thread = pending.pop();
19126
+ try {
19127
+ let state = thread.pc;
19128
+ let bytes3 = 32;
19129
+ if (this.groupCount) {
19130
+ const joinedLength = Math.max(0, thread.captures.length - 1) + thread.captures.length * positionDigits;
19131
+ const stateLength = instructionDigits + 1 + joinedLength;
19132
+ const serialized2 = work(stateLength);
19133
+ if (serialized2) await serialized2;
19134
+ const reserved2 = 32 + joinedLength * 2 + 64 + stateLength * 2;
19135
+ storage.reserve(reserved2);
19136
+ state = `${thread.pc}:${thread.captures.join(",")}`;
19137
+ bytes3 = 64 + state.length * 2;
19138
+ storage.release(reserved2 - bytes3);
19139
+ } else storage.reserve(bytes3);
19140
+ if (visited.has(state)) {
19141
+ storage.release(bytes3);
19142
+ continue;
19143
+ }
19144
+ visited.add(state);
19145
+ stateBytes += bytes3;
19146
+ const instruction = this.code[thread.pc];
19147
+ if (instruction.kind === "character") {
19148
+ if (position < text3.length && instruction.accepts(text3[position])) enqueue(position + 1, thread.pc + 1, thread.captures);
19149
+ } else if (instruction.kind === "backreference") {
19150
+ const begin = thread.captures[instruction.index * 2];
19151
+ const end = thread.captures[instruction.index * 2 + 1];
19152
+ if (begin === void 0 || end === void 0 || position + end - begin > text3.length) continue;
19153
+ let matches3 = true;
19154
+ for (let offset = 0; offset < end - begin; offset++) {
19155
+ const compared = work();
19156
+ if (compared) await compared;
19157
+ const expected = text3[begin + offset];
19158
+ const actual = text3[position + offset];
19159
+ if (instruction.ignoreCase ? expected.toLowerCase() !== actual.toLowerCase() : expected !== actual) {
19160
+ matches3 = false;
19161
+ break;
19162
+ }
19163
+ }
19164
+ if (matches3) enqueue(position + end - begin, thread.pc + 1, thread.captures);
19165
+ } else if (instruction.kind === "match") {
19166
+ let preferred2 = bestEnd === void 0 || position > bestEnd;
19167
+ if (position === bestEnd) for (let index = 1; index <= this.groupCount; index++) {
19168
+ const compared = work();
19169
+ if (compared) await compared;
19170
+ const begin = thread.captures[index * 2];
19171
+ const end = thread.captures[index * 2 + 1];
19172
+ const priorBegin = bestCaptures[index * 2];
19173
+ const priorEnd = bestCaptures[index * 2 + 1];
19174
+ const length = begin === void 0 || end === void 0 ? -1 : end - begin;
19175
+ const priorLength = priorBegin === void 0 || priorEnd === void 0 ? -1 : priorEnd - priorBegin;
19176
+ if (length !== priorLength) {
19177
+ preferred2 = length > priorLength;
19178
+ break;
19179
+ }
19180
+ }
19181
+ if (preferred2) {
19182
+ const retained = 32 + thread.captures.length * 8;
19183
+ storage.reserve(retained);
19184
+ bestEnd = position;
19185
+ bestCaptures = thread.captures;
19186
+ storage.release(bestBytes);
19187
+ bestBytes = retained;
19188
+ }
19189
+ } else if (instruction.kind === "split") {
19190
+ enqueue(position, instruction.second, thread.captures);
19191
+ enqueue(position, instruction.first, thread.captures);
19192
+ } else if (instruction.kind === "jump") enqueue(position, instruction.target, thread.captures);
19193
+ else if (instruction.kind === "save") {
19194
+ const copied = work(Math.max(thread.captures.length, instruction.slot + 1));
19195
+ if (copied) await copied;
19196
+ enqueue(position, thread.pc + 1, thread.captures, instruction.slot);
19197
+ } else if (instruction.kind === "begin" ? position === 0 : position === text3.length) enqueue(position, thread.pc + 1, thread.captures);
19198
+ } finally {
19199
+ storage.release(thread.bytes);
19064
19200
  }
19065
19201
  }
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;
19202
+ visited.clear();
19203
+ storage.release(stateBytes + 64);
19204
+ }
19205
+ if (bestEnd !== void 0) {
19206
+ let characters = bestEnd - start;
19207
+ for (let index = 1; index <= this.groupCount; index++) {
19208
+ const counted = work();
19209
+ if (counted) await counted;
19210
+ const begin = bestCaptures[index * 2];
19211
+ const end = bestCaptures[index * 2 + 1];
19212
+ if (begin !== void 0 && end !== void 0) characters += end - begin;
19077
19213
  }
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 });
19214
+ const copied = work(characters);
19215
+ if (copied) await copied;
19216
+ storage.reserve(64 + (this.groupCount + 1) * 40 + characters * 2);
19217
+ const groups = [text3.slice(start, bestEnd)];
19218
+ for (let index = 1; index <= this.groupCount; index++) {
19219
+ const materialized = work();
19220
+ if (materialized) await materialized;
19221
+ const begin = bestCaptures[index * 2];
19222
+ const end = bestCaptures[index * 2 + 1];
19223
+ groups.push(begin === void 0 || end === void 0 ? void 0 : text3.slice(begin, end));
19224
+ }
19225
+ await budget.checkpoint();
19226
+ return { start, end: bestEnd, groups };
19227
+ }
19228
+ } finally {
19229
+ positions.clear();
19230
+ storage.clear();
19086
19231
  }
19087
19232
  }
19088
- if (best) return best;
19233
+ return void 0;
19234
+ } finally {
19235
+ storage.clear();
19089
19236
  }
19090
- return void 0;
19091
19237
  }
19092
19238
  };
19093
19239
  async function replacementLength(replacement, match, budget, available2) {
@@ -19149,7 +19295,7 @@ async function substitute(text3, pattern, replacement, budget, global, occurrenc
19149
19295
  while (search <= text3.length) {
19150
19296
  await budget.checkpoint();
19151
19297
  budget.step();
19152
- const match = pattern.find(text3, budget, search);
19298
+ const match = await pattern.find(text3, budget, search);
19153
19299
  if (!match) break;
19154
19300
  if (match.start === match.end && match.start === previousEnd) {
19155
19301
  search = match.end + 1;
@@ -19482,7 +19628,7 @@ async function execute(program, context2, files, quiet, budget, separator, outpu
19482
19628
  if (terminated) outputState.unterminatedFiles.delete(path);
19483
19629
  else outputState.unterminatedFiles.add(path);
19484
19630
  };
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;
19631
+ 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
19632
  for (let pc = 0; pc < program.length; ) {
19487
19633
  budget.step();
19488
19634
  await budget.checkpoint();
@@ -22920,7 +23066,7 @@ var AwkRuntime = class {
22920
23066
  let search = 0;
22921
23067
  while (search <= value2.length) {
22922
23068
  await this.budget.checkpoint();
22923
- const match = matcher.find(value2, this.budget, search);
23069
+ const match = await matcher.find(value2, this.budget, search);
22924
23070
  if (!match) break;
22925
23071
  if (match.start === match.end) {
22926
23072
  search = match.end + 1;
@@ -23022,7 +23168,7 @@ var AwkRuntime = class {
23022
23168
  case "string":
23023
23169
  return string(expression.value);
23024
23170
  case "regex":
23025
- return numeric(expression.pattern.find(this.record, this.budget) ? 1 : 0);
23171
+ return numeric(await expression.pattern.find(this.record, this.budget) ? 1 : 0);
23026
23172
  case "variable":
23027
23173
  return this.get(expression.name);
23028
23174
  case "field":
@@ -23064,7 +23210,7 @@ var AwkRuntime = class {
23064
23210
  if (operator === "&&" && !truth(left)) return numeric(0);
23065
23211
  if (operator === "||" && truth(left)) return numeric(1);
23066
23212
  if (operator === "~" || operator === "!~") {
23067
- const matched = (await this.regex(expression.right)).find(this.asText(left), this.budget) !== void 0;
23213
+ const matched = await (await this.regex(expression.right)).find(this.asText(left), this.budget) !== void 0;
23068
23214
  return numeric((operator === "~" ? matched : !matched) ? 1 : 0);
23069
23215
  }
23070
23216
  const right = await this.scalarExpression(expression.right);
@@ -23206,7 +23352,7 @@ var AwkRuntime = class {
23206
23352
  }
23207
23353
  if (name2 === "match") {
23208
23354
  const value2 = this.asText(await this.scalarExpression(args[0]));
23209
- const matched = (await this.regex(args[1])).find(value2, this.budget);
23355
+ const matched = await (await this.regex(args[1])).find(value2, this.budget);
23210
23356
  this.set("RSTART", numeric(matched ? matched.start + 1 : 0));
23211
23357
  this.set("RLENGTH", numeric(matched ? matched.end - matched.start : -1));
23212
23358
  return this.get("RSTART");
@@ -23684,6 +23830,7 @@ var Budget8 = class {
23684
23830
  signal;
23685
23831
  steps = 0;
23686
23832
  nextYield = 1024;
23833
+ lastYield = monotonicNow();
23687
23834
  inputBytes = 0;
23688
23835
  outputBytes = 0;
23689
23836
  results = 0;
@@ -23693,12 +23840,13 @@ var Budget8 = class {
23693
23840
  this.steps += count2;
23694
23841
  if (this.steps > this.limits.maxSteps) throw new JqLimitError("maxSteps");
23695
23842
  }
23696
- async tick() {
23697
- this.step();
23698
- if (this.steps >= this.nextYield) {
23699
- this.nextYield = this.steps + 1024;
23843
+ async tick(count2 = 1) {
23844
+ this.step(count2);
23845
+ if (this.steps >= this.nextYield || monotonicNow() - this.lastYield >= 25) {
23700
23846
  await yieldTurn(this.signal);
23701
23847
  this.signal.throwIfAborted();
23848
+ this.nextYield = this.steps + 1024;
23849
+ this.lastYield = monotonicNow();
23702
23850
  }
23703
23851
  }
23704
23852
  collection(size) {
@@ -23747,6 +23895,11 @@ function object() {
23747
23895
  function objectKeys(value2) {
23748
23896
  return keyOrders.get(value2)?.slice() ?? Object.keys(value2);
23749
23897
  }
23898
+ function* objectKeyIterator(value2) {
23899
+ const keys = keyOrders.get(value2);
23900
+ if (keys) yield* keys;
23901
+ else for (const key in value2) if (Object.hasOwn(value2, key)) yield key;
23902
+ }
23750
23903
  function objectSize(value2) {
23751
23904
  return keyOrders.get(value2)?.length ?? Object.keys(value2).length;
23752
23905
  }
@@ -24261,36 +24414,83 @@ function describe(value2, budget) {
24261
24414
  const text3 = bytes3.length < 15 ? bytes3.toString() : `${bytes3.subarray(0, 11).toString()}...`;
24262
24415
  return `${type(value2)} (${text3})`;
24263
24416
  }
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;
24417
+ async function stringCompare(left, right, budget) {
24418
+ await budget.tick(1 + Math.ceil(Math.min(left.length, right.length) / 32));
24419
+ let leftOffset = 0;
24420
+ let rightOffset = 0;
24421
+ let points = 0;
24422
+ while (leftOffset < left.length && rightOffset < right.length) {
24423
+ if (points++ % 32 === 0) await budget.tick(0);
24424
+ const leftPoint = left.codePointAt(leftOffset);
24425
+ const rightPoint = right.codePointAt(rightOffset);
24426
+ if (leftPoint !== rightPoint) return leftPoint < rightPoint ? -1 : 1;
24427
+ leftOffset += leftPoint > 65535 ? 2 : 1;
24428
+ rightOffset += rightPoint > 65535 ? 2 : 1;
24429
+ }
24430
+ return leftOffset < left.length ? 1 : rightOffset < right.length ? -1 : 0;
24431
+ }
24432
+ async function stableSort(items, budget, comparator) {
24433
+ await budget.tick(0);
24434
+ budget.collection(items.length);
24435
+ if (items.length < 2) return;
24436
+ await budget.tick(items.length);
24437
+ const scratch = new Array(items.length);
24438
+ let source2 = items;
24439
+ let target = scratch;
24440
+ for (let width = 1; width < items.length; width *= 2) {
24441
+ for (let start = 0; start < items.length; start += width * 2) {
24442
+ const middle = Math.min(start + width, items.length);
24443
+ const end = Math.min(start + width * 2, items.length);
24444
+ let left = start;
24445
+ let right = middle;
24446
+ for (let index = start; index < end; index++) {
24447
+ await budget.tick();
24448
+ if (left < middle && (right >= end || await comparator(source2[left], source2[right]) <= 0)) target[index] = source2[left++];
24449
+ else target[index] = source2[right++];
24450
+ }
24451
+ }
24452
+ const previous = source2;
24453
+ source2 = target;
24454
+ target = previous;
24455
+ }
24456
+ if (source2 !== items) for (let index = 0; index < items.length; index++) {
24457
+ await budget.tick();
24458
+ items[index] = source2[index];
24459
+ }
24460
+ }
24461
+ async function sortedKeys(value2, budget) {
24462
+ await budget.tick(0);
24463
+ const keys = [];
24464
+ for (const key of objectKeyIterator(value2)) {
24465
+ await budget.tick();
24466
+ budget.collection(keys.length + 1);
24467
+ keys.push(key);
24269
24468
  }
24270
- return Math.sign(leftPoints.length - rightPoints.length);
24469
+ await stableSort(keys, budget, (left, right) => stringCompare(left, right, budget));
24470
+ return keys;
24271
24471
  }
24272
- function compare2(left, right, budget) {
24273
- budget.step();
24472
+ async function compare2(left, right, budget) {
24473
+ await budget.tick();
24274
24474
  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
24475
  const difference = rank2(left) - rank2(right);
24276
24476
  if (difference) return Math.sign(difference);
24277
24477
  if (isNumber(left) && isNumber(right)) return compareNumbers(left, right, budget);
24478
+ if (typeof left === "string" && typeof right === "string") return stringCompare(left, right, budget);
24278
24479
  if (left === right && !Array.isArray(left) && !isObject(left)) return 0;
24279
- if (typeof left === "string" && typeof right === "string") return stringCompare(left, right);
24280
24480
  if (Array.isArray(left) && Array.isArray(right)) {
24281
24481
  for (let index = 0; index < Math.min(left.length, right.length); index++) {
24282
- const result2 = compare2(left[index], right[index], budget);
24482
+ const result2 = await compare2(left[index], right[index], budget);
24283
24483
  if (result2) return result2;
24284
24484
  }
24285
24485
  return Math.sign(left.length - right.length);
24286
24486
  }
24287
24487
  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);
24488
+ const keys = await sortedKeys(left, budget);
24489
+ const otherKeys = await sortedKeys(right, budget);
24490
+ const keyDifference = await compare2(keys, otherKeys, budget);
24291
24491
  if (keyDifference) return keyDifference;
24292
24492
  for (const key of keys) {
24293
- const result2 = compare2(left[key], right[key], budget);
24493
+ const result2 = await compare2(left[key], right[key], budget);
24294
24494
  if (result2) return result2;
24295
24495
  }
24296
24496
  }
@@ -24367,12 +24567,12 @@ function contains(value2, sought, budget) {
24367
24567
  if (isObject(value2) && isObject(sought)) return objectKeys(sought).every((key) => Object.hasOwn(value2, key) && contains(value2[key], sought[key], budget));
24368
24568
  return type(value2) === type(sought) && equal(value2, sought, budget);
24369
24569
  }
24370
- function binary(operator, left, right, budget) {
24570
+ async function binary(operator, left, right, budget) {
24371
24571
  budget.step();
24372
24572
  if (["==", "!=", "<", "<=", ">", ">="].includes(operator)) {
24373
24573
  if (operator === "==") return equal(left, right, budget);
24374
24574
  if (operator === "!=") return !equal(left, right, budget);
24375
- const order = compare2(left, right, budget);
24575
+ const order = await compare2(left, right, budget);
24376
24576
  switch (operator) {
24377
24577
  case "<":
24378
24578
  return order < 0;
@@ -24409,7 +24609,7 @@ function binary(operator, left, right, budget) {
24409
24609
  const result2 = copyObject(left);
24410
24610
  for (const key of objectKeys(right)) {
24411
24611
  const value2 = right[key];
24412
- put(result2, key, Object.hasOwn(left, key) && isObject(left[key]) && isObject(value2) ? binary("*", left[key], value2, budget) : value2);
24612
+ put(result2, key, Object.hasOwn(left, key) && isObject(left[key]) && isObject(value2) ? await binary("*", left[key], value2, budget) : value2);
24413
24613
  }
24414
24614
  budget.collection(objectKeys(result2).length);
24415
24615
  return result2;
@@ -24626,7 +24826,7 @@ var Interpreter = class _Interpreter {
24626
24826
  }
24627
24827
  for await (const right of this.run(ast.right, input3)) {
24628
24828
  for await (const left of this.run(ast.left, input3)) {
24629
- const result2 = binary(operator, left, right, this.budget);
24829
+ const result2 = await binary(operator, left, right, this.budget);
24630
24830
  this.budget.value(result2);
24631
24831
  yield result2;
24632
24832
  }
@@ -24731,7 +24931,7 @@ var Interpreter = class _Interpreter {
24731
24931
  for await (const path of this.paths(left, input3)) {
24732
24932
  let previous = result3;
24733
24933
  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);
24934
+ const assigned = operator === "=" ? value2 : operator === "//=" ? truth2(previous) ? previous : value2 : await binary(operator.slice(0, -1), previous, value2, this.budget);
24735
24935
  result3 = this.set(result3, path, assigned);
24736
24936
  this.budget.value(result3);
24737
24937
  }
@@ -24760,10 +24960,10 @@ var Interpreter = class _Interpreter {
24760
24960
  this.budget.value(result2);
24761
24961
  }
24762
24962
  }
24763
- deletions.sort((first, second) => -compare2(first, second, this.budget));
24963
+ await stableSort(deletions, this.budget, async (first, second) => -await compare2(first, second, this.budget));
24764
24964
  let lastDeletion;
24765
24965
  for (const path of deletions) {
24766
- if (!lastDeletion || compare2(lastDeletion, path, this.budget) !== 0) result2 = this.set(result2, path, deleted);
24966
+ if (!lastDeletion || await compare2(lastDeletion, path, this.budget) !== 0) result2 = this.set(result2, path, deleted);
24767
24967
  lastDeletion = path;
24768
24968
  }
24769
24969
  this.budget.value(result2);
@@ -24821,7 +25021,7 @@ var Interpreter = class _Interpreter {
24821
25021
  }
24822
25022
  if (name2 === "keys" || name2 === "keys_unsorted") {
24823
25023
  if (Array.isArray(input3)) yield input3.map((_, index) => index);
24824
- else if (isObject(input3)) yield name2 === "keys" ? objectKeys(input3).sort(stringCompare) : objectKeys(input3);
25024
+ else if (isObject(input3)) yield name2 === "keys" ? await sortedKeys(input3, budget) : objectKeys(input3);
24825
25025
  else throw new JqError("keys requires an object or array");
24826
25026
  return;
24827
25027
  }
@@ -24873,12 +25073,12 @@ var Interpreter = class _Interpreter {
24873
25073
  for (const [, item] of entries(input3, budget)) {
24874
25074
  await budget.tick();
24875
25075
  if (!first && separator !== null) {
24876
- if (typeof separator !== "string") binary("+", result2, separator, budget);
25076
+ if (typeof separator !== "string") await binary("+", result2, separator, budget);
24877
25077
  if (typeof separator !== "string") throw new JqError("join separator must be a string or null when used");
24878
25078
  append(separator, separatorBytes);
24879
25079
  }
24880
25080
  first = false;
24881
- if (isObject(item) || Array.isArray(item)) binary("+", result2, item, budget);
25081
+ if (isObject(item) || Array.isArray(item)) await binary("+", result2, item, budget);
24882
25082
  const text3 = item === null ? "" : typeof item === "string" ? item : stringify(item, budget);
24883
25083
  append(text3, budget.value(text3));
24884
25084
  }
@@ -25016,7 +25216,7 @@ var Interpreter = class _Interpreter {
25016
25216
  let result2 = null;
25017
25217
  for (const item of input3) {
25018
25218
  await budget.tick();
25019
- result2 = binary("+", result2, item, budget);
25219
+ result2 = await binary("+", result2, item, budget);
25020
25220
  budget.value(result2);
25021
25221
  }
25022
25222
  yield result2;
@@ -25031,7 +25231,7 @@ var Interpreter = class _Interpreter {
25031
25231
  if (keyBytes2 > budget.limits.maxValueBytes) throw new JqLimitError("maxValueBytes");
25032
25232
  keyed.push({ value: value2, key });
25033
25233
  }
25034
- keyed.sort((left, right) => compare2(left.key, right.key, budget));
25234
+ await stableSort(keyed, budget, (left, right) => compare2(left.key, right.key, budget));
25035
25235
  if (name2 === "min" || name2 === "min_by" || name2 === "max" || name2 === "max_by") {
25036
25236
  yield keyed[name2.startsWith("min") ? 0 : keyed.length - 1]?.value ?? null;
25037
25237
  return;
@@ -32014,7 +32214,7 @@ function createNlCommand(limits) {
32014
32214
  if (numbered) blanks = 0;
32015
32215
  } else if (current === "t") numbered = record4.length > 0;
32016
32216
  else if (current === "n") numbered = false;
32017
- else numbered = current.find(bytes3.toString("latin1"), budget) !== void 0;
32217
+ else numbered = await current.find(bytes3.toString("latin1"), budget) !== void 0;
32018
32218
  if (numbered) {
32019
32219
  if (number4 < -(1n << 63n) || number4 >= 1n << 63n) throw new UsageError("line number overflow");
32020
32220
  let label = number4.toString();