@poe-platform/safe-bash 0.1.521 → 0.1.523
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.
- package/dist/safe-bash/core.browser.js +342 -23
- package/dist/safe-bash/core.browser.js.map +3 -3
- package/dist/safe-bash/shell/arrays/bindings.d.ts +1 -0
- package/dist/safe-bash/shell/arrays/bindings.d.ts.map +1 -1
- package/dist/safe-bash/shell/arrays/bindings.js +3 -0
- package/dist/safe-bash/shell/arrays/bindings.js.map +1 -1
- package/dist/safe-bash/shell/arrays/syntax.d.ts +1 -0
- package/dist/safe-bash/shell/arrays/syntax.d.ts.map +1 -1
- package/dist/safe-bash/shell/arrays/syntax.js +4 -0
- package/dist/safe-bash/shell/arrays/syntax.js.map +1 -1
- package/dist/safe-bash/shell/parser.d.ts +1 -0
- package/dist/safe-bash/shell/parser.d.ts.map +1 -1
- package/dist/safe-bash/shell/parser.js +31 -4
- package/dist/safe-bash/shell/parser.js.map +1 -1
- package/dist/safe-bash/shell/runtime.d.ts +6 -0
- package/dist/safe-bash/shell/runtime.d.ts.map +1 -1
- package/dist/safe-bash/shell/runtime.js +381 -20
- package/dist/safe-bash/shell/runtime.js.map +1 -1
- package/dist/safe-bash/shell/shell.d.ts.map +1 -1
- package/dist/safe-bash/shell/shell.js +1 -0
- package/dist/safe-bash/shell/shell.js.map +1 -1
- package/package.json +2 -2
|
@@ -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,18 @@ 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 === "`"))
|
|
38123
|
-
|
|
38126
|
+
} else if (!literal && (inner === "$" || inner === "`")) {
|
|
38127
|
+
this.expansion(parts, true);
|
|
38128
|
+
const part = parts.at(-1);
|
|
38129
|
+
nameListing ||= part.kind === "variable" && part.prefixNames === "@";
|
|
38130
|
+
} else if (inner === "\\" && /[$`"\\\n]/u.test(this.source[this.position + 1] ?? "")) {
|
|
38124
38131
|
const escaped3 = this.source[this.position + 1];
|
|
38125
38132
|
if (escaped3 !== "\n") text3(escaped3, true, false, this.position, this.position + 2);
|
|
38126
38133
|
else this.printedNewlineReduction++;
|
|
@@ -38132,6 +38139,15 @@ shell: command substitution: line ${line}: \`${sourceLine}'
|
|
|
38132
38139
|
}
|
|
38133
38140
|
if (this.source[this.position] !== '"' && !this.braceReplay) this.error("Unterminated double quote", { quote: '"', line: quoteLine });
|
|
38134
38141
|
if (parts.length === quoteParts) setQuoteMarker(parts.at(-1), false);
|
|
38142
|
+
if (nameListing) {
|
|
38143
|
+
this.budget.admit();
|
|
38144
|
+
const group = {};
|
|
38145
|
+
for (let index = quoteParts - 1; index < parts.length; index++) {
|
|
38146
|
+
this.budget.admit();
|
|
38147
|
+
const part = parts[index];
|
|
38148
|
+
if (index !== quoteParts - 1 || isQuoteMarker(part) || part.kind !== "text" || part.value !== "") prefixNameQuoteGroups.set(part, group);
|
|
38149
|
+
}
|
|
38150
|
+
}
|
|
38135
38151
|
const spelling2 = expansionSpellings.get(parts.at(-1));
|
|
38136
38152
|
if (spelling2) spelling2.end = Math.min(this.position + 1, this.source.length);
|
|
38137
38153
|
if (this.position < this.source.length) this.position++;
|
|
@@ -38291,11 +38307,20 @@ shell: command substitution: line ${line}: \`${sourceLine}'
|
|
|
38291
38307
|
} else if (this.source[this.position] === "{") {
|
|
38292
38308
|
this.position++;
|
|
38293
38309
|
const parameterStart = this.position - 2;
|
|
38294
|
-
const
|
|
38310
|
+
const listing = this.source[this.position] === "!";
|
|
38311
|
+
if (listing) this.position++;
|
|
38312
|
+
const length = !listing && this.source[this.position] === "#" && /[a-zA-Z_]/u.test(this.source[this.position + 1] ?? "");
|
|
38295
38313
|
if (length) this.position++;
|
|
38296
38314
|
const name2 = /^(?:[a-zA-Z_][a-zA-Z_0-9]*|[0-9]+|[?@*#-])/u.exec(this.source.slice(this.position))?.[0];
|
|
38297
38315
|
if (!name2) this.error("Unsupported parameter expansion");
|
|
38298
38316
|
this.position += name2.length;
|
|
38317
|
+
let prefixNames;
|
|
38318
|
+
if (listing) {
|
|
38319
|
+
const separator = this.source[this.position];
|
|
38320
|
+
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");
|
|
38321
|
+
prefixNames = separator;
|
|
38322
|
+
this.position++;
|
|
38323
|
+
}
|
|
38299
38324
|
let selector;
|
|
38300
38325
|
if (this.source[this.position] === "[") {
|
|
38301
38326
|
if (!/^[a-zA-Z_][a-zA-Z_0-9]*$/u.test(name2)) this.error("Unsupported indexed-array parameter");
|
|
@@ -38348,7 +38373,7 @@ shell: command substitution: line ${line}: \`${sourceLine}'
|
|
|
38348
38373
|
parts.push({ kind: "failed-parameter", source: this.source.slice(parameterStart, this.position), line, quoted: quoted2 });
|
|
38349
38374
|
} else {
|
|
38350
38375
|
this.position++;
|
|
38351
|
-
const part = { kind: "variable", name: name2, quoted: quoted2, line, ...length ? { length } : {}, ...operator ? { operator, alternate } : {}, ...replacement ? { replacement } : {}, ...substring ? { substring } : {} };
|
|
38376
|
+
const part = { kind: "variable", name: name2, quoted: quoted2, line, ...prefixNames ? { prefixNames } : {}, ...length ? { length } : {}, ...operator ? { operator, alternate } : {}, ...replacement ? { replacement } : {}, ...substring ? { substring } : {} };
|
|
38352
38377
|
if (selector) setArraySelector(part, selector);
|
|
38353
38378
|
parts.push(part);
|
|
38354
38379
|
}
|
|
@@ -40760,6 +40785,7 @@ var IndexedBinding = class _IndexedBinding {
|
|
|
40760
40785
|
generation = 0;
|
|
40761
40786
|
version = 0;
|
|
40762
40787
|
references = 1;
|
|
40788
|
+
assigned = false;
|
|
40763
40789
|
static create(parent) {
|
|
40764
40790
|
const owner = ArrayOwner.create(parent.ledger, parent);
|
|
40765
40791
|
try {
|
|
@@ -40791,11 +40817,13 @@ var IndexedBinding = class _IndexedBinding {
|
|
|
40791
40817
|
text3.release();
|
|
40792
40818
|
};
|
|
40793
40819
|
this.values.set(index, element);
|
|
40820
|
+
this.assigned = true;
|
|
40794
40821
|
if (index > this.maximum) this.maximum = index;
|
|
40795
40822
|
previous?.slot.release();
|
|
40796
40823
|
}
|
|
40797
40824
|
async copy(signal) {
|
|
40798
40825
|
const copy2 = _IndexedBinding.create(this.owner.parent);
|
|
40826
|
+
copy2.assigned = this.assigned;
|
|
40799
40827
|
this.retain();
|
|
40800
40828
|
try {
|
|
40801
40829
|
for (const [index, element] of this.values) {
|
|
@@ -41671,6 +41699,35 @@ function resolveLimits(...limits) {
|
|
|
41671
41699
|
return result2;
|
|
41672
41700
|
}
|
|
41673
41701
|
var budgetedSinks = /* @__PURE__ */ new WeakMap();
|
|
41702
|
+
async function sortExpansionStrings(values, work) {
|
|
41703
|
+
const compare6 = async (left, right) => {
|
|
41704
|
+
for (let index = 0; index < Math.min(left.length, right.length); index++) {
|
|
41705
|
+
const pending = stringCheckpoint(work);
|
|
41706
|
+
if (pending) await pending;
|
|
41707
|
+
const difference = left.charCodeAt(index) - right.charCodeAt(index);
|
|
41708
|
+
if (difference) return difference;
|
|
41709
|
+
}
|
|
41710
|
+
return left.length - right.length;
|
|
41711
|
+
};
|
|
41712
|
+
const sift = async (root, end) => {
|
|
41713
|
+
while (root * 2 + 1 < end) {
|
|
41714
|
+
let child = root * 2 + 1;
|
|
41715
|
+
if (child + 1 < end && await compare6(values[child], values[child + 1]) < 0) child++;
|
|
41716
|
+
if (await compare6(values[root], values[child]) >= 0) return;
|
|
41717
|
+
const saved = values[root];
|
|
41718
|
+
values[root] = values[child];
|
|
41719
|
+
values[child] = saved;
|
|
41720
|
+
root = child;
|
|
41721
|
+
}
|
|
41722
|
+
};
|
|
41723
|
+
for (let index = Math.floor(values.length / 2) - 1; index >= 0; index--) await sift(index, values.length);
|
|
41724
|
+
for (let end = values.length - 1; end > 0; end--) {
|
|
41725
|
+
const saved = values[0];
|
|
41726
|
+
values[0] = values[end];
|
|
41727
|
+
values[end] = saved;
|
|
41728
|
+
await sift(0, end);
|
|
41729
|
+
}
|
|
41730
|
+
}
|
|
41674
41731
|
var Budget25 = class {
|
|
41675
41732
|
constructor(limits, signal, onInternalError) {
|
|
41676
41733
|
this.limits = limits;
|
|
@@ -41691,6 +41748,8 @@ var Budget25 = class {
|
|
|
41691
41748
|
iterations = 0;
|
|
41692
41749
|
bytes = 0;
|
|
41693
41750
|
sourceBytes = 0;
|
|
41751
|
+
globstarEntries = 0;
|
|
41752
|
+
globstarStates = 0;
|
|
41694
41753
|
controller = new AbortController();
|
|
41695
41754
|
signal;
|
|
41696
41755
|
#wallClockTimer;
|
|
@@ -41839,7 +41898,7 @@ var typedSavedVariables = /* @__PURE__ */ new WeakMap();
|
|
|
41839
41898
|
var valueScope = /* @__PURE__ */ Symbol("shell value allocation scope");
|
|
41840
41899
|
var invokedValues = /* @__PURE__ */ new WeakMap();
|
|
41841
41900
|
function isolateIO(io) {
|
|
41842
|
-
return { ...io, ...io.descriptors ? { descriptors: new Map([...io.descriptors].map(([number5, descriptor2]) => [number5, { ...descriptor2 }])) } : {} };
|
|
41901
|
+
return { ...io, nameExpansionContext: void 0, ...io.descriptors ? { descriptors: new Map([...io.descriptors].map(([number5, descriptor2]) => [number5, { ...descriptor2 }])) } : {} };
|
|
41843
41902
|
}
|
|
41844
41903
|
function activeIO(io) {
|
|
41845
41904
|
const input3 = io.descriptors?.get(0);
|
|
@@ -43036,6 +43095,7 @@ var Runtime = class _Runtime {
|
|
|
43036
43095
|
const current = store.get(name2);
|
|
43037
43096
|
if (index !== void 0 && current) {
|
|
43038
43097
|
staged = index === "members" ? IndexedBinding.create(store.owner) : await current.copy(this.signal);
|
|
43098
|
+
staged.assigned = current.assigned;
|
|
43039
43099
|
let maximum = -1;
|
|
43040
43100
|
for (const key of staged.values.keys()) {
|
|
43041
43101
|
operation2.reserve({ work: 2 }).release();
|
|
@@ -43236,7 +43296,8 @@ var Runtime = class _Runtime {
|
|
|
43236
43296
|
this.signal.throwIfAborted();
|
|
43237
43297
|
if (state.readonlyVariables?.has(name2)) throw new ArrayFailure("readonly binding");
|
|
43238
43298
|
if (!watch.valid()) throw new ArrayFailure("stale binding");
|
|
43239
|
-
|
|
43299
|
+
staged.assigned = true;
|
|
43300
|
+
if (!(assignment.kind === "compound" && assignment.append && writes === 0 && current?.assigned)) {
|
|
43240
43301
|
let released;
|
|
43241
43302
|
stateMonitor(state).publish(tickets, name2, () => {
|
|
43242
43303
|
supersede();
|
|
@@ -43539,8 +43600,8 @@ var Runtime = class _Runtime {
|
|
|
43539
43600
|
signal: this.signal,
|
|
43540
43601
|
locale: state.variables.LC_ALL || state.variables.LC_COLLATE || state.variables.LANG || "C",
|
|
43541
43602
|
work: { remaining: this.budget.limits.maxExpansionBytes, signal: this.signal, exhausted: () => this.budget.fail("maxExpansionBytes"), allocation },
|
|
43542
|
-
expand: async (word, pattern = false) => (await this.word(word, state, io, false, pattern, false, pattern)).join(""),
|
|
43543
|
-
regex: (subject, pattern) => this.ere(subject, pattern, state, io),
|
|
43603
|
+
expand: async (word, pattern = false) => (await this.word(word, state, { ...io, nameExpansionContext: "conditional" }, false, pattern, false, pattern)).join(""),
|
|
43604
|
+
regex: (subject, pattern) => this.ere(subject, pattern, state, { ...io, nameExpansionContext: "conditional" }),
|
|
43544
43605
|
option: (name2) => name2 === "braceexpand" ? state.braceexpand !== false : name2 === "errexit" ? !!state.errexit : name2 === "nounset" ? !!state.nounset : name2 === "pipefail" ? state.pipefail : false,
|
|
43545
43606
|
present: (name2) => {
|
|
43546
43607
|
const match = /^([a-zA-Z_][a-zA-Z_0-9]*)(?:\[(0|[1-9][0-9]*|[@*])\])?$/u.exec(name2);
|
|
@@ -43763,7 +43824,7 @@ var Runtime = class _Runtime {
|
|
|
43763
43824
|
for (const warning of warnings.splice(0)) await writeDiagnostic(io.stderr, `shell: warning: ${warning}
|
|
43764
43825
|
`);
|
|
43765
43826
|
if (++words % 128 === 0) await yieldTurn(this.signal);
|
|
43766
|
-
const part = (await this.word(word, state, io, false)).join("");
|
|
43827
|
+
const part = (await this.word(word, state, { ...io, nameExpansionContext: "document" }, false)).join("");
|
|
43767
43828
|
size += import_buffer.Buffer.byteLength(part);
|
|
43768
43829
|
if (size > this.budget.limits.maxExpansionBytes) this.budget.fail("maxExpansionBytes");
|
|
43769
43830
|
value2 += part;
|
|
@@ -44606,6 +44667,7 @@ ${functionDisplay(name2, state.functions.get(name2))}`;
|
|
|
44606
44667
|
getopts: { cursor: createGetoptsState(), integer: true },
|
|
44607
44668
|
directoryStack: { entries: [], bytes: 0 },
|
|
44608
44669
|
dotglob: false,
|
|
44670
|
+
globstar: false,
|
|
44609
44671
|
positional: [...args],
|
|
44610
44672
|
arg0,
|
|
44611
44673
|
profile: context2.command === "sh" ? "sh" : "bash",
|
|
@@ -45680,7 +45742,7 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
|
|
|
45680
45742
|
else if (flag === "u") unset2 = true;
|
|
45681
45743
|
else {
|
|
45682
45744
|
await this.diagnostic(context2, `shopt: ${option.startsWith("--") ? option : `-${flag}`}: unsupported option`);
|
|
45683
|
-
await writeDiagnostic(context2.stderr, "shopt: usage: shopt [-pqsu] [--] [dotglob ...]\n");
|
|
45745
|
+
await writeDiagnostic(context2.stderr, "shopt: usage: shopt [-pqsu] [--] [dotglob globstar ...]\n");
|
|
45684
45746
|
return 2;
|
|
45685
45747
|
}
|
|
45686
45748
|
}
|
|
@@ -45689,26 +45751,26 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
|
|
|
45689
45751
|
await this.diagnostic(context2, "shopt: cannot set and unset shell options simultaneously");
|
|
45690
45752
|
return 1;
|
|
45691
45753
|
}
|
|
45692
|
-
const emit2 = async () => {
|
|
45693
|
-
if (!quiet) await writeText(context2.stdout, print ? `shopt -${state
|
|
45694
|
-
` :
|
|
45754
|
+
const emit2 = async (name2) => {
|
|
45755
|
+
if (!quiet) await writeText(context2.stdout, print ? `shopt -${state[name2] ? "s" : "u"} ${name2}
|
|
45756
|
+
` : `${name2.padEnd(20)} ${state[name2] ? "on" : "off"}
|
|
45695
45757
|
`);
|
|
45696
45758
|
};
|
|
45697
45759
|
if (index === context2.args.length) {
|
|
45698
|
-
if ((!set || state
|
|
45760
|
+
for (const name2 of ["dotglob", "globstar"]) if ((!set || state[name2]) && (!unset2 || !state[name2])) await emit2(name2);
|
|
45699
45761
|
return 0;
|
|
45700
45762
|
}
|
|
45701
45763
|
let status2 = 0;
|
|
45702
45764
|
for (; index < context2.args.length; index++) {
|
|
45703
45765
|
this.signal.throwIfAborted();
|
|
45704
45766
|
const name2 = context2.args[index];
|
|
45705
|
-
if (name2 !== "dotglob") {
|
|
45706
|
-
await this.diagnostic(context2, `shopt: ${name2}: unsupported shell option name (
|
|
45767
|
+
if (name2 !== "dotglob" && name2 !== "globstar") {
|
|
45768
|
+
await this.diagnostic(context2, `shopt: ${name2}: unsupported shell option name (supported: dotglob, globstar)`);
|
|
45707
45769
|
status2 = 1;
|
|
45708
|
-
} else if (set || unset2) state
|
|
45770
|
+
} else if (set || unset2) state[name2] = set;
|
|
45709
45771
|
else {
|
|
45710
|
-
await emit2();
|
|
45711
|
-
if (!state
|
|
45772
|
+
await emit2(name2);
|
|
45773
|
+
if (!state[name2]) status2 = 1;
|
|
45712
45774
|
}
|
|
45713
45775
|
}
|
|
45714
45776
|
return status2;
|
|
@@ -46340,7 +46402,66 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
|
|
|
46340
46402
|
async part(part, state, io, hereString = false) {
|
|
46341
46403
|
return shellValueText(await this.valuePart(part, state, io, hereString));
|
|
46342
46404
|
}
|
|
46405
|
+
async *prefixNames(prefix3, state) {
|
|
46406
|
+
const allocation = this.budget.values.scope();
|
|
46407
|
+
const store = arrayStore(state);
|
|
46408
|
+
const holding = store?.owner.hold();
|
|
46409
|
+
const work = { remaining: Math.min(Number.MAX_SAFE_INTEGER, this.budget.limits.maxExpansionBytes * 4 + 1024), signal: this.signal, exhausted: () => this.budget.fail("maxExpansionBytes") };
|
|
46410
|
+
try {
|
|
46411
|
+
allocation.reserveBytes(128);
|
|
46412
|
+
const names = [];
|
|
46413
|
+
const seen = /* @__PURE__ */ new Set();
|
|
46414
|
+
let bytes3 = 0;
|
|
46415
|
+
const consider = async (name2, assigned) => {
|
|
46416
|
+
const scanned = await scanString(name2, work);
|
|
46417
|
+
const pending = stringCheckpoint(work, name2.length + 1);
|
|
46418
|
+
if (pending) await pending;
|
|
46419
|
+
if (!assigned || !name2.startsWith(prefix3) || seen.has(name2)) return;
|
|
46420
|
+
for (let index = 0; index < name2.length; index++) {
|
|
46421
|
+
const pending2 = stringCheckpoint(work);
|
|
46422
|
+
if (pending2) await pending2;
|
|
46423
|
+
const code = name2.charCodeAt(index);
|
|
46424
|
+
if (!(code === 95 || code >= 65 && code <= 90 || code >= 97 && code <= 122 || index > 0 && code >= 48 && code <= 57)) return;
|
|
46425
|
+
}
|
|
46426
|
+
if (names.length >= this.budget.limits.maxExpansionFields) this.budget.fail("maxExpansionFields");
|
|
46427
|
+
if (scanned.bytes > this.budget.limits.maxExpansionBytes - bytes3) this.budget.fail("maxExpansionBytes");
|
|
46428
|
+
bytes3 += scanned.bytes;
|
|
46429
|
+
allocation.reserveBytes(name2.length * 2 + 64);
|
|
46430
|
+
seen.add(name2);
|
|
46431
|
+
names.push(name2);
|
|
46432
|
+
};
|
|
46433
|
+
for (const name2 in state.variables) if (Object.hasOwn(state.variables, name2)) await consider(name2, state.variables[name2] !== void 0);
|
|
46434
|
+
if (store) for (const [name2, entry] of store.bindings) await consider(name2, entry.binding.assigned);
|
|
46435
|
+
for (const frame of state.locals) for (const [name2, saved] of frame) {
|
|
46436
|
+
await consider(name2, saved.value !== void 0 || typedSavedVariables.get(saved)?.binding?.assigned === true);
|
|
46437
|
+
}
|
|
46438
|
+
await sortExpansionStrings(names, work);
|
|
46439
|
+
for (const name2 of names) {
|
|
46440
|
+
const pending = stringCheckpoint(work);
|
|
46441
|
+
if (pending) await pending;
|
|
46442
|
+
yield name2;
|
|
46443
|
+
}
|
|
46444
|
+
} finally {
|
|
46445
|
+
allocation.close();
|
|
46446
|
+
holding?.release();
|
|
46447
|
+
}
|
|
46448
|
+
}
|
|
46343
46449
|
async valuePart(part, state, io, hereString = false) {
|
|
46450
|
+
if (part.kind === "variable" && part.prefixNames) {
|
|
46451
|
+
const ifs = state.variables.IFS ?? " ";
|
|
46452
|
+
const separator = io.nameExpansionContext === "document" || io.nameExpansionContext === "conditional" && part.prefixNames === "@" ? " " : ifs.length ? String.fromCodePoint(ifs.codePointAt(0)) : "";
|
|
46453
|
+
const fragments = [];
|
|
46454
|
+
let bytes3 = 0;
|
|
46455
|
+
for await (const name2 of this.prefixNames(part.name, state)) {
|
|
46456
|
+
const join = fragments.length ? separator : "";
|
|
46457
|
+
bytes3 += import_buffer.Buffer.byteLength(name2) + import_buffer.Buffer.byteLength(join);
|
|
46458
|
+
if (bytes3 > this.budget.limits.maxExpansionBytes) this.budget.fail("maxExpansionBytes");
|
|
46459
|
+
io[valueScope]?.reserve((name2.length + join.length) * 2 + 32, 0);
|
|
46460
|
+
fragments.push(join, name2);
|
|
46461
|
+
}
|
|
46462
|
+
io[valueScope]?.reserve(bytes3 * 2, 0);
|
|
46463
|
+
return fragments.join("");
|
|
46464
|
+
}
|
|
46344
46465
|
const binding = part.kind === "variable" ? arrayStore(state)?.get(part.name) : void 0;
|
|
46345
46466
|
const holding = binding ? requireArrays(state).owner.hold() : void 0;
|
|
46346
46467
|
const selector = getArraySelector(part);
|
|
@@ -46730,7 +46851,8 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
|
|
|
46730
46851
|
}
|
|
46731
46852
|
return fields3;
|
|
46732
46853
|
}
|
|
46733
|
-
const arrayOwned = word.parts.some((part) => part.kind === "variable" && (getArraySelector(part) !== void 0 || arrayStore(state)?.get(part.name) !== void 0));
|
|
46854
|
+
const arrayOwned = word.parts.some((part) => part.kind === "variable" && !part.prefixNames && (getArraySelector(part) !== void 0 || arrayStore(state)?.get(part.name) !== void 0));
|
|
46855
|
+
const prefixOwned = word.parts.some((part) => part.kind === "variable" && part.prefixNames === "@");
|
|
46734
46856
|
const owner = arrayOwned ? requireArrays(state).owner : void 0;
|
|
46735
46857
|
const holding = owner?.hold();
|
|
46736
46858
|
const scratch = !owner && split4 && state.variables.IFS !== "" && word.parts.some((part) => !part.quoted && part.kind !== "text") ? this.budget.values.scope() : void 0;
|
|
@@ -46739,11 +46861,13 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
|
|
|
46739
46861
|
owner?.reserve({ metadata: 128 + word.parts.length * 32, allocatedSlots: word.parts.length + 1, work: word.parts.length + 5 });
|
|
46740
46862
|
scratch?.reserve(word.parts.length * 32, 0);
|
|
46741
46863
|
const fields3 = [];
|
|
46864
|
+
let emptyNameGroups;
|
|
46865
|
+
let quoteGroup;
|
|
46742
46866
|
const addField = () => {
|
|
46743
46867
|
if (fields3.length >= this.budget.limits.maxExpansionFields) this.budget.fail("maxExpansionFields");
|
|
46744
46868
|
scratch?.reserve(32, 0);
|
|
46745
46869
|
owner?.reserve({ metadata: 32, allocatedSlots: 1, work: 3 });
|
|
46746
|
-
fields3.push({ fragments: [], bytes: false, patterns: void 0, present: false });
|
|
46870
|
+
fields3.push({ fragments: [], bytes: false, patterns: void 0, present: false, independentPresence: false });
|
|
46747
46871
|
};
|
|
46748
46872
|
addField();
|
|
46749
46873
|
let expansionBytes = 0;
|
|
@@ -46776,6 +46900,14 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
|
|
|
46776
46900
|
regexAppend?.(text3, !glob);
|
|
46777
46901
|
field2.fragments.push(value2);
|
|
46778
46902
|
field2.present ||= present;
|
|
46903
|
+
if (present) {
|
|
46904
|
+
if (size > 0 || !quoteGroup) field2.independentPresence = true;
|
|
46905
|
+
else {
|
|
46906
|
+
io[valueScope]?.reserve(32, 0);
|
|
46907
|
+
field2.quoteGroups ??= [];
|
|
46908
|
+
field2.quoteGroups.push(quoteGroup);
|
|
46909
|
+
}
|
|
46910
|
+
}
|
|
46779
46911
|
};
|
|
46780
46912
|
const appendSplit = async (value2) => {
|
|
46781
46913
|
this.budget.cpuCheckpoint();
|
|
@@ -46824,7 +46956,8 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
|
|
|
46824
46956
|
const parts = word.parts.map((part) => ({ part, splitText: false, io }));
|
|
46825
46957
|
for (let index = 0; index < parts.length; index++) {
|
|
46826
46958
|
const { part, splitText, io: partIO } = parts[index];
|
|
46827
|
-
|
|
46959
|
+
quoteGroup = prefixNameQuoteGroups.get(part);
|
|
46960
|
+
const quotedPresence = part.quoted && !((arrayOwned || prefixOwned) && isQuoteMarker(part));
|
|
46828
46961
|
if (part.kind === "variable" && ["-", "+", ":-", ":+"].includes(part.operator ?? "") && /^[a-zA-Z_][a-zA-Z_0-9]*$/u.test(part.name)) {
|
|
46829
46962
|
const value2 = this.variable(state, part.name);
|
|
46830
46963
|
const missing = value2 === void 0 || part.operator.startsWith(":") && value2 === "";
|
|
@@ -46838,7 +46971,18 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
|
|
|
46838
46971
|
}
|
|
46839
46972
|
}
|
|
46840
46973
|
const selector = getArraySelector(part);
|
|
46841
|
-
if (part.kind === "variable" &&
|
|
46974
|
+
if (part.kind === "variable" && part.prefixNames === "@" && split4 && (part.quoted || state.variables.IFS === "")) {
|
|
46975
|
+
let position = 0;
|
|
46976
|
+
for await (const name2 of this.prefixNames(part.name, state)) {
|
|
46977
|
+
if (position++) addField();
|
|
46978
|
+
append(name2, !part.quoted, true);
|
|
46979
|
+
}
|
|
46980
|
+
if (position === 0 && quoteGroup) {
|
|
46981
|
+
io[valueScope]?.reserve(32, 0);
|
|
46982
|
+
emptyNameGroups ??= /* @__PURE__ */ new Set();
|
|
46983
|
+
emptyNameGroups.add(quoteGroup);
|
|
46984
|
+
}
|
|
46985
|
+
} else if (part.kind === "variable" && selector?.kind === "members" && !part.length && split4 && (!part.quoted || selector.separator === "@")) {
|
|
46842
46986
|
const members = await this.arrayMembers(part.name, state);
|
|
46843
46987
|
for (let position = 0; position < members.length; position++) {
|
|
46844
46988
|
if (position > 0) addField();
|
|
@@ -46868,6 +47012,19 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
|
|
|
46868
47012
|
let resultBytes = 0;
|
|
46869
47013
|
for (const field2 of fields3) {
|
|
46870
47014
|
if (!field2.present && split4) continue;
|
|
47015
|
+
if (split4 && !field2.independentPresence && field2.quoteGroups) {
|
|
47016
|
+
const work = { remaining: this.budget.limits.maxExpansionBytes, signal: this.signal, exhausted: () => this.budget.fail("maxExpansionBytes") };
|
|
47017
|
+
let empty2 = true;
|
|
47018
|
+
for (const group of field2.quoteGroups) {
|
|
47019
|
+
const pending = stringCheckpoint(work);
|
|
47020
|
+
if (pending) await pending;
|
|
47021
|
+
if (!emptyNameGroups?.has(group)) {
|
|
47022
|
+
empty2 = false;
|
|
47023
|
+
break;
|
|
47024
|
+
}
|
|
47025
|
+
}
|
|
47026
|
+
if (empty2) continue;
|
|
47027
|
+
}
|
|
46871
47028
|
if (scratch && field2.fragments.length > 1 && !field2.bytes) scratch.reserve(field2.fragments.reduce((bytes3, value2) => bytes3 + shellValueText(value2).length * 2, 0), 0);
|
|
46872
47029
|
const assembled = concatShellValues(field2.fragments, io[valueScope]);
|
|
46873
47030
|
const projection = shellValueText(assembled);
|
|
@@ -46994,8 +47151,169 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
|
|
|
46994
47151
|
holding.release();
|
|
46995
47152
|
}
|
|
46996
47153
|
}
|
|
47154
|
+
async recursiveGlob(value2, pattern, state) {
|
|
47155
|
+
const failWalk = (message3) => {
|
|
47156
|
+
const error = new FsError("EFBIG", { syscall: "glob", message: message3 });
|
|
47157
|
+
this.budget.controller.abort(error);
|
|
47158
|
+
throw error;
|
|
47159
|
+
};
|
|
47160
|
+
const work = { remaining: Math.min(Number.MAX_SAFE_INTEGER, this.budget.limits.maxExpansionBytes * 4 + 1024), signal: this.signal, exhausted: () => this.budget.fail("maxExpansionBytes") };
|
|
47161
|
+
const scratch = this.budget.values.scope();
|
|
47162
|
+
work.allocation = scratch;
|
|
47163
|
+
try {
|
|
47164
|
+
const segments = [];
|
|
47165
|
+
let start = 0;
|
|
47166
|
+
for (let end = 0; end <= pattern.length; end++) {
|
|
47167
|
+
const pending = stringCheckpoint(work);
|
|
47168
|
+
if (pending) await pending;
|
|
47169
|
+
if (end !== pattern.length && pattern[end] !== "/") continue;
|
|
47170
|
+
if (end > start) {
|
|
47171
|
+
const bytes3 = (await scanString(pattern, work, start, end)).bytes;
|
|
47172
|
+
if (++this.budget.globstarStates > 1e5) failWalk("globstar traversal state limit exceeded");
|
|
47173
|
+
scratch.reserveBytes(bytes3 * 2 + 64);
|
|
47174
|
+
segments.push(pattern.slice(start, end));
|
|
47175
|
+
}
|
|
47176
|
+
start = end + 1;
|
|
47177
|
+
}
|
|
47178
|
+
const make = (parent, suffix2, bytes3, descend, depth) => {
|
|
47179
|
+
const separator = parent.path && parent.path !== "/" ? "/" : "";
|
|
47180
|
+
const size = parent.bytes + separator.length + bytes3;
|
|
47181
|
+
if (size > this.budget.limits.maxExpansionBytes) this.budget.fail("maxExpansionBytes");
|
|
47182
|
+
if (++this.budget.globstarStates > 1e5) failWalk("globstar traversal state limit exceeded");
|
|
47183
|
+
if (depth > 128) failWalk("globstar directory depth limit exceeded");
|
|
47184
|
+
scratch.reserveBytes(size * 2 + 128);
|
|
47185
|
+
return { path: parent.path + separator + suffix2, bytes: size, descend, depth };
|
|
47186
|
+
};
|
|
47187
|
+
const empty2 = { path: "", bytes: 0, descend: true, depth: 0 };
|
|
47188
|
+
let candidates = [make(empty2, pattern.startsWith("/") ? "/" : "", pattern.startsWith("/") ? 1 : 0, true, 0)];
|
|
47189
|
+
const ignored = (error) => {
|
|
47190
|
+
this.signal.throwIfAborted();
|
|
47191
|
+
return ["ENOENT", "ENOTDIR", "EACCES"].includes(errorCode(error) ?? "");
|
|
47192
|
+
};
|
|
47193
|
+
const read = async (candidate) => {
|
|
47194
|
+
const maxEntries = 1e5 - this.budget.globstarEntries;
|
|
47195
|
+
let entries2;
|
|
47196
|
+
try {
|
|
47197
|
+
entries2 = await interruptible3(this.fs.readdir(pathOf(state, candidate.path || "."), { signal: this.signal, maxEntries }), this.signal);
|
|
47198
|
+
} catch (error) {
|
|
47199
|
+
this.signal.throwIfAborted();
|
|
47200
|
+
if (errorCode(error) === "EFBIG") this.budget.controller.abort(error);
|
|
47201
|
+
throw error;
|
|
47202
|
+
}
|
|
47203
|
+
this.signal.throwIfAborted();
|
|
47204
|
+
if (entries2.length > maxEntries) failWalk("globstar directory entry limit exceeded");
|
|
47205
|
+
this.budget.globstarEntries += entries2.length;
|
|
47206
|
+
return entries2;
|
|
47207
|
+
};
|
|
47208
|
+
let wildcardPrefix = false;
|
|
47209
|
+
for (let index = 0; index < segments.length; index++) {
|
|
47210
|
+
const segment2 = segments[index];
|
|
47211
|
+
const terminal = index === segments.length - 1;
|
|
47212
|
+
const next = /* @__PURE__ */ new Map();
|
|
47213
|
+
const add3 = (candidate) => {
|
|
47214
|
+
const prior = next.get(candidate.path);
|
|
47215
|
+
if (!prior || candidate.descend && !prior.descend) next.set(candidate.path, candidate);
|
|
47216
|
+
};
|
|
47217
|
+
if (segment2 === "**") {
|
|
47218
|
+
const visited = /* @__PURE__ */ new Set();
|
|
47219
|
+
for (const root of candidates) {
|
|
47220
|
+
this.signal.throwIfAborted();
|
|
47221
|
+
try {
|
|
47222
|
+
if ((await interruptible3(this.fs.stat(pathOf(state, root.path || "."), { signal: this.signal }), this.signal)).type !== "directory") continue;
|
|
47223
|
+
} catch (error) {
|
|
47224
|
+
if (ignored(error)) continue;
|
|
47225
|
+
throw error;
|
|
47226
|
+
}
|
|
47227
|
+
if (!terminal || root.path) {
|
|
47228
|
+
add3(terminal && !wildcardPrefix && root.path !== "/" ? make(root, "", 0, root.descend, root.depth) : root);
|
|
47229
|
+
}
|
|
47230
|
+
const queue = root.descend ? [root] : [];
|
|
47231
|
+
while (queue.length) {
|
|
47232
|
+
const directory2 = queue.pop();
|
|
47233
|
+
if (visited.has(directory2.path)) continue;
|
|
47234
|
+
visited.add(directory2.path);
|
|
47235
|
+
let entries2;
|
|
47236
|
+
try {
|
|
47237
|
+
entries2 = await read(directory2);
|
|
47238
|
+
} catch (error) {
|
|
47239
|
+
if (ignored(error)) continue;
|
|
47240
|
+
throw error;
|
|
47241
|
+
}
|
|
47242
|
+
for (const entry of entries2) {
|
|
47243
|
+
const pending = stringCheckpoint(work);
|
|
47244
|
+
if (pending) await pending;
|
|
47245
|
+
if (entry.name === "." || entry.name === ".." || !state.dotglob && entry.name.startsWith(".")) continue;
|
|
47246
|
+
const bytes3 = (await scanString(entry.name, work)).bytes;
|
|
47247
|
+
const child = make(directory2, entry.name, bytes3, entry.type === "directory", directory2.depth + (entry.type === "directory" ? 1 : 0));
|
|
47248
|
+
if (terminal || entry.type === "directory" || entry.type === "symlink" && root.path !== "") add3(child);
|
|
47249
|
+
if (entry.type === "directory") queue.push(child);
|
|
47250
|
+
}
|
|
47251
|
+
}
|
|
47252
|
+
}
|
|
47253
|
+
wildcardPrefix = true;
|
|
47254
|
+
} else if (!/(?:^|[^\\])[*?[]/u.test(segment2)) {
|
|
47255
|
+
const literal = segment2.replace(/\\(.)/gu, "$1");
|
|
47256
|
+
const bytes3 = (await scanString(literal, work)).bytes;
|
|
47257
|
+
for (const candidate of candidates) add3(make(candidate, literal, bytes3, true, candidate.depth));
|
|
47258
|
+
} else {
|
|
47259
|
+
const matches3 = await compilePattern(segment2, work);
|
|
47260
|
+
for (const candidate of candidates) {
|
|
47261
|
+
let entries2;
|
|
47262
|
+
try {
|
|
47263
|
+
entries2 = await read(candidate);
|
|
47264
|
+
} catch (error) {
|
|
47265
|
+
if (ignored(error)) continue;
|
|
47266
|
+
throw error;
|
|
47267
|
+
}
|
|
47268
|
+
for (const entry of entries2) {
|
|
47269
|
+
const pending = stringCheckpoint(work);
|
|
47270
|
+
if (pending) await pending;
|
|
47271
|
+
if (entry.name !== "." && entry.name !== ".." && (state.dotglob || !entry.name.startsWith(".") || segment2.startsWith(".")) && await matches3(entry.name)) {
|
|
47272
|
+
add3(make(candidate, entry.name, (await scanString(entry.name, work)).bytes, true, candidate.depth));
|
|
47273
|
+
}
|
|
47274
|
+
}
|
|
47275
|
+
}
|
|
47276
|
+
wildcardPrefix = true;
|
|
47277
|
+
}
|
|
47278
|
+
candidates = [...next.values()];
|
|
47279
|
+
}
|
|
47280
|
+
const found = [];
|
|
47281
|
+
let outputBytes = 0;
|
|
47282
|
+
for (const candidate of candidates) {
|
|
47283
|
+
this.signal.throwIfAborted();
|
|
47284
|
+
try {
|
|
47285
|
+
const path = pathOf(state, candidate.path);
|
|
47286
|
+
const stat = await interruptible3(value2.endsWith("/") ? this.fs.stat(path, { signal: this.signal }) : this.fs.lstat(path, { signal: this.signal }), this.signal);
|
|
47287
|
+
if (value2.endsWith("/") && stat.type !== "directory") continue;
|
|
47288
|
+
const slash = value2.endsWith("/") && !candidate.path.endsWith("/") ? "/" : "";
|
|
47289
|
+
if (found.length >= this.budget.limits.maxExpansionFields) this.budget.fail("maxExpansionFields");
|
|
47290
|
+
outputBytes += candidate.bytes + slash.length;
|
|
47291
|
+
if (outputBytes > this.budget.limits.maxExpansionBytes) this.budget.fail("maxExpansionBytes");
|
|
47292
|
+
scratch.reserveBytes(candidate.bytes * 2 + slash.length + 8);
|
|
47293
|
+
found.push(candidate.path + slash);
|
|
47294
|
+
} catch (error) {
|
|
47295
|
+
if (!ignored(error)) throw error;
|
|
47296
|
+
}
|
|
47297
|
+
}
|
|
47298
|
+
await sortExpansionStrings(found, work);
|
|
47299
|
+
return found.length ? found : [value2];
|
|
47300
|
+
} finally {
|
|
47301
|
+
scratch.close();
|
|
47302
|
+
}
|
|
47303
|
+
}
|
|
46997
47304
|
async glob(value2, pattern, state) {
|
|
46998
47305
|
if (!/(?:^|[^\\])[*?[]/u.test(pattern)) return [value2];
|
|
47306
|
+
if (state.globstar) {
|
|
47307
|
+
const work2 = { remaining: Math.min(Number.MAX_SAFE_INTEGER, this.budget.limits.maxExpansionBytes * 4 + 1024), signal: this.signal, exhausted: () => this.budget.fail("maxExpansionBytes") };
|
|
47308
|
+
let start = 0;
|
|
47309
|
+
for (let end = 0; end <= pattern.length; end++) {
|
|
47310
|
+
const pending = stringCheckpoint(work2);
|
|
47311
|
+
if (pending) await pending;
|
|
47312
|
+
if (end !== pattern.length && pattern[end] !== "/") continue;
|
|
47313
|
+
if (end - start === 2 && pattern[start] === "*" && pattern[start + 1] === "*") return this.recursiveGlob(value2, pattern, state);
|
|
47314
|
+
start = end + 1;
|
|
47315
|
+
}
|
|
47316
|
+
}
|
|
46999
47317
|
const absolute2 = pattern.startsWith("/");
|
|
47000
47318
|
const work = { remaining: Math.min(Number.MAX_SAFE_INTEGER, this.budget.limits.maxExpansionBytes * 4 + 1024), signal: this.signal, exhausted: () => this.budget.fail("maxExpansionBytes") };
|
|
47001
47319
|
let candidates = [absolute2 ? "/" : ""];
|
|
@@ -47838,6 +48156,7 @@ var Shell = class {
|
|
|
47838
48156
|
getopts: { cursor: { index: 0 }, integer: true },
|
|
47839
48157
|
directoryStack: { entries: [], bytes: 0 },
|
|
47840
48158
|
dotglob: false,
|
|
48159
|
+
globstar: false,
|
|
47841
48160
|
status: 0,
|
|
47842
48161
|
substitutionStatus: 0,
|
|
47843
48162
|
depth: 0,
|