@poe-platform/safe-bash 0.1.522 → 0.1.524

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.
@@ -33508,8 +33508,8 @@ async function entities(text3, budget) {
33508
33508
  const name2 = match[1];
33509
33509
  if (name2[0] !== "#") result2.append(Object.hasOwn(named, name2) ? named[name2] : match[0]);
33510
33510
  else {
33511
- const hexadecimal = name2[1]?.toLowerCase() === "x";
33512
- const value2 = Number.parseInt(name2.slice(hexadecimal ? 2 : 1), hexadecimal ? 16 : 10);
33511
+ const hexadecimal2 = name2[1]?.toLowerCase() === "x";
33512
+ const value2 = Number.parseInt(name2.slice(hexadecimal2 ? 2 : 1), hexadecimal2 ? 16 : 10);
33513
33513
  result2.append(value2 === 0 || value2 > 1114111 || value2 >= 55296 && value2 <= 57343 ? "\uFFFD" : String.fromCodePoint(value2));
33514
33514
  }
33515
33515
  offset += match[0].length;
@@ -37479,6 +37479,7 @@ init_platform();
37479
37479
  var assignments = /* @__PURE__ */ new WeakMap();
37480
37480
  var selectors = /* @__PURE__ */ new WeakMap();
37481
37481
  var quoteMarkers = /* @__PURE__ */ new WeakSet();
37482
+ var prefixNameQuoteGroups = /* @__PURE__ */ new WeakMap();
37482
37483
  function setQuoteMarker(part, synthetic) {
37483
37484
  if (synthetic) quoteMarkers.add(part);
37484
37485
  else quoteMarkers.delete(part);
@@ -37514,6 +37515,8 @@ function copyArraySelector(original, copy2) {
37514
37515
  const selector = selectors.get(original);
37515
37516
  if (selector) selectors.set(copy2, selector);
37516
37517
  setQuoteMarker(copy2, isQuoteMarker(original));
37518
+ const group = prefixNameQuoteGroups.get(original);
37519
+ if (group) prefixNameQuoteGroups.set(copy2, group);
37517
37520
  return copy2;
37518
37521
  }
37519
37522
  function setArrayAssignment(word, assignment) {
@@ -38113,14 +38116,19 @@ shell: command substitution: line ${line}: \`${sourceLine}'
38113
38116
  this.position++;
38114
38117
  text3("", true, true, this.position - 1, this.position);
38115
38118
  const quoteParts = parts.length;
38119
+ let nameListing = false;
38116
38120
  while (this.position < this.source.length && this.source[this.position] !== '"') {
38117
38121
  const inner = this.source[this.position];
38118
38122
  const opaque2 = this.braceReplay?.get(this.position);
38119
38123
  if (opaque2 !== void 0) {
38120
38124
  text3(opaque2, true);
38121
38125
  this.position++;
38122
- } else if (!literal && (inner === "$" || inner === "`")) this.expansion(parts, true);
38123
- else if (inner === "\\" && /[$`"\\\n]/u.test(this.source[this.position + 1] ?? "")) {
38126
+ } else if (!literal && (inner === "$" || inner === "`")) {
38127
+ this.expansion(parts, true);
38128
+ const part = parts.at(-1);
38129
+ const selector = getArraySelector(part);
38130
+ nameListing ||= part.kind === "variable" && (part.prefixNames === "@" || !!part.transform && (part.name === "@" || selector?.kind === "members" && selector.separator === "@"));
38131
+ } else if (inner === "\\" && /[$`"\\\n]/u.test(this.source[this.position + 1] ?? "")) {
38124
38132
  const escaped3 = this.source[this.position + 1];
38125
38133
  if (escaped3 !== "\n") text3(escaped3, true, false, this.position, this.position + 2);
38126
38134
  else this.printedNewlineReduction++;
@@ -38132,6 +38140,15 @@ shell: command substitution: line ${line}: \`${sourceLine}'
38132
38140
  }
38133
38141
  if (this.source[this.position] !== '"' && !this.braceReplay) this.error("Unterminated double quote", { quote: '"', line: quoteLine });
38134
38142
  if (parts.length === quoteParts) setQuoteMarker(parts.at(-1), false);
38143
+ if (nameListing) {
38144
+ this.budget.admit();
38145
+ const group = {};
38146
+ for (let index = quoteParts - 1; index < parts.length; index++) {
38147
+ this.budget.admit();
38148
+ const part = parts[index];
38149
+ if (index !== quoteParts - 1 || isQuoteMarker(part) || part.kind !== "text" || part.value !== "") prefixNameQuoteGroups.set(part, group);
38150
+ }
38151
+ }
38135
38152
  const spelling2 = expansionSpellings.get(parts.at(-1));
38136
38153
  if (spelling2) spelling2.end = Math.min(this.position + 1, this.source.length);
38137
38154
  if (this.position < this.source.length) this.position++;
@@ -38291,11 +38308,20 @@ shell: command substitution: line ${line}: \`${sourceLine}'
38291
38308
  } else if (this.source[this.position] === "{") {
38292
38309
  this.position++;
38293
38310
  const parameterStart = this.position - 2;
38294
- const length = this.source[this.position] === "#" && /[a-zA-Z_]/u.test(this.source[this.position + 1] ?? "");
38311
+ const listing = this.source[this.position] === "!";
38312
+ if (listing) this.position++;
38313
+ const length = !listing && this.source[this.position] === "#" && /[a-zA-Z_]/u.test(this.source[this.position + 1] ?? "");
38295
38314
  if (length) this.position++;
38296
38315
  const name2 = /^(?:[a-zA-Z_][a-zA-Z_0-9]*|[0-9]+|[?@*#-])/u.exec(this.source.slice(this.position))?.[0];
38297
38316
  if (!name2) this.error("Unsupported parameter expansion");
38298
38317
  this.position += name2.length;
38318
+ let prefixNames;
38319
+ if (listing) {
38320
+ const separator = this.source[this.position];
38321
+ if (!/^[a-zA-Z_][a-zA-Z_0-9]*$/u.test(name2) || separator !== "*" && separator !== "@" || this.source[this.position + 1] !== "}") this.error("Unsupported indirect parameter expansion");
38322
+ prefixNames = separator;
38323
+ this.position++;
38324
+ }
38299
38325
  let selector;
38300
38326
  if (this.source[this.position] === "[") {
38301
38327
  if (!/^[a-zA-Z_][a-zA-Z_0-9]*$/u.test(name2)) this.error("Unsupported indexed-array parameter");
@@ -38304,7 +38330,14 @@ shell: command substitution: line ${line}: \`${sourceLine}'
38304
38330
  if (end < 0) this.error("Unterminated indexed-array subscript");
38305
38331
  selector = arraySelector(this.source.slice(start, end), start, this.budget);
38306
38332
  this.position = end + 1;
38307
- if (this.source[this.position] !== "}") this.error("Unsupported indexed-array operator");
38333
+ if (this.source[this.position] !== "}" && this.source[this.position] !== "@") this.error("Unsupported indexed-array operator");
38334
+ }
38335
+ let transform2;
38336
+ if (this.source[this.position] === "@") {
38337
+ const operation2 = this.source[this.position + 1];
38338
+ if (length || prefixNames || operation2 !== "Q" && operation2 !== "E" || this.source[this.position + 2] !== "}") this.error("Unsupported parameter transform");
38339
+ transform2 = operation2;
38340
+ this.position += 2;
38308
38341
  }
38309
38342
  const operator = /^(?::[-=+?]|##|%%|\/\/|\/[#%]?|[-=+?#%])/u.exec(this.source.slice(this.position))?.[0];
38310
38343
  let alternate;
@@ -38348,7 +38381,7 @@ shell: command substitution: line ${line}: \`${sourceLine}'
38348
38381
  parts.push({ kind: "failed-parameter", source: this.source.slice(parameterStart, this.position), line, quoted: quoted2 });
38349
38382
  } else {
38350
38383
  this.position++;
38351
- const part = { kind: "variable", name: name2, quoted: quoted2, line, ...length ? { length } : {}, ...operator ? { operator, alternate } : {}, ...replacement ? { replacement } : {}, ...substring ? { substring } : {} };
38384
+ const part = { kind: "variable", name: name2, quoted: quoted2, line, ...prefixNames ? { prefixNames } : {}, ...transform2 ? { transform: transform2 } : {}, ...length ? { length } : {}, ...operator ? { operator, alternate } : {}, ...replacement ? { replacement } : {}, ...substring ? { substring } : {} };
38352
38385
  if (selector) setArraySelector(part, selector);
38353
38386
  parts.push(part);
38354
38387
  }
@@ -40760,6 +40793,7 @@ var IndexedBinding = class _IndexedBinding {
40760
40793
  generation = 0;
40761
40794
  version = 0;
40762
40795
  references = 1;
40796
+ assigned = false;
40763
40797
  static create(parent) {
40764
40798
  const owner = ArrayOwner.create(parent.ledger, parent);
40765
40799
  try {
@@ -40791,11 +40825,13 @@ var IndexedBinding = class _IndexedBinding {
40791
40825
  text3.release();
40792
40826
  };
40793
40827
  this.values.set(index, element);
40828
+ this.assigned = true;
40794
40829
  if (index > this.maximum) this.maximum = index;
40795
40830
  previous?.slot.release();
40796
40831
  }
40797
40832
  async copy(signal) {
40798
40833
  const copy2 = _IndexedBinding.create(this.owner.parent);
40834
+ copy2.assigned = this.assigned;
40799
40835
  this.retain();
40800
40836
  try {
40801
40837
  for (const [index, element] of this.values) {
@@ -41581,6 +41617,138 @@ function* pathTargets(name2, path, limits, signal, fail4) {
41581
41617
  }
41582
41618
  }
41583
41619
 
41620
+ // packages/safe-bash/src/shell/parameter-transforms.ts
41621
+ init_platform();
41622
+ function hexadecimal(byte) {
41623
+ return byte >= 48 && byte <= 57 ? byte - 48 : byte >= 65 && byte <= 70 ? byte - 55 : byte >= 97 && byte <= 102 ? byte - 87 : -1;
41624
+ }
41625
+ function utf8Unit(bytes3, offset) {
41626
+ const first = bytes3[offset];
41627
+ if (first < 128) return { point: first, size: 1 };
41628
+ const size = first >= 194 && first <= 223 ? 2 : first >= 224 && first <= 239 ? 3 : first >= 240 && first <= 244 ? 4 : 0;
41629
+ if (!size || offset + size > bytes3.length) return { point: -1, size: 1 };
41630
+ let point = first & 127 >> size;
41631
+ for (let index = 1; index < size; index++) {
41632
+ const byte = bytes3[offset + index];
41633
+ if (byte < 128 || byte > 191) return { point: -1, size: 1 };
41634
+ point = point * 64 + (byte & 63);
41635
+ }
41636
+ if (point < (size === 2 ? 128 : size === 3 ? 2048 : 65536) || point > 1114111 || point >= 55296 && point <= 57343) return { point: -1, size: 1 };
41637
+ return { point, size };
41638
+ }
41639
+ var controlEscapes = { 7: 97, 8: 98, 9: 116, 10: 110, 11: 118, 12: 102, 13: 114, 27: 69 };
41640
+ var decodedEscapes = { 97: 7, 98: 8, 116: 9, 110: 10, 118: 11, 102: 12, 114: 13, 101: 27, 69: 27, 92: 92, 39: 39, 34: 34, 63: 63 };
41641
+ async function transformParameter(value2, operator, options3) {
41642
+ const { work, allocation, maximumBytes } = options3;
41643
+ work.signal.throwIfAborted();
41644
+ if (typeof value2 === "string") {
41645
+ if (value2.length > maximumBytes) work.exhausted();
41646
+ if ((await scanString(value2, work)).bytes > maximumBytes) work.exhausted();
41647
+ } else if (shellValueByteLength(value2) > maximumBytes) work.exhausted();
41648
+ const input3 = shellValueBytes(value2, allocation);
41649
+ let ansi = false;
41650
+ if (operator === "Q") {
41651
+ for (let offset = 0; offset < input3.length; ) {
41652
+ const pending = stringCheckpoint(work);
41653
+ if (pending) await pending;
41654
+ const unit2 = options3.byteLocale ? { point: input3[offset], size: 1 } : utf8Unit(input3, offset);
41655
+ const printable = unit2.point >= 32 && unit2.point < 127 || !options3.byteLocale && unit2.point >= 128 && !/[\p{Cc}\p{Cf}\p{Cn}]/u.test(String.fromCodePoint(unit2.point));
41656
+ if (!printable) ansi = true;
41657
+ offset += unit2.size;
41658
+ }
41659
+ }
41660
+ let output2 = void 0;
41661
+ let size = 0;
41662
+ const emit2 = (byte) => {
41663
+ if (size >= maximumBytes) work.exhausted();
41664
+ if (output2) output2[size] = byte;
41665
+ size++;
41666
+ };
41667
+ const ascii2 = (text3) => {
41668
+ for (let index = 0; index < text3.length; index++) emit2(text3.charCodeAt(index));
41669
+ };
41670
+ const scan = async () => {
41671
+ size = 0;
41672
+ if (operator === "Q") {
41673
+ ascii2(ansi ? "$'" : "'");
41674
+ for (let offset = 0; offset < input3.length; ) {
41675
+ const pending = stringCheckpoint(work);
41676
+ if (pending) await pending;
41677
+ const unit2 = options3.byteLocale ? { point: input3[offset], size: 1 } : utf8Unit(input3, offset);
41678
+ const printable = unit2.point >= 32 && unit2.point < 127 || !options3.byteLocale && unit2.point >= 128 && !/[\p{Cc}\p{Cf}\p{Cn}]/u.test(String.fromCodePoint(unit2.point));
41679
+ if (ansi && !printable) {
41680
+ if (unit2.size === 1 && controlEscapes[input3[offset]] !== void 0) {
41681
+ emit2(92);
41682
+ emit2(controlEscapes[input3[offset]]);
41683
+ } else for (let index = 0; index < unit2.size; index++) ascii2("\\" + input3[offset + index].toString(8).padStart(3, "0"));
41684
+ } else if (unit2.point === 39) ascii2(ansi ? "\\'" : "'\\''");
41685
+ else if (ansi && unit2.point === 92) ascii2("\\\\");
41686
+ else for (let index = 0; index < unit2.size; index++) emit2(input3[offset + index]);
41687
+ offset += unit2.size;
41688
+ }
41689
+ emit2(39);
41690
+ return;
41691
+ }
41692
+ for (let offset = 0; offset < input3.length; ) {
41693
+ const pending = stringCheckpoint(work);
41694
+ if (pending) await pending;
41695
+ let byte = input3[offset++];
41696
+ if (byte === 92 && offset < input3.length) {
41697
+ const escape = input3[offset++];
41698
+ if (decodedEscapes[escape] !== void 0) byte = decodedEscapes[escape];
41699
+ else if (escape >= 48 && escape <= 55) {
41700
+ byte = escape - 48;
41701
+ for (let count2 = 1; count2 < 3 && offset < input3.length && input3[offset] >= 48 && input3[offset] <= 55; count2++) byte = byte * 8 + input3[offset++] - 48;
41702
+ byte &= 255;
41703
+ } else if (escape === 120 || escape === 117 || escape === 85) {
41704
+ const maximum = escape === 120 ? 2 : escape === 117 ? 4 : 8;
41705
+ let point = 0;
41706
+ let count2 = 0;
41707
+ while (count2 < maximum && offset < input3.length && hexadecimal(input3[offset]) >= 0) {
41708
+ point = point * 16 + hexadecimal(input3[offset++]);
41709
+ count2++;
41710
+ }
41711
+ if (!count2) {
41712
+ emit2(92);
41713
+ emit2(escape);
41714
+ continue;
41715
+ }
41716
+ if (escape === 120) byte = point;
41717
+ else {
41718
+ if (!point || point >= 2147483648) return;
41719
+ if (options3.byteLocale && point >= 55296 && point <= 57343) ascii2(`\\u${point.toString(16).toUpperCase().padStart(4, "0")}`);
41720
+ else {
41721
+ const width = point < 128 ? 1 : point < 2048 ? 2 : point < 65536 ? 3 : point < 2097152 ? 4 : point < 67108864 ? 5 : 6;
41722
+ if (width === 1) emit2(point);
41723
+ else {
41724
+ const divisor = 64 ** (width - 1);
41725
+ emit2(256 - 2 ** (8 - width) + Math.floor(point / divisor));
41726
+ for (let shift = width - 2; shift >= 0; shift--) emit2(128 + Math.floor(point / 64 ** shift) % 64);
41727
+ }
41728
+ }
41729
+ continue;
41730
+ }
41731
+ } else if (escape === 99 && offset < input3.length) {
41732
+ const control = input3[offset++];
41733
+ if (control === 92 && input3[offset] === 92) offset++;
41734
+ byte = control === 63 ? 127 : control & 31;
41735
+ } else {
41736
+ emit2(92);
41737
+ byte = escape;
41738
+ }
41739
+ }
41740
+ if (!byte) return;
41741
+ emit2(byte);
41742
+ }
41743
+ };
41744
+ await scan();
41745
+ allocation.reserve(size + 64, 1);
41746
+ output2 = new Uint8Array(size);
41747
+ await scan();
41748
+ work.signal.throwIfAborted();
41749
+ return shellValueFromBytes(output2, allocation);
41750
+ }
41751
+
41584
41752
  // packages/safe-bash/src/shell/runtime.ts
41585
41753
  var defaultLimits = {
41586
41754
  maxParseUnits: defaultMaxParseUnits,
@@ -41671,6 +41839,35 @@ function resolveLimits(...limits) {
41671
41839
  return result2;
41672
41840
  }
41673
41841
  var budgetedSinks = /* @__PURE__ */ new WeakMap();
41842
+ async function sortExpansionStrings(values, work) {
41843
+ const compare6 = async (left, right) => {
41844
+ for (let index = 0; index < Math.min(left.length, right.length); index++) {
41845
+ const pending = stringCheckpoint(work);
41846
+ if (pending) await pending;
41847
+ const difference = left.charCodeAt(index) - right.charCodeAt(index);
41848
+ if (difference) return difference;
41849
+ }
41850
+ return left.length - right.length;
41851
+ };
41852
+ const sift = async (root, end) => {
41853
+ while (root * 2 + 1 < end) {
41854
+ let child = root * 2 + 1;
41855
+ if (child + 1 < end && await compare6(values[child], values[child + 1]) < 0) child++;
41856
+ if (await compare6(values[root], values[child]) >= 0) return;
41857
+ const saved = values[root];
41858
+ values[root] = values[child];
41859
+ values[child] = saved;
41860
+ root = child;
41861
+ }
41862
+ };
41863
+ for (let index = Math.floor(values.length / 2) - 1; index >= 0; index--) await sift(index, values.length);
41864
+ for (let end = values.length - 1; end > 0; end--) {
41865
+ const saved = values[0];
41866
+ values[0] = values[end];
41867
+ values[end] = saved;
41868
+ await sift(0, end);
41869
+ }
41870
+ }
41674
41871
  var Budget25 = class {
41675
41872
  constructor(limits, signal, onInternalError) {
41676
41873
  this.limits = limits;
@@ -41841,7 +42038,7 @@ var typedSavedVariables = /* @__PURE__ */ new WeakMap();
41841
42038
  var valueScope = /* @__PURE__ */ Symbol("shell value allocation scope");
41842
42039
  var invokedValues = /* @__PURE__ */ new WeakMap();
41843
42040
  function isolateIO(io) {
41844
- return { ...io, ...io.descriptors ? { descriptors: new Map([...io.descriptors].map(([number5, descriptor2]) => [number5, { ...descriptor2 }])) } : {} };
42041
+ return { ...io, nameExpansionContext: void 0, ...io.descriptors ? { descriptors: new Map([...io.descriptors].map(([number5, descriptor2]) => [number5, { ...descriptor2 }])) } : {} };
41845
42042
  }
41846
42043
  function activeIO(io) {
41847
42044
  const input3 = io.descriptors?.get(0);
@@ -43038,6 +43235,7 @@ var Runtime = class _Runtime {
43038
43235
  const current = store.get(name2);
43039
43236
  if (index !== void 0 && current) {
43040
43237
  staged = index === "members" ? IndexedBinding.create(store.owner) : await current.copy(this.signal);
43238
+ staged.assigned = current.assigned;
43041
43239
  let maximum = -1;
43042
43240
  for (const key of staged.values.keys()) {
43043
43241
  operation2.reserve({ work: 2 }).release();
@@ -43238,7 +43436,8 @@ var Runtime = class _Runtime {
43238
43436
  this.signal.throwIfAborted();
43239
43437
  if (state.readonlyVariables?.has(name2)) throw new ArrayFailure("readonly binding");
43240
43438
  if (!watch.valid()) throw new ArrayFailure("stale binding");
43241
- if (!(assignment.kind === "compound" && assignment.append && writes === 0)) {
43439
+ staged.assigned = true;
43440
+ if (!(assignment.kind === "compound" && assignment.append && writes === 0 && current?.assigned)) {
43242
43441
  let released;
43243
43442
  stateMonitor(state).publish(tickets, name2, () => {
43244
43443
  supersede();
@@ -43541,8 +43740,8 @@ var Runtime = class _Runtime {
43541
43740
  signal: this.signal,
43542
43741
  locale: state.variables.LC_ALL || state.variables.LC_COLLATE || state.variables.LANG || "C",
43543
43742
  work: { remaining: this.budget.limits.maxExpansionBytes, signal: this.signal, exhausted: () => this.budget.fail("maxExpansionBytes"), allocation },
43544
- expand: async (word, pattern = false) => (await this.word(word, state, io, false, pattern, false, pattern)).join(""),
43545
- regex: (subject, pattern) => this.ere(subject, pattern, state, io),
43743
+ expand: async (word, pattern = false) => (await this.word(word, state, { ...io, nameExpansionContext: "conditional" }, false, pattern, false, pattern)).join(""),
43744
+ regex: (subject, pattern) => this.ere(subject, pattern, state, { ...io, nameExpansionContext: "conditional" }),
43546
43745
  option: (name2) => name2 === "braceexpand" ? state.braceexpand !== false : name2 === "errexit" ? !!state.errexit : name2 === "nounset" ? !!state.nounset : name2 === "pipefail" ? state.pipefail : false,
43547
43746
  present: (name2) => {
43548
43747
  const match = /^([a-zA-Z_][a-zA-Z_0-9]*)(?:\[(0|[1-9][0-9]*|[@*])\])?$/u.exec(name2);
@@ -43756,6 +43955,7 @@ var Runtime = class _Runtime {
43756
43955
  async document(document, state, io, line = document.endLine) {
43757
43956
  this.signal.throwIfAborted();
43758
43957
  let value2 = "";
43958
+ let fragments;
43759
43959
  let size = 0;
43760
43960
  let words = 0;
43761
43961
  const warnings = [];
@@ -43765,16 +43965,25 @@ var Runtime = class _Runtime {
43765
43965
  for (const warning of warnings.splice(0)) await writeDiagnostic(io.stderr, `shell: warning: ${warning}
43766
43966
  `);
43767
43967
  if (++words % 128 === 0) await yieldTurn(this.signal);
43768
- const part = (await this.word(word, state, io, false)).join("");
43769
- size += import_buffer.Buffer.byteLength(part);
43968
+ const part = concatShellValues(await this.valueWord(word, state, { ...io, nameExpansionContext: "document" }, false), io[valueScope]);
43969
+ size += shellValueByteLength(part);
43770
43970
  if (size > this.budget.limits.maxExpansionBytes) this.budget.fail("maxExpansionBytes");
43771
- value2 += part;
43971
+ if (!fragments && typeof part === "string") value2 += part;
43972
+ else {
43973
+ if (!fragments) {
43974
+ io[valueScope]?.reserve(64 + value2.length * 2, 0);
43975
+ fragments = [value2];
43976
+ value2 = "";
43977
+ }
43978
+ io[valueScope]?.reserve(32 + (typeof part === "string" ? part.length * 2 : 0), 0);
43979
+ fragments.push(part);
43980
+ }
43772
43981
  }
43773
43982
  } finally {
43774
43983
  for (const warning of warnings.splice(0)) await writeDiagnostic(io.stderr, `shell: warning: ${warning}
43775
43984
  `);
43776
43985
  }
43777
- return value2;
43986
+ return fragments ? concatShellValues(fragments, io[valueScope]) : value2;
43778
43987
  }
43779
43988
  async redirect(redirects, state, io, inputs2, outputs, isolatedInlineInput = false, persistMoves = false, fileShortcut = false, line) {
43780
43989
  this.signal.throwIfAborted();
@@ -43803,6 +44012,7 @@ var Runtime = class _Runtime {
43803
44012
  const stdinIsDefault = descriptor2?.input ? descriptor2.stdinIsDefault : false;
43804
44013
  return {
43805
44014
  [invocationScope]: io[invocationScope],
44015
+ ...io[valueScope] === void 0 ? {} : { [valueScope]: io[valueScope] },
43806
44016
  ...io.execution === void 0 ? {} : { execution: io.execution },
43807
44017
  ...io.diagnosticLine === void 0 ? {} : { diagnosticLine: io.diagnosticLine },
43808
44018
  ...io.diagnosticOffset === void 0 ? {} : { diagnosticOffset: io.diagnosticOffset },
@@ -43823,7 +44033,7 @@ var Runtime = class _Runtime {
43823
44033
  const hereString = redirect.operator === "<<<";
43824
44034
  let value2;
43825
44035
  try {
43826
- value2 = redirect.document ? await this.document(redirect.document, state, currentIO(), line) : (await this.word(redirect.target, state, currentIO(), false, false, hereString)).join("");
44036
+ value2 = redirect.document ? await this.document(redirect.document, state, currentIO(), line) : concatShellValues(await this.valueWord(redirect.target, state, currentIO(), false, false, hereString), io[valueScope]);
43827
44037
  } catch (error) {
43828
44038
  if (error instanceof NounsetFailure) throw error;
43829
44039
  if (error instanceof ParameterExpansionFailure && !isolatedInlineInput) throw error;
@@ -43832,10 +44042,10 @@ var Runtime = class _Runtime {
43832
44042
  throw error;
43833
44043
  }
43834
44044
  if (hereString) {
43835
- if (import_buffer.Buffer.byteLength(value2) >= this.budget.limits.maxExpansionBytes) this.budget.fail("maxExpansionBytes");
43836
- value2 += "\n";
44045
+ if (shellValueByteLength(value2) >= this.budget.limits.maxExpansionBytes) this.budget.fail("maxExpansionBytes");
44046
+ value2 = concatShellValues([value2, "\n"], io[valueScope]);
43837
44047
  }
43838
- const input3 = new ShellInput(toByteSource(value2), this.budget, this.signal);
44048
+ const input3 = new ShellInput(toByteSource(typeof value2 === "string" ? value2 : shellValueBytes(value2, io[valueScope])), this.budget, this.signal);
43839
44049
  inputs2.add(input3);
43840
44050
  descriptors.set(redirect.descriptor, { input: input3, stdinIsDefault: false });
43841
44051
  continue;
@@ -46343,7 +46553,91 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46343
46553
  async part(part, state, io, hereString = false) {
46344
46554
  return shellValueText(await this.valuePart(part, state, io, hereString));
46345
46555
  }
46556
+ async *prefixNames(prefix3, state) {
46557
+ const allocation = this.budget.values.scope();
46558
+ const store = arrayStore(state);
46559
+ const holding = store?.owner.hold();
46560
+ const work = { remaining: Math.min(Number.MAX_SAFE_INTEGER, this.budget.limits.maxExpansionBytes * 4 + 1024), signal: this.signal, exhausted: () => this.budget.fail("maxExpansionBytes") };
46561
+ try {
46562
+ allocation.reserveBytes(128);
46563
+ const names = [];
46564
+ const seen = /* @__PURE__ */ new Set();
46565
+ let bytes3 = 0;
46566
+ const consider = async (name2, assigned) => {
46567
+ const scanned = await scanString(name2, work);
46568
+ const pending = stringCheckpoint(work, name2.length + 1);
46569
+ if (pending) await pending;
46570
+ if (!assigned || !name2.startsWith(prefix3) || seen.has(name2)) return;
46571
+ for (let index = 0; index < name2.length; index++) {
46572
+ const pending2 = stringCheckpoint(work);
46573
+ if (pending2) await pending2;
46574
+ const code = name2.charCodeAt(index);
46575
+ if (!(code === 95 || code >= 65 && code <= 90 || code >= 97 && code <= 122 || index > 0 && code >= 48 && code <= 57)) return;
46576
+ }
46577
+ if (names.length >= this.budget.limits.maxExpansionFields) this.budget.fail("maxExpansionFields");
46578
+ if (scanned.bytes > this.budget.limits.maxExpansionBytes - bytes3) this.budget.fail("maxExpansionBytes");
46579
+ bytes3 += scanned.bytes;
46580
+ allocation.reserveBytes(name2.length * 2 + 64);
46581
+ seen.add(name2);
46582
+ names.push(name2);
46583
+ };
46584
+ for (const name2 in state.variables) if (Object.hasOwn(state.variables, name2)) await consider(name2, state.variables[name2] !== void 0);
46585
+ if (store) for (const [name2, entry] of store.bindings) await consider(name2, entry.binding.assigned);
46586
+ for (const frame of state.locals) for (const [name2, saved] of frame) {
46587
+ await consider(name2, saved.value !== void 0 || typedSavedVariables.get(saved)?.binding?.assigned === true);
46588
+ }
46589
+ await sortExpansionStrings(names, work);
46590
+ for (const name2 of names) {
46591
+ const pending = stringCheckpoint(work);
46592
+ if (pending) await pending;
46593
+ yield name2;
46594
+ }
46595
+ } finally {
46596
+ allocation.close();
46597
+ holding?.release();
46598
+ }
46599
+ }
46346
46600
  async valuePart(part, state, io, hereString = false) {
46601
+ if (part.kind === "variable" && part.transform) {
46602
+ const selector2 = getArraySelector(part);
46603
+ if (selector2?.kind === "members" || part.name === "@" || part.name === "*") {
46604
+ const members = selector2 ? await this.arrayMembers(part.name, state) : this.positionalValues(state);
46605
+ const ifs = state.variables.IFS ?? " ";
46606
+ const separator = ifs.length ? String.fromCodePoint(ifs.codePointAt(0)) : "";
46607
+ const fragments = [];
46608
+ let bytes3 = 0;
46609
+ for (const member2 of members) {
46610
+ const value3 = await this.transformValue(member2, part.transform, state, io);
46611
+ bytes3 += shellValueByteLength(value3) + (fragments.length ? import_buffer.Buffer.byteLength(separator) : 0);
46612
+ if (bytes3 > this.budget.limits.maxExpansionBytes) this.budget.fail("maxExpansionBytes");
46613
+ io[valueScope]?.reserve(32, 0);
46614
+ if (fragments.length) fragments.push(separator);
46615
+ fragments.push(value3);
46616
+ }
46617
+ return concatShellValues(fragments, io[valueScope]);
46618
+ }
46619
+ const base = { ...part };
46620
+ delete base.transform;
46621
+ copyArraySelector(part, base);
46622
+ const existing2 = selector2?.kind === "element" ? arrayStore(state)?.get(part.name)?.get(numericIndex(selector2.index) ?? -1) ?? (numericIndex(selector2.index) === 0 ? this.variable(state, part.name) : void 0) : /^[a-zA-Z_][a-zA-Z_0-9]*$/u.test(part.name) ? this.variable(state, part.name) : /^[1-9][0-9]*$/u.test(part.name) ? state.positional[Number(part.name) - 1] : "";
46623
+ const value2 = await this.valuePart(base, state, io, hereString);
46624
+ return existing2 === void 0 ? "" : this.transformValue(value2, part.transform, state, io);
46625
+ }
46626
+ if (part.kind === "variable" && part.prefixNames) {
46627
+ const ifs = state.variables.IFS ?? " ";
46628
+ const separator = io.nameExpansionContext === "document" || io.nameExpansionContext === "conditional" && part.prefixNames === "@" ? " " : ifs.length ? String.fromCodePoint(ifs.codePointAt(0)) : "";
46629
+ const fragments = [];
46630
+ let bytes3 = 0;
46631
+ for await (const name2 of this.prefixNames(part.name, state)) {
46632
+ const join = fragments.length ? separator : "";
46633
+ bytes3 += import_buffer.Buffer.byteLength(name2) + import_buffer.Buffer.byteLength(join);
46634
+ if (bytes3 > this.budget.limits.maxExpansionBytes) this.budget.fail("maxExpansionBytes");
46635
+ io[valueScope]?.reserve((name2.length + join.length) * 2 + 32, 0);
46636
+ fragments.push(join, name2);
46637
+ }
46638
+ io[valueScope]?.reserve(bytes3 * 2, 0);
46639
+ return fragments.join("");
46640
+ }
46347
46641
  const binding = part.kind === "variable" ? arrayStore(state)?.get(part.name) : void 0;
46348
46642
  const holding = binding ? requireArrays(state).owner.hold() : void 0;
46349
46643
  const selector = getArraySelector(part);
@@ -46365,6 +46659,19 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46365
46659
  if (state.depth + parameterDepth > 64) throw new ShellSyntaxError("Syntax nesting exceeds 64", word.offset);
46366
46660
  return { ...io, parameterDepth };
46367
46661
  }
46662
+ async transformValue(value2, operator, state, io) {
46663
+ const allocation = io[valueScope] ?? this.budget.values.scope();
46664
+ try {
46665
+ return await transformParameter(value2, operator, {
46666
+ maximumBytes: this.budget.limits.maxExpansionBytes,
46667
+ byteLocale: byteLocale(state.variables),
46668
+ allocation,
46669
+ work: { remaining: Math.min(Number.MAX_SAFE_INTEGER, this.budget.limits.maxExpansionBytes * 8 + 1024), signal: this.signal, exhausted: () => this.budget.fail("maxExpansionBytes") }
46670
+ });
46671
+ } finally {
46672
+ if (!io[valueScope]) allocation.close();
46673
+ }
46674
+ }
46368
46675
  async partValue(part, state, io, hereString) {
46369
46676
  this.signal.throwIfAborted();
46370
46677
  if (part.kind === "compound-substitution-eof") {
@@ -46733,7 +47040,8 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46733
47040
  }
46734
47041
  return fields3;
46735
47042
  }
46736
- const arrayOwned = word.parts.some((part) => part.kind === "variable" && (getArraySelector(part) !== void 0 || arrayStore(state)?.get(part.name) !== void 0));
47043
+ const arrayOwned = word.parts.some((part) => part.kind === "variable" && !part.prefixNames && (getArraySelector(part) !== void 0 || arrayStore(state)?.get(part.name) !== void 0));
47044
+ const prefixOwned = word.parts.some((part) => part.kind === "variable" && (part.prefixNames === "@" || part.transform && part.name === "@"));
46737
47045
  const owner = arrayOwned ? requireArrays(state).owner : void 0;
46738
47046
  const holding = owner?.hold();
46739
47047
  const scratch = !owner && split4 && state.variables.IFS !== "" && word.parts.some((part) => !part.quoted && part.kind !== "text") ? this.budget.values.scope() : void 0;
@@ -46742,11 +47050,13 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46742
47050
  owner?.reserve({ metadata: 128 + word.parts.length * 32, allocatedSlots: word.parts.length + 1, work: word.parts.length + 5 });
46743
47051
  scratch?.reserve(word.parts.length * 32, 0);
46744
47052
  const fields3 = [];
47053
+ let emptyNameGroups;
47054
+ let quoteGroup;
46745
47055
  const addField = () => {
46746
47056
  if (fields3.length >= this.budget.limits.maxExpansionFields) this.budget.fail("maxExpansionFields");
46747
47057
  scratch?.reserve(32, 0);
46748
47058
  owner?.reserve({ metadata: 32, allocatedSlots: 1, work: 3 });
46749
- fields3.push({ fragments: [], bytes: false, patterns: void 0, present: false });
47059
+ fields3.push({ fragments: [], bytes: false, patterns: void 0, present: false, independentPresence: false });
46750
47060
  };
46751
47061
  addField();
46752
47062
  let expansionBytes = 0;
@@ -46779,6 +47089,14 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46779
47089
  regexAppend?.(text3, !glob);
46780
47090
  field2.fragments.push(value2);
46781
47091
  field2.present ||= present;
47092
+ if (present) {
47093
+ if (size > 0 || !quoteGroup) field2.independentPresence = true;
47094
+ else {
47095
+ io[valueScope]?.reserve(32, 0);
47096
+ field2.quoteGroups ??= [];
47097
+ field2.quoteGroups.push(quoteGroup);
47098
+ }
47099
+ }
46782
47100
  };
46783
47101
  const appendSplit = async (value2) => {
46784
47102
  this.budget.cpuCheckpoint();
@@ -46827,7 +47145,8 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46827
47145
  const parts = word.parts.map((part) => ({ part, splitText: false, io }));
46828
47146
  for (let index = 0; index < parts.length; index++) {
46829
47147
  const { part, splitText, io: partIO } = parts[index];
46830
- const quotedPresence = part.quoted && !(arrayOwned && isQuoteMarker(part));
47148
+ quoteGroup = prefixNameQuoteGroups.get(part);
47149
+ const quotedPresence = part.quoted && !((arrayOwned || prefixOwned) && isQuoteMarker(part));
46831
47150
  if (part.kind === "variable" && ["-", "+", ":-", ":+"].includes(part.operator ?? "") && /^[a-zA-Z_][a-zA-Z_0-9]*$/u.test(part.name)) {
46832
47151
  const value2 = this.variable(state, part.name);
46833
47152
  const missing = value2 === void 0 || part.operator.startsWith(":") && value2 === "";
@@ -46841,19 +47160,36 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46841
47160
  }
46842
47161
  }
46843
47162
  const selector = getArraySelector(part);
46844
- if (part.kind === "variable" && selector?.kind === "members" && !part.length && split4 && (!part.quoted || selector.separator === "@")) {
46845
- const members = await this.arrayMembers(part.name, state);
47163
+ if (part.kind === "variable" && part.prefixNames === "@" && split4 && (part.quoted || state.variables.IFS === "")) {
47164
+ let position = 0;
47165
+ for await (const name2 of this.prefixNames(part.name, state)) {
47166
+ if (position++) addField();
47167
+ append(name2, !part.quoted, true);
47168
+ }
47169
+ if (position === 0 && quoteGroup) {
47170
+ io[valueScope]?.reserve(32, 0);
47171
+ emptyNameGroups ??= /* @__PURE__ */ new Set();
47172
+ emptyNameGroups.add(quoteGroup);
47173
+ }
47174
+ } else if (part.kind === "variable" && split4 && (selector?.kind === "members" && !part.length && (!part.quoted || selector.separator === "@") || part.transform && part.name === "@")) {
47175
+ const members = selector?.kind === "members" ? await this.arrayMembers(part.name, state) : this.positionalValues(state);
46846
47176
  for (let position = 0; position < members.length; position++) {
46847
47177
  if (position > 0) addField();
46848
- const value2 = members[position];
46849
- if (part.quoted || state.variables.IFS === "") append(value2, !part.quoted, part.quoted || value2.length > 0);
47178
+ const original = members[position];
47179
+ const value2 = part.transform ? await this.transformValue(original, part.transform, state, partIO) : original;
47180
+ if (part.quoted || state.variables.IFS === "") append(value2, !part.quoted, part.quoted || shellValueByteLength(value2) > 0);
46850
47181
  else await appendSplit(value2);
46851
47182
  }
47183
+ if (part.transform && members.length === 0 && quoteGroup) {
47184
+ io[valueScope]?.reserve(32, 0);
47185
+ emptyNameGroups ??= /* @__PURE__ */ new Set();
47186
+ emptyNameGroups.add(quoteGroup);
47187
+ }
46852
47188
  } else if (part.kind === "text" && !splitText) {
46853
47189
  let value2 = invokedValues.get(part) ?? part.byteValue ?? part.value;
46854
47190
  if (typeof value2 === "string" && index === 0 && !part.quoted && /^~(?:\/|$)/u.test(value2)) value2 = (state.variables.HOME ?? "~") + value2.slice(1);
46855
47191
  append(value2, !part.quoted, quotedPresence || shellValueByteLength(value2) > 0);
46856
- } else if (part.kind === "variable" && part.name === "@" && part.quoted && !part.operator && split4) {
47192
+ } else if (part.kind === "variable" && part.name === "@" && part.quoted && !part.operator && !part.transform && split4) {
46857
47193
  for (let position = 0; position < state.positional.length; position++) {
46858
47194
  if (position > 0) addField();
46859
47195
  append(stateMonitor(state)?.positionals.get(String(position), state.positional[position]) ?? state.positional[position], false, true);
@@ -46871,6 +47207,19 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46871
47207
  let resultBytes = 0;
46872
47208
  for (const field2 of fields3) {
46873
47209
  if (!field2.present && split4) continue;
47210
+ if (split4 && !field2.independentPresence && field2.quoteGroups) {
47211
+ const work = { remaining: this.budget.limits.maxExpansionBytes, signal: this.signal, exhausted: () => this.budget.fail("maxExpansionBytes") };
47212
+ let empty2 = true;
47213
+ for (const group of field2.quoteGroups) {
47214
+ const pending = stringCheckpoint(work);
47215
+ if (pending) await pending;
47216
+ if (!emptyNameGroups?.has(group)) {
47217
+ empty2 = false;
47218
+ break;
47219
+ }
47220
+ }
47221
+ if (empty2) continue;
47222
+ }
46874
47223
  if (scratch && field2.fragments.length > 1 && !field2.bytes) scratch.reserve(field2.fragments.reduce((bytes3, value2) => bytes3 + shellValueText(value2).length * 2, 0), 0);
46875
47224
  const assembled = concatShellValues(field2.fragments, io[valueScope]);
46876
47225
  const projection = shellValueText(assembled);
@@ -47141,33 +47490,7 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
47141
47490
  if (!ignored(error)) throw error;
47142
47491
  }
47143
47492
  }
47144
- const compare6 = async (left, right) => {
47145
- for (let index = 0; index < Math.min(left.length, right.length); index++) {
47146
- const pending = stringCheckpoint(work);
47147
- if (pending) await pending;
47148
- const difference = left.charCodeAt(index) - right.charCodeAt(index);
47149
- if (difference) return difference;
47150
- }
47151
- return left.length - right.length;
47152
- };
47153
- const sift = async (root, end) => {
47154
- while (root * 2 + 1 < end) {
47155
- let child = root * 2 + 1;
47156
- if (child + 1 < end && await compare6(found[child], found[child + 1]) < 0) child++;
47157
- if (await compare6(found[root], found[child]) >= 0) return;
47158
- const saved = found[root];
47159
- found[root] = found[child];
47160
- found[child] = saved;
47161
- root = child;
47162
- }
47163
- };
47164
- for (let index = Math.floor(found.length / 2) - 1; index >= 0; index--) await sift(index, found.length);
47165
- for (let end = found.length - 1; end > 0; end--) {
47166
- const saved = found[0];
47167
- found[0] = found[end];
47168
- found[end] = saved;
47169
- await sift(0, end);
47170
- }
47493
+ await sortExpansionStrings(found, work);
47171
47494
  return found.length ? found : [value2];
47172
47495
  } finally {
47173
47496
  scratch.close();
@@ -49866,15 +50189,15 @@ function* entities2(text3) {
49866
50189
  const predefined = { amp: "&", lt: "<", gt: ">", quot: '"', apos: "'" };
49867
50190
  if (Object.hasOwn(predefined, entity)) result2 += predefined[entity];
49868
50191
  else {
49869
- const hexadecimal = entity.startsWith("#x");
49870
- const digits = entity.slice(hexadecimal ? 2 : 1);
50192
+ const hexadecimal2 = entity.startsWith("#x");
50193
+ const digits = entity.slice(hexadecimal2 ? 2 : 1);
49871
50194
  if (!entity.startsWith("#") || !digits.length) invalid("undeclared entity");
49872
50195
  let point = 0;
49873
50196
  for (let index = 0; index < digits.length; index++) {
49874
50197
  const code = digits.charCodeAt(index);
49875
- const digit3 = code >= 48 && code <= 57 ? code - 48 : hexadecimal && code >= 65 && code <= 70 ? code - 55 : hexadecimal && code >= 97 && code <= 102 ? code - 87 : -1;
50198
+ const digit3 = code >= 48 && code <= 57 ? code - 48 : hexadecimal2 && code >= 65 && code <= 70 ? code - 55 : hexadecimal2 && code >= 97 && code <= 102 ? code - 87 : -1;
49876
50199
  if (digit3 < 0) invalid("undeclared entity");
49877
- point = point * (hexadecimal ? 16 : 10) + digit3;
50200
+ point = point * (hexadecimal2 ? 16 : 10) + digit3;
49878
50201
  if (point > 1114111) invalid("invalid character reference");
49879
50202
  if ((index + 1) % 512 === 0) yield 512;
49880
50203
  }