@poe-platform/safe-bash 0.1.524 → 0.1.526
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 +210 -8
- package/dist/safe-bash/core.browser.js.map +4 -4
- package/dist/safe-bash/shell/display.d.ts.map +1 -1
- package/dist/safe-bash/shell/display.js +2 -1
- package/dist/safe-bash/shell/display.js.map +1 -1
- package/dist/safe-bash/shell/input.d.ts +6 -0
- package/dist/safe-bash/shell/input.d.ts.map +1 -1
- package/dist/safe-bash/shell/input.js +57 -0
- package/dist/safe-bash/shell/input.js.map +1 -1
- package/dist/safe-bash/shell/parser.d.ts +5 -0
- package/dist/safe-bash/shell/parser.d.ts.map +1 -1
- package/dist/safe-bash/shell/parser.js +6 -6
- package/dist/safe-bash/shell/parser.js.map +1 -1
- package/dist/safe-bash/shell/runtime.d.ts.map +1 -1
- package/dist/safe-bash/shell/runtime.js +70 -1
- package/dist/safe-bash/shell/runtime.js.map +1 -1
- package/dist/safe-bash/shell/select-menu.d.ts +6 -0
- package/dist/safe-bash/shell/select-menu.d.ts.map +1 -0
- package/dist/safe-bash/shell/select-menu.js +103 -0
- package/dist/safe-bash/shell/select-menu.js.map +1 -0
- package/package.json +2 -2
|
@@ -38650,10 +38650,10 @@ var Parser4 = class {
|
|
|
38650
38650
|
const body = this.nonemptyScript(/* @__PURE__ */ new Set(["done"]));
|
|
38651
38651
|
this.expect("done", true);
|
|
38652
38652
|
command7 = { kind, condition, body, redirects: [] };
|
|
38653
|
-
} else if (this.is("for")) {
|
|
38654
|
-
this.advance();
|
|
38653
|
+
} else if (this.is("for") || this.is("select")) {
|
|
38654
|
+
const kind = this.advance().value;
|
|
38655
38655
|
const name2 = this.advance().value;
|
|
38656
|
-
if (!/^[a-zA-Z_][a-zA-Z_0-9]*$/u.test(name2)) this.error(
|
|
38656
|
+
if (!/^[a-zA-Z_][a-zA-Z_0-9]*$/u.test(name2)) this.error(`Invalid ${kind} variable`);
|
|
38657
38657
|
this.newlines();
|
|
38658
38658
|
let words;
|
|
38659
38659
|
if (this.is("in")) {
|
|
@@ -38662,12 +38662,12 @@ var Parser4 = class {
|
|
|
38662
38662
|
while (this.current.kind === "word") words.push(this.advance().word);
|
|
38663
38663
|
}
|
|
38664
38664
|
if (this.is(";") || this.is("\n")) this.advance();
|
|
38665
|
-
else if (words) this.error(
|
|
38665
|
+
else if (words) this.error(`Expected ${kind} separator`, true);
|
|
38666
38666
|
this.newlines();
|
|
38667
38667
|
this.expect("do", true);
|
|
38668
38668
|
const body = this.nonemptyScript(/* @__PURE__ */ new Set(["done"]));
|
|
38669
38669
|
this.expect("done", true);
|
|
38670
|
-
command7 = { kind
|
|
38670
|
+
command7 = { kind, name: name2, ...words ? { words } : {}, body, redirects: [] };
|
|
38671
38671
|
} else if (this.is("function")) {
|
|
38672
38672
|
this.advance();
|
|
38673
38673
|
if (this.current.kind !== "word" || !/^[a-zA-Z_][a-zA-Z_0-9]*$/u.test(this.current.value)) this.error("Invalid function name");
|
|
@@ -38685,7 +38685,7 @@ var Parser4 = class {
|
|
|
38685
38685
|
this.expect("(");
|
|
38686
38686
|
this.expect(")");
|
|
38687
38687
|
this.newlines();
|
|
38688
|
-
if (!["{", "(", "if", "case", "while", "until", "for", "[["].includes(this.current.value)) this.error("Expected function body");
|
|
38688
|
+
if (!["{", "(", "if", "case", "while", "until", "for", "select", "[["].includes(this.current.value)) this.error("Expected function body");
|
|
38689
38689
|
command7 = { kind: "function", name: name2, body: this.command(), redirects: [] };
|
|
38690
38690
|
} else {
|
|
38691
38691
|
if (["!", "then", "else", "elif", "fi", "do", "done", "}", "case", "esac", "select", "function", "[[", "]]"].includes(this.current.value)) this.error(`Unexpected or unsupported keyword ${this.current.value}`);
|
|
@@ -39540,6 +39540,94 @@ function evaluatePositionalArithmetic(program, options3, evaluate) {
|
|
|
39540
39540
|
}
|
|
39541
39541
|
}
|
|
39542
39542
|
|
|
39543
|
+
// packages/safe-bash/src/shell/select-menu.ts
|
|
39544
|
+
init_platform();
|
|
39545
|
+
async function selectMenu(values, columns, byteLocale2, sink, work, allocation) {
|
|
39546
|
+
allocation.reserve(64 + values.length * 32, 0);
|
|
39547
|
+
const items = [];
|
|
39548
|
+
let maximum = 0;
|
|
39549
|
+
for (const value2 of values) {
|
|
39550
|
+
const bytes3 = shellValueBytes(value2, allocation);
|
|
39551
|
+
allocation.reserve(bytes3.length * 2 + 64, 0);
|
|
39552
|
+
const decoder2 = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
|
|
39553
|
+
let text3 = "";
|
|
39554
|
+
for (let offset = 0; offset < bytes3.length; offset += 1024) {
|
|
39555
|
+
const end = Math.min(offset + 1024, bytes3.length);
|
|
39556
|
+
const pending = stringCheckpoint(work, end - offset);
|
|
39557
|
+
if (pending) await pending;
|
|
39558
|
+
if (text3 !== void 0) try {
|
|
39559
|
+
text3 += decoder2.decode(bytes3.subarray(offset, end), { stream: end < bytes3.length });
|
|
39560
|
+
} catch (error) {
|
|
39561
|
+
if (!(error instanceof TypeError) || "code" in error && error.code !== "ERR_ENCODING_INVALID_ENCODED_DATA") throw error;
|
|
39562
|
+
text3 = void 0;
|
|
39563
|
+
}
|
|
39564
|
+
}
|
|
39565
|
+
let width = 0;
|
|
39566
|
+
if (text3 !== void 0) for (const character of text3) {
|
|
39567
|
+
const pending = stringCheckpoint(work);
|
|
39568
|
+
if (pending) await pending;
|
|
39569
|
+
const point = character.codePointAt(0);
|
|
39570
|
+
if (byteLocale2 && point >= 128) {
|
|
39571
|
+
width = 0;
|
|
39572
|
+
break;
|
|
39573
|
+
}
|
|
39574
|
+
if (point < 32 || point === 127) {
|
|
39575
|
+
width = bytes3.length;
|
|
39576
|
+
break;
|
|
39577
|
+
}
|
|
39578
|
+
if (/[\p{Mn}\p{Me}\p{Cf}]/u.test(character)) continue;
|
|
39579
|
+
width += point >= 4352 && (point <= 4447 || point === 9001 || point === 9002 || point >= 11904 && point <= 42191 && point !== 12351 || point >= 44032 && point <= 55203 || point >= 63744 && point <= 64255 || point >= 65040 && point <= 65049 || point >= 65072 && point <= 65135 || point >= 65280 && point <= 65376 || point >= 65504 && point <= 65510 || point >= 127744 && point <= 129791 || point >= 131072 && point <= 262141) ? 2 : 1;
|
|
39580
|
+
}
|
|
39581
|
+
maximum = Math.max(maximum, byteLocale2 ? bytes3.length : width);
|
|
39582
|
+
items.push({ bytes: bytes3, width });
|
|
39583
|
+
}
|
|
39584
|
+
let screen = 0;
|
|
39585
|
+
if (columns) {
|
|
39586
|
+
let started = false;
|
|
39587
|
+
for (const character of columns) {
|
|
39588
|
+
const pending = stringCheckpoint(work);
|
|
39589
|
+
if (pending) await pending;
|
|
39590
|
+
if (!started && " \r\n\v\f".includes(character)) continue;
|
|
39591
|
+
if (!started && character === "+") {
|
|
39592
|
+
started = true;
|
|
39593
|
+
continue;
|
|
39594
|
+
}
|
|
39595
|
+
if (character < "0" || character > "9") break;
|
|
39596
|
+
started = true;
|
|
39597
|
+
screen = Math.min(2147483647, screen * 10 + Number(character));
|
|
39598
|
+
}
|
|
39599
|
+
}
|
|
39600
|
+
screen ||= 80;
|
|
39601
|
+
const digits = String(values.length).length;
|
|
39602
|
+
const cell2 = maximum + digits + 4;
|
|
39603
|
+
let rows2 = Math.ceil(values.length / Math.max(1, Math.floor(screen / cell2)));
|
|
39604
|
+
if (rows2 === 1) rows2 = values.length;
|
|
39605
|
+
for (let row = 0; row < rows2; row++) {
|
|
39606
|
+
let position = 0;
|
|
39607
|
+
for (let index = row; index < items.length; index += rows2) {
|
|
39608
|
+
const pending = stringCheckpoint(work);
|
|
39609
|
+
if (pending) await pending;
|
|
39610
|
+
const item = items[index];
|
|
39611
|
+
const indexWidth = position ? digits : String(rows2).length;
|
|
39612
|
+
await writeText(sink, `${String(index + 1).padStart(indexWidth)}) `);
|
|
39613
|
+
await sink.write(item.bytes);
|
|
39614
|
+
if (index + rows2 < items.length) {
|
|
39615
|
+
let from = position + indexWidth + 2 + item.width;
|
|
39616
|
+
const to = position + cell2;
|
|
39617
|
+
while (from < to) {
|
|
39618
|
+
const pending2 = stringCheckpoint(work);
|
|
39619
|
+
if (pending2) await pending2;
|
|
39620
|
+
const tab = Math.floor(to / 8) > Math.floor(from / 8);
|
|
39621
|
+
await writeText(sink, tab ? " " : " ");
|
|
39622
|
+
from += tab ? 8 - from % 8 : 1;
|
|
39623
|
+
}
|
|
39624
|
+
position += cell2;
|
|
39625
|
+
}
|
|
39626
|
+
}
|
|
39627
|
+
await writeText(sink, "\n");
|
|
39628
|
+
}
|
|
39629
|
+
}
|
|
39630
|
+
|
|
39543
39631
|
// packages/safe-bash/src/shell/locale.ts
|
|
39544
39632
|
init_platform();
|
|
39545
39633
|
function byteLocale(variables) {
|
|
@@ -39598,7 +39686,8 @@ ${nested}${scriptText(command7.body, nested)};
|
|
|
39598
39686
|
${indent}done`;
|
|
39599
39687
|
break;
|
|
39600
39688
|
case "for":
|
|
39601
|
-
|
|
39689
|
+
case "select":
|
|
39690
|
+
text3 = `${command7.kind} ${command7.name}${command7.words ? ` in ${command7.words.map(spelling).join(" ")}` : ""};
|
|
39602
39691
|
do
|
|
39603
39692
|
${nested}${scriptText(command7.body, nested)};
|
|
39604
39693
|
${indent}done`;
|
|
@@ -43857,6 +43946,64 @@ var Runtime = class _Runtime {
|
|
|
43857
43946
|
status3 = result2.status;
|
|
43858
43947
|
if (result2.stop) break;
|
|
43859
43948
|
}
|
|
43949
|
+
} else if (command7.kind === "select") {
|
|
43950
|
+
const values = command7.words ? await this.valueWords(command7.words, state, io) : this.positionalValues(state);
|
|
43951
|
+
if (!values.length) return 0;
|
|
43952
|
+
const input3 = io.stdin instanceof ShellInput ? io.stdin : new ShellInput(io.stdin, this.budget, this.signal);
|
|
43953
|
+
const work = { remaining: this.budget.limits.maxExpansionBytes * 8, signal: this.signal, exhausted: () => this.budget.fail("maxExpansionBytes") };
|
|
43954
|
+
let showMenu = true;
|
|
43955
|
+
while (true) {
|
|
43956
|
+
this.budget.loop();
|
|
43957
|
+
if (showMenu) await selectMenu(values, state.variables.COLUMNS, byteLocale(state.variables), io.stderr, work, allocation);
|
|
43958
|
+
const prompt = stateMonitor(state)?.values.get("PS3", state.variables.PS3 ?? "#? ") ?? state.variables.PS3 ?? "#? ";
|
|
43959
|
+
await io.stderr.write(shellValueBytes(prompt, allocation));
|
|
43960
|
+
const line = await input3.selectLine(allocation);
|
|
43961
|
+
if (state.readonlyVariables?.has("REPLY")) {
|
|
43962
|
+
await this.diagnostic(io, "REPLY: readonly variable");
|
|
43963
|
+
await writeText(io.stdout, "\n");
|
|
43964
|
+
return 1;
|
|
43965
|
+
}
|
|
43966
|
+
this.writeVariable(state, "REPLY", line.value);
|
|
43967
|
+
if (!line.terminated) {
|
|
43968
|
+
await writeText(io.stdout, "\n");
|
|
43969
|
+
return 1;
|
|
43970
|
+
}
|
|
43971
|
+
const bytes3 = shellValueBytes(line.value, allocation);
|
|
43972
|
+
if (!bytes3.length) {
|
|
43973
|
+
showMenu = true;
|
|
43974
|
+
continue;
|
|
43975
|
+
}
|
|
43976
|
+
let choice = 0;
|
|
43977
|
+
let phase = "start";
|
|
43978
|
+
let valid = true;
|
|
43979
|
+
let negative = false;
|
|
43980
|
+
let digits = false;
|
|
43981
|
+
for (const byte of bytes3) {
|
|
43982
|
+
const pending = stringCheckpoint(work);
|
|
43983
|
+
if (pending) await pending;
|
|
43984
|
+
if (byte === 32 || byte >= 9 && byte <= 13) {
|
|
43985
|
+
if (phase === "digits") phase = "tail";
|
|
43986
|
+
continue;
|
|
43987
|
+
}
|
|
43988
|
+
if (phase === "start" && (byte === 43 || byte === 45)) {
|
|
43989
|
+
negative = byte === 45;
|
|
43990
|
+
phase = "digits";
|
|
43991
|
+
continue;
|
|
43992
|
+
}
|
|
43993
|
+
if (phase === "tail" || byte < 48 || byte > 57) {
|
|
43994
|
+
valid = false;
|
|
43995
|
+
continue;
|
|
43996
|
+
}
|
|
43997
|
+
phase = "digits";
|
|
43998
|
+
digits = true;
|
|
43999
|
+
choice = Math.min(values.length + 1, choice * 10 + byte - 48);
|
|
44000
|
+
}
|
|
44001
|
+
await this.assignVariable(state, command7.name, valid && digits && !negative && choice >= 1 && choice <= values.length ? values[choice - 1] : "");
|
|
44002
|
+
const result2 = await this.loopBody(command7.body, state, io);
|
|
44003
|
+
status3 = result2.status;
|
|
44004
|
+
if (result2.stop) break;
|
|
44005
|
+
showMenu = shellValueByteLength(stateMonitor(state)?.values.get("REPLY", state.variables.REPLY ?? "") ?? state.variables.REPLY ?? "") === 0;
|
|
44006
|
+
}
|
|
43860
44007
|
} else {
|
|
43861
44008
|
while (true) {
|
|
43862
44009
|
this.budget.loop();
|
|
@@ -44392,6 +44539,7 @@ var Runtime = class _Runtime {
|
|
|
44392
44539
|
}
|
|
44393
44540
|
async dispatchScoped(name2, values, state, io, assignments2, bypassFunctions) {
|
|
44394
44541
|
const { [invocationScope]: scope, ...publicIO } = io;
|
|
44542
|
+
Reflect.deleteProperty(publicIO, valueScope);
|
|
44395
44543
|
const allocation = this.budget.values.scope();
|
|
44396
44544
|
scope.register(() => allocation.close());
|
|
44397
44545
|
const argumentValues = this.admitArguments(values, allocation);
|
|
@@ -44440,7 +44588,13 @@ var Runtime = class _Runtime {
|
|
|
44440
44588
|
scope.assertOpen();
|
|
44441
44589
|
const forwardedValues = getCommandArguments(forwarded);
|
|
44442
44590
|
const admitted = forwardedValues === argumentValues ? argumentValues : this.admitArguments(forwardedValues.values, allocation);
|
|
44443
|
-
const context3 = {
|
|
44591
|
+
const context3 = {
|
|
44592
|
+
...forwarded,
|
|
44593
|
+
args: admitted.args,
|
|
44594
|
+
argumentValues: admitted,
|
|
44595
|
+
[invocationScope]: scope,
|
|
44596
|
+
...io[valueScope] === void 0 ? {} : { [valueScope]: io[valueScope] }
|
|
44597
|
+
};
|
|
44444
44598
|
const previous = /* @__PURE__ */ new Map();
|
|
44445
44599
|
const cwd = state.cwd;
|
|
44446
44600
|
const directoryStackCwdPublication = state.directoryStackCwdPublication;
|
|
@@ -45037,6 +45191,8 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
|
|
|
45037
45191
|
return invocation2;
|
|
45038
45192
|
}
|
|
45039
45193
|
};
|
|
45194
|
+
Reflect.deleteProperty(context2, invocationScope);
|
|
45195
|
+
Reflect.deleteProperty(context2, valueScope);
|
|
45040
45196
|
bindCommandIO(context2);
|
|
45041
45197
|
bindFileOutputBudget(context2, (sink) => this.budget.sink(sink, runtime.signal));
|
|
45042
45198
|
if (argumentValues.values.every((value2) => typeof value2 === "string")) Reflect.deleteProperty(context2, "argumentValues");
|
|
@@ -47963,6 +48119,52 @@ var ShellInput = class _ShellInput {
|
|
|
47963
48119
|
line(raw, options3) {
|
|
47964
48120
|
return this.#cursor.consume(this.signal, () => options3 ? this.readBounded(raw, options3) : this.readLine(raw));
|
|
47965
48121
|
}
|
|
48122
|
+
/** Select uses read's escape rules without projecting raw REPLY bytes to text. */
|
|
48123
|
+
selectLine(allocation) {
|
|
48124
|
+
return this.#cursor.consume(this.signal, async () => {
|
|
48125
|
+
allocation.reserve(64, 0);
|
|
48126
|
+
const parts = [];
|
|
48127
|
+
let escaping = false;
|
|
48128
|
+
let length = 0;
|
|
48129
|
+
let pulls = 0;
|
|
48130
|
+
while (true) {
|
|
48131
|
+
if (++pulls % 128 === 0) await yieldTurn(this.signal);
|
|
48132
|
+
const result2 = await this.#cursor.take(this.signal);
|
|
48133
|
+
if (result2.done) return { value: concatShellValues(parts, allocation), terminated: false };
|
|
48134
|
+
const chunk = result2.value;
|
|
48135
|
+
for (let offset = 0; offset < chunk.length; ) {
|
|
48136
|
+
await yieldTurn(this.signal);
|
|
48137
|
+
const end = Math.min(offset + 1024, chunk.length);
|
|
48138
|
+
allocation.reserve(end - offset + 64, 0);
|
|
48139
|
+
const output2 = new Uint8Array(end - offset);
|
|
48140
|
+
let used = 0;
|
|
48141
|
+
let terminated = false;
|
|
48142
|
+
while (offset < end) {
|
|
48143
|
+
const byte = chunk[offset++];
|
|
48144
|
+
this.#cursor.position++;
|
|
48145
|
+
if (++length > this.budget.limits.maxOutputBytes) this.budget.fail("maxOutputBytes");
|
|
48146
|
+
if (byte === 0) continue;
|
|
48147
|
+
if (escaping) {
|
|
48148
|
+
escaping = false;
|
|
48149
|
+
if (byte !== 10) output2[used++] = byte;
|
|
48150
|
+
} else if (byte === 92) escaping = true;
|
|
48151
|
+
else if (byte === 10) {
|
|
48152
|
+
terminated = true;
|
|
48153
|
+
break;
|
|
48154
|
+
} else output2[used++] = byte;
|
|
48155
|
+
}
|
|
48156
|
+
if (used) {
|
|
48157
|
+
allocation.reserve(32, 0);
|
|
48158
|
+
parts.push(shellValueFromBytes(output2.subarray(0, used), allocation));
|
|
48159
|
+
}
|
|
48160
|
+
if (terminated) {
|
|
48161
|
+
if (offset < chunk.length) this.#cursor.remainder = chunk.subarray(offset);
|
|
48162
|
+
return { value: concatShellValues(parts, allocation), terminated: true };
|
|
48163
|
+
}
|
|
48164
|
+
}
|
|
48165
|
+
}
|
|
48166
|
+
});
|
|
48167
|
+
}
|
|
47966
48168
|
async readBounded(raw, options3) {
|
|
47967
48169
|
const text3 = new ReadText();
|
|
47968
48170
|
let characters = 0;
|