@poe-platform/safe-bash 0.1.521 → 0.1.522

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.
@@ -41691,6 +41691,8 @@ var Budget25 = class {
41691
41691
  iterations = 0;
41692
41692
  bytes = 0;
41693
41693
  sourceBytes = 0;
41694
+ globstarEntries = 0;
41695
+ globstarStates = 0;
41694
41696
  controller = new AbortController();
41695
41697
  signal;
41696
41698
  #wallClockTimer;
@@ -44606,6 +44608,7 @@ ${functionDisplay(name2, state.functions.get(name2))}`;
44606
44608
  getopts: { cursor: createGetoptsState(), integer: true },
44607
44609
  directoryStack: { entries: [], bytes: 0 },
44608
44610
  dotglob: false,
44611
+ globstar: false,
44609
44612
  positional: [...args],
44610
44613
  arg0,
44611
44614
  profile: context2.command === "sh" ? "sh" : "bash",
@@ -45680,7 +45683,7 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
45680
45683
  else if (flag === "u") unset2 = true;
45681
45684
  else {
45682
45685
  await this.diagnostic(context2, `shopt: ${option.startsWith("--") ? option : `-${flag}`}: unsupported option`);
45683
- await writeDiagnostic(context2.stderr, "shopt: usage: shopt [-pqsu] [--] [dotglob ...]\n");
45686
+ await writeDiagnostic(context2.stderr, "shopt: usage: shopt [-pqsu] [--] [dotglob globstar ...]\n");
45684
45687
  return 2;
45685
45688
  }
45686
45689
  }
@@ -45689,26 +45692,26 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
45689
45692
  await this.diagnostic(context2, "shopt: cannot set and unset shell options simultaneously");
45690
45693
  return 1;
45691
45694
  }
45692
- const emit2 = async () => {
45693
- if (!quiet) await writeText(context2.stdout, print ? `shopt -${state.dotglob ? "s" : "u"} dotglob
45694
- ` : `dotglob ${state.dotglob ? "on" : "off"}
45695
+ const emit2 = async (name2) => {
45696
+ if (!quiet) await writeText(context2.stdout, print ? `shopt -${state[name2] ? "s" : "u"} ${name2}
45697
+ ` : `${name2.padEnd(20)} ${state[name2] ? "on" : "off"}
45695
45698
  `);
45696
45699
  };
45697
45700
  if (index === context2.args.length) {
45698
- if ((!set || state.dotglob) && (!unset2 || !state.dotglob)) await emit2();
45701
+ for (const name2 of ["dotglob", "globstar"]) if ((!set || state[name2]) && (!unset2 || !state[name2])) await emit2(name2);
45699
45702
  return 0;
45700
45703
  }
45701
45704
  let status2 = 0;
45702
45705
  for (; index < context2.args.length; index++) {
45703
45706
  this.signal.throwIfAborted();
45704
45707
  const name2 = context2.args[index];
45705
- if (name2 !== "dotglob") {
45706
- await this.diagnostic(context2, `shopt: ${name2}: unsupported shell option name (only dotglob is supported)`);
45708
+ if (name2 !== "dotglob" && name2 !== "globstar") {
45709
+ await this.diagnostic(context2, `shopt: ${name2}: unsupported shell option name (supported: dotglob, globstar)`);
45707
45710
  status2 = 1;
45708
- } else if (set || unset2) state.dotglob = set;
45711
+ } else if (set || unset2) state[name2] = set;
45709
45712
  else {
45710
- await emit2();
45711
- if (!state.dotglob) status2 = 1;
45713
+ await emit2(name2);
45714
+ if (!state[name2]) status2 = 1;
45712
45715
  }
45713
45716
  }
45714
45717
  return status2;
@@ -46994,8 +46997,195 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46994
46997
  holding.release();
46995
46998
  }
46996
46999
  }
47000
+ async recursiveGlob(value2, pattern, state) {
47001
+ const failWalk = (message3) => {
47002
+ const error = new FsError("EFBIG", { syscall: "glob", message: message3 });
47003
+ this.budget.controller.abort(error);
47004
+ throw error;
47005
+ };
47006
+ const work = { remaining: Math.min(Number.MAX_SAFE_INTEGER, this.budget.limits.maxExpansionBytes * 4 + 1024), signal: this.signal, exhausted: () => this.budget.fail("maxExpansionBytes") };
47007
+ const scratch = this.budget.values.scope();
47008
+ work.allocation = scratch;
47009
+ try {
47010
+ const segments = [];
47011
+ let start = 0;
47012
+ for (let end = 0; end <= pattern.length; end++) {
47013
+ const pending = stringCheckpoint(work);
47014
+ if (pending) await pending;
47015
+ if (end !== pattern.length && pattern[end] !== "/") continue;
47016
+ if (end > start) {
47017
+ const bytes3 = (await scanString(pattern, work, start, end)).bytes;
47018
+ if (++this.budget.globstarStates > 1e5) failWalk("globstar traversal state limit exceeded");
47019
+ scratch.reserveBytes(bytes3 * 2 + 64);
47020
+ segments.push(pattern.slice(start, end));
47021
+ }
47022
+ start = end + 1;
47023
+ }
47024
+ const make = (parent, suffix2, bytes3, descend, depth) => {
47025
+ const separator = parent.path && parent.path !== "/" ? "/" : "";
47026
+ const size = parent.bytes + separator.length + bytes3;
47027
+ if (size > this.budget.limits.maxExpansionBytes) this.budget.fail("maxExpansionBytes");
47028
+ if (++this.budget.globstarStates > 1e5) failWalk("globstar traversal state limit exceeded");
47029
+ if (depth > 128) failWalk("globstar directory depth limit exceeded");
47030
+ scratch.reserveBytes(size * 2 + 128);
47031
+ return { path: parent.path + separator + suffix2, bytes: size, descend, depth };
47032
+ };
47033
+ const empty2 = { path: "", bytes: 0, descend: true, depth: 0 };
47034
+ let candidates = [make(empty2, pattern.startsWith("/") ? "/" : "", pattern.startsWith("/") ? 1 : 0, true, 0)];
47035
+ const ignored = (error) => {
47036
+ this.signal.throwIfAborted();
47037
+ return ["ENOENT", "ENOTDIR", "EACCES"].includes(errorCode(error) ?? "");
47038
+ };
47039
+ const read = async (candidate) => {
47040
+ const maxEntries = 1e5 - this.budget.globstarEntries;
47041
+ let entries2;
47042
+ try {
47043
+ entries2 = await interruptible3(this.fs.readdir(pathOf(state, candidate.path || "."), { signal: this.signal, maxEntries }), this.signal);
47044
+ } catch (error) {
47045
+ this.signal.throwIfAborted();
47046
+ if (errorCode(error) === "EFBIG") this.budget.controller.abort(error);
47047
+ throw error;
47048
+ }
47049
+ this.signal.throwIfAborted();
47050
+ if (entries2.length > maxEntries) failWalk("globstar directory entry limit exceeded");
47051
+ this.budget.globstarEntries += entries2.length;
47052
+ return entries2;
47053
+ };
47054
+ let wildcardPrefix = false;
47055
+ for (let index = 0; index < segments.length; index++) {
47056
+ const segment2 = segments[index];
47057
+ const terminal = index === segments.length - 1;
47058
+ const next = /* @__PURE__ */ new Map();
47059
+ const add3 = (candidate) => {
47060
+ const prior = next.get(candidate.path);
47061
+ if (!prior || candidate.descend && !prior.descend) next.set(candidate.path, candidate);
47062
+ };
47063
+ if (segment2 === "**") {
47064
+ const visited = /* @__PURE__ */ new Set();
47065
+ for (const root of candidates) {
47066
+ this.signal.throwIfAborted();
47067
+ try {
47068
+ if ((await interruptible3(this.fs.stat(pathOf(state, root.path || "."), { signal: this.signal }), this.signal)).type !== "directory") continue;
47069
+ } catch (error) {
47070
+ if (ignored(error)) continue;
47071
+ throw error;
47072
+ }
47073
+ if (!terminal || root.path) {
47074
+ add3(terminal && !wildcardPrefix && root.path !== "/" ? make(root, "", 0, root.descend, root.depth) : root);
47075
+ }
47076
+ const queue = root.descend ? [root] : [];
47077
+ while (queue.length) {
47078
+ const directory2 = queue.pop();
47079
+ if (visited.has(directory2.path)) continue;
47080
+ visited.add(directory2.path);
47081
+ let entries2;
47082
+ try {
47083
+ entries2 = await read(directory2);
47084
+ } catch (error) {
47085
+ if (ignored(error)) continue;
47086
+ throw error;
47087
+ }
47088
+ for (const entry of entries2) {
47089
+ const pending = stringCheckpoint(work);
47090
+ if (pending) await pending;
47091
+ if (entry.name === "." || entry.name === ".." || !state.dotglob && entry.name.startsWith(".")) continue;
47092
+ const bytes3 = (await scanString(entry.name, work)).bytes;
47093
+ const child = make(directory2, entry.name, bytes3, entry.type === "directory", directory2.depth + (entry.type === "directory" ? 1 : 0));
47094
+ if (terminal || entry.type === "directory" || entry.type === "symlink" && root.path !== "") add3(child);
47095
+ if (entry.type === "directory") queue.push(child);
47096
+ }
47097
+ }
47098
+ }
47099
+ wildcardPrefix = true;
47100
+ } else if (!/(?:^|[^\\])[*?[]/u.test(segment2)) {
47101
+ const literal = segment2.replace(/\\(.)/gu, "$1");
47102
+ const bytes3 = (await scanString(literal, work)).bytes;
47103
+ for (const candidate of candidates) add3(make(candidate, literal, bytes3, true, candidate.depth));
47104
+ } else {
47105
+ const matches3 = await compilePattern(segment2, work);
47106
+ for (const candidate of candidates) {
47107
+ let entries2;
47108
+ try {
47109
+ entries2 = await read(candidate);
47110
+ } catch (error) {
47111
+ if (ignored(error)) continue;
47112
+ throw error;
47113
+ }
47114
+ for (const entry of entries2) {
47115
+ const pending = stringCheckpoint(work);
47116
+ if (pending) await pending;
47117
+ if (entry.name !== "." && entry.name !== ".." && (state.dotglob || !entry.name.startsWith(".") || segment2.startsWith(".")) && await matches3(entry.name)) {
47118
+ add3(make(candidate, entry.name, (await scanString(entry.name, work)).bytes, true, candidate.depth));
47119
+ }
47120
+ }
47121
+ }
47122
+ wildcardPrefix = true;
47123
+ }
47124
+ candidates = [...next.values()];
47125
+ }
47126
+ const found = [];
47127
+ let outputBytes = 0;
47128
+ for (const candidate of candidates) {
47129
+ this.signal.throwIfAborted();
47130
+ try {
47131
+ const path = pathOf(state, candidate.path);
47132
+ const stat = await interruptible3(value2.endsWith("/") ? this.fs.stat(path, { signal: this.signal }) : this.fs.lstat(path, { signal: this.signal }), this.signal);
47133
+ if (value2.endsWith("/") && stat.type !== "directory") continue;
47134
+ const slash = value2.endsWith("/") && !candidate.path.endsWith("/") ? "/" : "";
47135
+ if (found.length >= this.budget.limits.maxExpansionFields) this.budget.fail("maxExpansionFields");
47136
+ outputBytes += candidate.bytes + slash.length;
47137
+ if (outputBytes > this.budget.limits.maxExpansionBytes) this.budget.fail("maxExpansionBytes");
47138
+ scratch.reserveBytes(candidate.bytes * 2 + slash.length + 8);
47139
+ found.push(candidate.path + slash);
47140
+ } catch (error) {
47141
+ if (!ignored(error)) throw error;
47142
+ }
47143
+ }
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
+ }
47171
+ return found.length ? found : [value2];
47172
+ } finally {
47173
+ scratch.close();
47174
+ }
47175
+ }
46997
47176
  async glob(value2, pattern, state) {
46998
47177
  if (!/(?:^|[^\\])[*?[]/u.test(pattern)) return [value2];
47178
+ if (state.globstar) {
47179
+ const work2 = { remaining: Math.min(Number.MAX_SAFE_INTEGER, this.budget.limits.maxExpansionBytes * 4 + 1024), signal: this.signal, exhausted: () => this.budget.fail("maxExpansionBytes") };
47180
+ let start = 0;
47181
+ for (let end = 0; end <= pattern.length; end++) {
47182
+ const pending = stringCheckpoint(work2);
47183
+ if (pending) await pending;
47184
+ if (end !== pattern.length && pattern[end] !== "/") continue;
47185
+ if (end - start === 2 && pattern[start] === "*" && pattern[start + 1] === "*") return this.recursiveGlob(value2, pattern, state);
47186
+ start = end + 1;
47187
+ }
47188
+ }
46999
47189
  const absolute2 = pattern.startsWith("/");
47000
47190
  const work = { remaining: Math.min(Number.MAX_SAFE_INTEGER, this.budget.limits.maxExpansionBytes * 4 + 1024), signal: this.signal, exhausted: () => this.budget.fail("maxExpansionBytes") };
47001
47191
  let candidates = [absolute2 ? "/" : ""];
@@ -47838,6 +48028,7 @@ var Shell = class {
47838
48028
  getopts: { cursor: { index: 0 }, integer: true },
47839
48029
  directoryStack: { entries: [], bytes: 0 },
47840
48030
  dotglob: false,
48031
+ globstar: false,
47841
48032
  status: 0,
47842
48033
  substitutionStatus: 0,
47843
48034
  depth: 0,