@poe-platform/safe-bash 0.1.527 → 0.1.528

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.
@@ -40879,14 +40879,16 @@ var controlNames = /* @__PURE__ */ new Set([
40879
40879
  "LC_CTYPE"
40880
40880
  ]);
40881
40881
  var OwnedText = class {
40882
- constructor(value2, bytes3, admission) {
40882
+ constructor(value2, bytes3, admission, rawValue) {
40883
40883
  this.value = value2;
40884
40884
  this.bytes = bytes3;
40885
40885
  this.admission = admission;
40886
+ this.rawValue = rawValue;
40886
40887
  }
40887
40888
  value;
40888
40889
  bytes;
40889
40890
  admission;
40891
+ rawValue;
40890
40892
  references = 1;
40891
40893
  retain() {
40892
40894
  if (this.references === Number.MAX_SAFE_INTEGER) throw new ArrayFailure("reference capacity is not representable");
@@ -40912,6 +40914,38 @@ async function textToken(owner, value2, signal) {
40912
40914
  const admission = owner.reserve({ payload: bytes3, metadata: 32, work: 4 });
40913
40915
  return new OwnedText(value2, bytes3, admission);
40914
40916
  }
40917
+ async function valueToken(owner, value2, signal) {
40918
+ if (typeof value2 === "string") return textToken(owner, value2, signal);
40919
+ const bytes3 = shellValueByteLength(value2);
40920
+ const temporary = owner.reserve({ payload: bytes3 * 3, metadata: 64, work: 4 });
40921
+ try {
40922
+ const input3 = shellValueBytes(value2);
40923
+ const decoder2 = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
40924
+ let text3 = "";
40925
+ for (let offset = 0; offset < bytes3; offset += 1024) {
40926
+ const end = Math.min(bytes3, offset + 1024);
40927
+ owner.reserve({ work: end - offset }).release();
40928
+ await owner.ledger.checkpoint(signal, end - offset);
40929
+ if (text3 !== void 0) try {
40930
+ text3 += decoder2.decode(input3.subarray(offset, end), { stream: end < bytes3 });
40931
+ } catch (error) {
40932
+ if (!(error instanceof TypeError) || "code" in error && error.code !== "ERR_ENCODING_INVALID_ENCODED_DATA") throw error;
40933
+ text3 = void 0;
40934
+ }
40935
+ }
40936
+ if (text3 !== void 0) return await textToken(owner, text3, signal);
40937
+ const admission = owner.reserve({ payload: bytes3 * 4, metadata: 128, work: 4 });
40938
+ try {
40939
+ const raw = shellValueFromBytes(input3);
40940
+ return new OwnedText(shellValueText(raw), bytes3, admission, raw);
40941
+ } catch (error) {
40942
+ admission.release();
40943
+ throw error;
40944
+ }
40945
+ } finally {
40946
+ temporary.release();
40947
+ }
40948
+ }
40915
40949
  var IndexedBinding = class _IndexedBinding {
40916
40950
  constructor(owner) {
40917
40951
  this.owner = owner;
@@ -41148,6 +41182,116 @@ var BindingStore = class _BindingStore {
41148
41182
  }
41149
41183
  };
41150
41184
 
41185
+ // packages/safe-bash/src/shell/mapfile.ts
41186
+ init_platform();
41187
+ var MapfileUsageError = class extends Error {
41188
+ constructor(message3, status2) {
41189
+ super(message3);
41190
+ this.status = status2;
41191
+ }
41192
+ status;
41193
+ };
41194
+ async function mapfileOptions(context2, work, allocation) {
41195
+ const options3 = { name: "MAPFILE", strip: false, delimiter: 10, count: 0, skip: 0, origin: 0, preserve: false, callback: void 0, quantum: 5e3 };
41196
+ const args = getCommandArguments(context2);
41197
+ let cursor = 0;
41198
+ const numeric4 = async (text3, maximum) => {
41199
+ let value2 = 0;
41200
+ let index = 0;
41201
+ const whitespace2 = (code) => code === 32 || code >= 9 && code <= 13;
41202
+ while (index < text3.length && whitespace2(text3.charCodeAt(index))) {
41203
+ const pending = stringCheckpoint(work);
41204
+ if (pending) await pending;
41205
+ index++;
41206
+ }
41207
+ const negative = text3[index] === "-";
41208
+ if (negative || text3[index] === "+") index++;
41209
+ let digits = 0;
41210
+ for (; index < text3.length; index++) {
41211
+ const pending = stringCheckpoint(work);
41212
+ if (pending) await pending;
41213
+ const digit3 = text3.charCodeAt(index) - 48;
41214
+ if (digit3 < 0 || digit3 > 9) break;
41215
+ if (value2 > Math.floor((maximum - digit3) / 10)) throw new MapfileUsageError(`${text3}: invalid number`, 1);
41216
+ value2 = value2 * 10 + digit3;
41217
+ digits++;
41218
+ }
41219
+ for (; index < text3.length; index++) {
41220
+ const pending = stringCheckpoint(work);
41221
+ if (pending) await pending;
41222
+ if (!whitespace2(text3.charCodeAt(index))) throw new MapfileUsageError(`${text3}: invalid number`, 1);
41223
+ }
41224
+ if (!digits || negative && value2 !== 0) throw new MapfileUsageError(`${text3}: invalid number`, 1);
41225
+ return value2;
41226
+ };
41227
+ while (cursor < context2.args.length) {
41228
+ const option = context2.args[cursor];
41229
+ if (option === "--") {
41230
+ cursor++;
41231
+ break;
41232
+ }
41233
+ if (!option.startsWith("-") || option === "-") break;
41234
+ cursor++;
41235
+ for (let index = 1; index < option.length; index++) {
41236
+ const pending = stringCheckpoint(work);
41237
+ if (pending) await pending;
41238
+ const flag = option[index];
41239
+ if (flag === "t") {
41240
+ options3.strip = true;
41241
+ continue;
41242
+ }
41243
+ if (!"dnsOCc".includes(flag)) throw new MapfileUsageError(`-${flag}: invalid option`, 2);
41244
+ const attached = index + 1 < option.length;
41245
+ const operandIndex = attached ? cursor - 1 : cursor++;
41246
+ const operand = attached ? option.slice(index + 1) : context2.args[operandIndex];
41247
+ if (operand === void 0) throw new MapfileUsageError(`-${flag}: option requires an argument`, 2);
41248
+ if (flag === "d") {
41249
+ const bytes3 = shellValueBytes(args.values[operandIndex], allocation);
41250
+ options3.delimiter = bytes3[attached ? index + 1 : 0] ?? 0;
41251
+ } else if (flag === "C") options3.callback = operand;
41252
+ else {
41253
+ const value2 = await numeric4(operand, flag === "O" ? 2147483647 : Number.MAX_SAFE_INTEGER);
41254
+ if (flag === "c") {
41255
+ if (!value2) throw new MapfileUsageError("0: invalid callback quantum", 1);
41256
+ options3.quantum = value2;
41257
+ } else if (flag === "n") options3.count = value2;
41258
+ else if (flag === "s") options3.skip = value2;
41259
+ else {
41260
+ options3.origin = value2;
41261
+ options3.preserve = true;
41262
+ }
41263
+ }
41264
+ break;
41265
+ }
41266
+ }
41267
+ options3.name = context2.args[cursor] ?? "MAPFILE";
41268
+ if (!/^[a-zA-Z_][a-zA-Z_0-9]*$/u.test(options3.name)) throw new MapfileUsageError(`${options3.name}: invalid identifier`, 1);
41269
+ return options3;
41270
+ }
41271
+ async function collectMapfile(options3, input3, hooks) {
41272
+ let skipped = 0;
41273
+ let written = 0;
41274
+ while (!options3.count || written < options3.count) {
41275
+ hooks.loop();
41276
+ const allocation = hooks.allocation();
41277
+ try {
41278
+ const record4 = await input3.mapfileRecord(options3.delimiter, options3.strip, allocation);
41279
+ if (!record4.present) break;
41280
+ if (skipped < options3.skip) {
41281
+ skipped++;
41282
+ continue;
41283
+ }
41284
+ const index = options3.origin + written;
41285
+ if (index > 2147483647) throw new MapfileUsageError("array index exceeds 2147483647", 1);
41286
+ if (options3.callback !== void 0 && (written + 1) % options3.quantum === 0) await hooks.callback(options3.callback, index, record4.value);
41287
+ await hooks.write(index, record4.value);
41288
+ written++;
41289
+ } finally {
41290
+ allocation.close();
41291
+ }
41292
+ }
41293
+ }
41294
+
41151
41295
  // packages/safe-bash/src/shell/arrays/state.ts
41152
41296
  init_platform();
41153
41297
  var sessions = /* @__PURE__ */ new WeakMap();
@@ -41909,6 +42053,8 @@ var shellBuiltinNames = /* @__PURE__ */ new Set([
41909
42053
  "local",
41910
42054
  "unset",
41911
42055
  "read",
42056
+ "mapfile",
42057
+ "readarray",
41912
42058
  "exit",
41913
42059
  "return",
41914
42060
  "break",
@@ -42907,6 +43053,7 @@ var InvocationCancellationOwner = class {
42907
43053
  this.#failures.push(...result2.failures);
42908
43054
  }
42909
43055
  };
43056
+ var mapfileCallbackStates = /* @__PURE__ */ new WeakSet();
42910
43057
  var Runtime = class _Runtime {
42911
43058
  constructor(fs, commands, middleware, budget, signal = budget.signal, fileWrites = /* @__PURE__ */ new Map(), outputFiles = /* @__PURE__ */ new Map(), commandSignal = signal, cancellation, cancellationState, cancellationOwner, cancellationDepth, cancellationMaxDepth, outcomeFrame = void 0, inputProfile = fs) {
42912
43059
  this.fs = fs;
@@ -43257,7 +43404,7 @@ var Runtime = class _Runtime {
43257
43404
  this.writeVariable(state, name2, value2, origin);
43258
43405
  return;
43259
43406
  }
43260
- await this.arrayZero(state, name2, async () => shellValueText(value2));
43407
+ await this.arrayZero(state, name2, async () => value2);
43261
43408
  }
43262
43409
  async prepareVariable(state, name2, saved, scalarLegacy = false) {
43263
43410
  const store = requireArrays(state);
@@ -43414,6 +43561,7 @@ var Runtime = class _Runtime {
43414
43561
  const store = requireArrays(state);
43415
43562
  const operation2 = ArrayOwner.create(store.owner.ledger, store.owner);
43416
43563
  const holding = store.owner.hold();
43564
+ const valueAllocation = this.budget.values.scope();
43417
43565
  let staged;
43418
43566
  try {
43419
43567
  const watch = await store.watch(name2, operation2, this.signal);
@@ -43430,8 +43578,9 @@ var Runtime = class _Runtime {
43430
43578
  const current = store.get(name2);
43431
43579
  if (!current) throw new ArrayFailure("stale binding");
43432
43580
  staged = await current.copy(this.signal);
43433
- const value2 = append ? await this.arrayJoin(operation2, [current.get(0) ?? "", expanded], "") : expanded;
43434
- const token = await textToken(staged.owner, value2, this.signal);
43581
+ const previous = current.values.get(0)?.text.rawValue ?? current.get(0) ?? "";
43582
+ const value2 = !append ? expanded : typeof previous === "string" && typeof expanded === "string" ? await this.arrayJoin(operation2, [previous, expanded], "") : concatShellValues([previous, expanded], valueAllocation);
43583
+ const token = await valueToken(staged.owner, value2, this.signal);
43435
43584
  try {
43436
43585
  staged.insert(0, token);
43437
43586
  } catch (error) {
@@ -43459,6 +43608,7 @@ var Runtime = class _Runtime {
43459
43608
  await staged?.release();
43460
43609
  await operation2.close();
43461
43610
  } finally {
43611
+ valueAllocation.close();
43462
43612
  holding.release();
43463
43613
  }
43464
43614
  }
@@ -43522,7 +43672,7 @@ var Runtime = class _Runtime {
43522
43672
  const preserve = assignment.kind === "element" || assignment.append;
43523
43673
  staged = preserve && current ? await current.copy(this.signal) : IndexedBinding.create(store.owner);
43524
43674
  if (preserve && !current && state.variables[name2] !== void 0) {
43525
- const token = await textToken(staged.owner, state.variables[name2], this.signal);
43675
+ const token = await valueToken(staged.owner, stateMonitor(state)?.values.get(name2, state.variables[name2]) ?? state.variables[name2], this.signal);
43526
43676
  try {
43527
43677
  staged.insert(0, token);
43528
43678
  } catch (error) {
@@ -43534,7 +43684,7 @@ var Runtime = class _Runtime {
43534
43684
  let cursor = assignment.append && assignment.kind === "compound" ? initialMaximum + 1 : 0;
43535
43685
  const insert = async (index, value2) => {
43536
43686
  if (index > 2147483647) throw new ArrayFailure("index outside 0..2147483647");
43537
- const token = await textToken(staged.owner, value2, this.signal);
43687
+ const token = await valueToken(staged.owner, value2, this.signal);
43538
43688
  try {
43539
43689
  staged.insert(index, token);
43540
43690
  } catch (error) {
@@ -43543,11 +43693,12 @@ var Runtime = class _Runtime {
43543
43693
  }
43544
43694
  writes++;
43545
43695
  };
43696
+ const join = async (values) => values.every((value2) => typeof value2 === "string") ? this.arrayJoin(operation2, values, "") : concatShellValues(values, io[valueScope]);
43546
43697
  if (assignment.kind === "element") {
43547
43698
  const index = numericIndex(assignment.index);
43548
- const fields3 = await this.word(assignment.value, state, io, false);
43549
- let value2 = await this.arrayJoin(operation2, fields3, "");
43550
- if (assignment.append) value2 = await this.arrayJoin(operation2, [staged.get(index) ?? "", value2], "");
43699
+ const fields3 = await this.valueWord(assignment.value, state, io, false);
43700
+ let value2 = await join(fields3);
43701
+ if (assignment.append) value2 = await join([staged.values.get(index)?.text.rawValue ?? staged.get(index) ?? "", value2]);
43551
43702
  await insert(index, value2);
43552
43703
  } else for (const entry of assignment.entries) {
43553
43704
  const original = compoundEntryWords.get(entry);
@@ -43558,16 +43709,16 @@ var Runtime = class _Runtime {
43558
43709
  expandedEntry = true;
43559
43710
  const values = await this.valueWord(expanded, state, io, true, false, false, false, void 0, false);
43560
43711
  for (const value2 of values) {
43561
- await insert(cursor, shellValueText(value2));
43712
+ await insert(cursor, value2);
43562
43713
  cursor++;
43563
43714
  }
43564
43715
  }
43565
43716
  if (expandedEntry) continue;
43566
43717
  }
43567
- const fields3 = await this.word(entry.value, state, io, entry.index === void 0);
43718
+ const fields3 = await this.valueWord(entry.value, state, io, entry.index === void 0);
43568
43719
  if (entry.index) {
43569
43720
  const index = numericIndex(entry.index);
43570
- await insert(index, await this.arrayJoin(operation2, fields3, ""));
43721
+ await insert(index, await join(fields3));
43571
43722
  cursor = index + 1;
43572
43723
  } else for (const value2 of fields3) {
43573
43724
  await insert(cursor, value2);
@@ -44458,8 +44609,8 @@ var Runtime = class _Runtime {
44458
44609
  throw new ArrayFailure("indexed binding cannot be a command prefix");
44459
44610
  }
44460
44611
  await this.arrayZero(state, assignment.name, async () => {
44461
- const fields3 = await this.word(assignment.value, state, io, false);
44462
- return this.arrayJoin(requireArrays(state).owner, fields3, "");
44612
+ const fields3 = await this.valueWord(assignment.value, state, io, false);
44613
+ return fields3.every((value3) => typeof value3 === "string") ? this.arrayJoin(requireArrays(state).owner, fields3, "") : concatShellValues(fields3, io[valueScope]);
44463
44614
  }, assignment.append);
44464
44615
  continue;
44465
44616
  }
@@ -44778,6 +44929,8 @@ var Runtime = class _Runtime {
44778
44929
  functionRestoration?.close();
44779
44930
  throw error;
44780
44931
  }
44932
+ const callerLoopDepth = state.loopDepth;
44933
+ if (mapfileCallbackStates.has(state)) state.loopDepth = 0;
44781
44934
  try {
44782
44935
  return { exitCode: await this.command(body, state, { ...io, ...context3, scriptName: body.sourceName ?? io.scriptName ?? "shell" }) };
44783
44936
  } catch (error) {
@@ -44791,6 +44944,7 @@ var Runtime = class _Runtime {
44791
44944
  savedPositionals.close();
44792
44945
  state.positionalSetVersion = positionalSetVersion;
44793
44946
  state.functionDepth--;
44947
+ state.loopDepth = callerLoopDepth;
44794
44948
  state.depth--;
44795
44949
  state.locals.pop();
44796
44950
  };
@@ -46262,12 +46416,119 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46262
46416
  allocation.close();
46263
46417
  }
46264
46418
  }
46419
+ async mapfileBuiltin(context2, state) {
46420
+ const allocation = this.budget.values.scope();
46421
+ const work = { remaining: this.budget.limits.maxExpansionBytes * 8, signal: this.signal, exhausted: () => this.budget.fail("maxExpansionBytes") };
46422
+ let pinned;
46423
+ let releaseHolding;
46424
+ try {
46425
+ const options3 = await mapfileOptions(context2, work, allocation);
46426
+ if (state.readonlyVariables?.has(options3.name)) throw new MapfileUsageError(`${options3.name}: readonly variable`, 1);
46427
+ if (controlNames.has(options3.name) || state.exported.has(options3.name)) throw new ArrayFailure("control or exported binding cannot be indexed");
46428
+ const store = requireArrays(state);
46429
+ const holding = store.owner.hold();
46430
+ releaseHolding = () => holding.release();
46431
+ if (!options3.preserve || !store.get(options3.name)) await this.arrayAssignment({ kind: "compound", name: options3.name, append: options3.preserve, entries: [] }, state, context2);
46432
+ const entry = store.bindings.get(options3.name);
46433
+ allocation.reserve(128 + import_buffer.Buffer.byteLength(options3.name) * 2, 0);
46434
+ pinned = entry.binding.retain();
46435
+ const input3 = context2.stdin instanceof ShellInput ? context2.stdin : new ShellInput(context2.stdin, this.budget, this.signal);
46436
+ let pendingFlow;
46437
+ await collectMapfile(options3, input3, {
46438
+ allocation: () => this.budget.values.scope(),
46439
+ loop: () => this.budget.loop(),
46440
+ write: async (index, value2) => {
46441
+ if (pinned !== entry.binding) {
46442
+ const previous = pinned;
46443
+ pinned = entry.binding.retain();
46444
+ await previous.release();
46445
+ }
46446
+ const operation2 = ArrayOwner.create(store.owner.ledger, store.owner);
46447
+ let staged;
46448
+ try {
46449
+ const current = pinned;
46450
+ const attached = store.bindings.get(options3.name) === entry;
46451
+ const watch = attached ? await store.watch(options3.name, operation2, this.signal) : void 0;
46452
+ const supersede = attached ? await stateMonitor(state).prepareTypedPublication(options3.name, operation2, this.signal) : void 0;
46453
+ if (attached) await this.prepareArrayObservers(state, operation2);
46454
+ const tickets = operation2.reserve({ generation: true, version: true, epoch: true, work: 8 });
46455
+ staged = current.references > (attached ? 2 : 1) ? await current.copy(this.signal) : current.retain();
46456
+ const token = await valueToken(staged.owner, value2, this.signal);
46457
+ try {
46458
+ this.signal.throwIfAborted();
46459
+ if (watch && !watch.valid()) throw new ArrayFailure("stale binding");
46460
+ staged.insert(index, token);
46461
+ } catch (error) {
46462
+ token.release();
46463
+ throw error;
46464
+ }
46465
+ if (attached) {
46466
+ let released;
46467
+ stateMonitor(state).publish(tickets, options3.name, () => {
46468
+ supersede();
46469
+ released = store.publish(options3.name, staged, tickets);
46470
+ });
46471
+ staged = void 0;
46472
+ await released;
46473
+ } else {
46474
+ const previous = pinned;
46475
+ pinned = staged;
46476
+ entry.binding = staged;
46477
+ staged = void 0;
46478
+ await previous.release();
46479
+ }
46480
+ } finally {
46481
+ try {
46482
+ await staged?.release();
46483
+ } finally {
46484
+ await operation2.close();
46485
+ }
46486
+ }
46487
+ },
46488
+ callback: async (source2, index, value2) => {
46489
+ if (pendingFlow) return;
46490
+ const callbackAllocation = this.budget.values.scope();
46491
+ const nested = mapfileCallbackStates.has(state);
46492
+ try {
46493
+ const quoted2 = shellValueText(await transformParameter(value2, "Q", { maximumBytes: this.budget.limits.maxExpansionBytes, byteLocale: byteLocale(state.variables), work, allocation: callbackAllocation }));
46494
+ if (import_buffer.Buffer.byteLength(source2) + import_buffer.Buffer.byteLength(quoted2) + String(index).length + 2 > this.budget.limits.maxExpansionBytes) this.budget.fail("maxExpansionBytes");
46495
+ mapfileCallbackStates.add(state);
46496
+ await this.evalBuiltin({ ...context2, args: [source2, String(index), quoted2] }, state, context2, false);
46497
+ } catch (error) {
46498
+ if (error instanceof Flow2 && (error.kind === "break" || error.kind === "continue")) pendingFlow = error;
46499
+ else throw error;
46500
+ } finally {
46501
+ if (!nested) mapfileCallbackStates.delete(state);
46502
+ callbackAllocation.close();
46503
+ }
46504
+ }
46505
+ });
46506
+ if (pendingFlow) throw pendingFlow;
46507
+ return 0;
46508
+ } catch (error) {
46509
+ this.signal.throwIfAborted();
46510
+ if (!(error instanceof MapfileUsageError)) throw error;
46511
+ await this.diagnostic(context2, `${context2.command}: ${error.message}`);
46512
+ return error.status;
46513
+ } finally {
46514
+ try {
46515
+ await pinned?.release();
46516
+ } finally {
46517
+ try {
46518
+ releaseHolding?.();
46519
+ } finally {
46520
+ allocation.close();
46521
+ }
46522
+ }
46523
+ }
46524
+ }
46265
46525
  async builtin(context2, state, assignments2, diagnose, suppressSpecial = false) {
46266
46526
  const { command: command7, args, stdout, stderr } = context2;
46267
46527
  if (command7 === ":" || command7 === "true") return 0;
46268
46528
  if (command7 === "false") return 1;
46269
46529
  if (command7 === "shopt") return this.shoptBuiltin(context2, state);
46270
46530
  if (command7 === "let") return this.letBuiltin(context2, state);
46531
+ if (command7 === "mapfile" || command7 === "readarray") return this.mapfileBuiltin(context2, state);
46271
46532
  if (command7 === "getopts") return this.getoptsBuiltin(context2, state);
46272
46533
  if (command7 === "pushd" || command7 === "dirs" || command7 === "popd") return this.directoryStackBuiltin(context2, state, diagnose);
46273
46534
  if (command7 === "pwd") {
@@ -46823,7 +47084,7 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46823
47084
  if (part.kind === "variable" && part.transform) {
46824
47085
  const selector2 = getArraySelector(part);
46825
47086
  if (selector2?.kind === "members" || part.name === "@" || part.name === "*") {
46826
- const members = selector2 ? await this.arrayMembers(part.name, state) : this.positionalValues(state);
47087
+ const members = selector2 ? await this.arrayMembers(part.name, state, io) : this.positionalValues(state);
46827
47088
  const ifs = state.variables.IFS ?? " ";
46828
47089
  const separator = ifs.length ? String.fromCodePoint(ifs.codePointAt(0)) : "";
46829
47090
  const fragments = [];
@@ -46867,6 +47128,7 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46867
47128
  const token = index === void 0 || selector?.kind === "members" ? void 0 : binding?.values.get(index)?.text;
46868
47129
  token?.retain();
46869
47130
  try {
47131
+ if (token?.rawValue && part.kind === "variable" && !part.length && !part.operator && !part.substring) return shellValueFromBytes(shellValueBytes(token.rawValue, io[valueScope]), io[valueScope]);
46870
47132
  const value2 = await this.partValue(part, state, io, hereString);
46871
47133
  if (binding) await textToken(requireArrays(state).owner, shellValueText(value2), this.signal);
46872
47134
  return value2;
@@ -46984,8 +47246,11 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46984
47246
  return part.length ? this.parameterLength(value3 ?? "") : value3 ?? "";
46985
47247
  }
46986
47248
  if (part.length) return String(binding?.values.size ?? (state.variables[part.name] === void 0 ? 0 : 1));
46987
- const values = await this.arrayMembers(part.name, state);
46988
- return this.arrayJoin(store.owner, values, Array.from(state.variables.IFS ?? " ")[0] ?? "");
47249
+ const values = await this.arrayMembers(part.name, state, io);
47250
+ const separator = Array.from(state.variables.IFS ?? " ")[0] ?? "";
47251
+ if (values.every((value3) => typeof value3 === "string")) return this.arrayJoin(store.owner, values, separator);
47252
+ io[valueScope]?.reserve(values.length * 32 + 64, 0);
47253
+ return concatShellValues(values.flatMap((value3, index) => index ? [separator, value3] : [value3]), io[valueScope]);
46989
47254
  }
46990
47255
  let value2 = part.name === "?" ? String(state.status) : part.name === "-" ? `${state.errexit ? "e" : ""}${state.nounset ? "u" : ""}${state.braceexpand !== false ? "B" : ""}` : part.name === "#" ? String(state.positional.length) : part.name === "@" || part.name === "*" ? state.positional.join(hereString && (part.name === "@" || !part.quoted) ? " " : Array.from(state.variables.IFS ?? " ")[0] ?? "") : /^0+$/u.test(part.name) ? state.arg0 ?? "virtual-bash" : /^\d+$/u.test(part.name) ? state.positional[Number(part.name) - 1] : this.variable(state, part.name);
46991
47256
  let retained = value2;
@@ -47394,7 +47659,7 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
47394
47659
  emptyNameGroups.add(quoteGroup);
47395
47660
  }
47396
47661
  } else if (part.kind === "variable" && split4 && (selector?.kind === "members" && !part.length && (!part.quoted || selector.separator === "@") || part.transform && part.name === "@")) {
47397
- const members = selector?.kind === "members" ? await this.arrayMembers(part.name, state) : this.positionalValues(state);
47662
+ const members = selector?.kind === "members" ? await this.arrayMembers(part.name, state, io) : this.positionalValues(state);
47398
47663
  for (let position = 0; position < members.length; position++) {
47399
47664
  if (position > 0) addField();
47400
47665
  const original = members[position];
@@ -47536,7 +47801,7 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
47536
47801
  for (const value2 of values) if (typeof value2 !== "string") allocation.hold(value2);
47537
47802
  return createCommandArguments(values, allocation);
47538
47803
  }
47539
- async arrayMembers(name2, state) {
47804
+ async arrayMembers(name2, state, io) {
47540
47805
  const store = requireArrays(state);
47541
47806
  const holding = store.owner.hold();
47542
47807
  try {
@@ -47555,8 +47820,9 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
47555
47820
  const values = [];
47556
47821
  for (const index of indices) {
47557
47822
  store.owner.reserve({ metadata: 32, allocatedSlots: 1, work: 4 });
47558
- const value2 = binding.get(index);
47559
- await textToken(store.owner, value2, this.signal);
47823
+ const token = binding.values.get(index).text;
47824
+ const value2 = token.rawValue === void 0 ? token.value : shellValueFromBytes(shellValueBytes(token.rawValue, io[valueScope]), io[valueScope]);
47825
+ if (typeof value2 === "string") await textToken(store.owner, value2, this.signal);
47560
47826
  values.push(value2);
47561
47827
  await store.owner.ledger.checkpoint(this.signal);
47562
47828
  }
@@ -48231,6 +48497,51 @@ var ShellInput = class _ShellInput {
48231
48497
  }
48232
48498
  });
48233
48499
  }
48500
+ mapfileRecord(delimiter, strip, allocation) {
48501
+ return this.#cursor.consume(this.signal, async () => {
48502
+ this.#cursor.admitBoundedRead();
48503
+ allocation.reserve(64, 0);
48504
+ const parts = [];
48505
+ let length = 0;
48506
+ let truncated = false;
48507
+ let pulls = 0;
48508
+ while (true) {
48509
+ if (++pulls % 128 === 0) await yieldTurn(this.signal);
48510
+ const result2 = await this.#cursor.take(this.signal);
48511
+ if (result2.done) return { value: concatShellValues(parts, allocation), present: length > 0 };
48512
+ const chunk = result2.value;
48513
+ for (let offset = 0; offset < chunk.length; ) {
48514
+ await yieldTurn(this.signal);
48515
+ if (length >= this.budget.limits.maxOutputBytes) this.budget.fail("maxOutputBytes");
48516
+ const end = Math.min(offset + 1024, chunk.length, offset + this.budget.limits.maxOutputBytes - length);
48517
+ allocation.reserve(end - offset + 64, 0);
48518
+ const output2 = new Uint8Array(end - offset);
48519
+ let used = 0;
48520
+ let terminated = false;
48521
+ while (offset < end) {
48522
+ const byte = chunk[offset++];
48523
+ this.#cursor.position++;
48524
+ if (++length > this.budget.limits.maxOutputBytes) this.budget.fail("maxOutputBytes");
48525
+ if (byte === delimiter) {
48526
+ if (!strip && byte !== 0 && !truncated) output2[used++] = byte;
48527
+ terminated = true;
48528
+ break;
48529
+ }
48530
+ if (byte === 0) truncated = true;
48531
+ if (!truncated) output2[used++] = byte;
48532
+ }
48533
+ if (used) {
48534
+ allocation.reserve(32, 0);
48535
+ parts.push(shellValueFromBytes(output2.subarray(0, used), allocation));
48536
+ }
48537
+ if (terminated) {
48538
+ if (offset < chunk.length) this.#cursor.remainder = chunk.subarray(offset);
48539
+ return { value: concatShellValues(parts, allocation), present: true };
48540
+ }
48541
+ }
48542
+ }
48543
+ });
48544
+ }
48234
48545
  async readBounded(raw, options3) {
48235
48546
  const text3 = new ReadText();
48236
48547
  let characters = 0;