@poe-platform/safe-bash 0.1.93 → 0.1.95

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.
@@ -5398,6 +5398,47 @@ var ParseBudget = class {
5398
5398
  }
5399
5399
  };
5400
5400
 
5401
+ // packages/safe-bash/src/shell/source-line-index.ts
5402
+ init_platform();
5403
+ var SourceLineIndex = class {
5404
+ constructor(source, budget) {
5405
+ this.budget = budget;
5406
+ this.#source = source;
5407
+ }
5408
+ budget;
5409
+ #source;
5410
+ #scanned = 0;
5411
+ #newlines;
5412
+ get source() {
5413
+ return this.#source;
5414
+ }
5415
+ append(source) {
5416
+ this.#source += source;
5417
+ }
5418
+ lineAt(position) {
5419
+ this.budget.admit(0);
5420
+ if (!Number.isSafeInteger(position) || position < 0 || position > this.#source.length) throw new RangeError("Invalid source line position");
5421
+ if (position === 0 || position === 1 && this.#source[0] !== "\n") return 1;
5422
+ while (this.#scanned < position) {
5423
+ if (this.#scanned % 1024 === 0) this.budget.admit();
5424
+ if (this.#source.charCodeAt(this.#scanned) === 10) {
5425
+ this.budget.admit();
5426
+ (this.#newlines ??= []).push(this.#scanned);
5427
+ }
5428
+ this.#scanned++;
5429
+ }
5430
+ this.budget.admit(0);
5431
+ let low = 0;
5432
+ let high = this.#newlines?.length ?? 0;
5433
+ while (low < high) {
5434
+ const middle = low + Math.floor((high - low) / 2);
5435
+ if (this.#newlines[middle] < position) low = middle + 1;
5436
+ else high = middle;
5437
+ }
5438
+ return low + 1;
5439
+ }
5440
+ };
5441
+
5401
5442
  // packages/safe-bash/src/shell/arithmetic.ts
5402
5443
  init_platform();
5403
5444
  var ArithmeticFailure = class extends Error {
@@ -6169,7 +6210,7 @@ function printedSimpleLines(lists, separators, budget) {
6169
6210
  var IncompleteShellInput = class extends Error {
6170
6211
  };
6171
6212
  var Lexer = class {
6172
- constructor(budget, source, depth, warnings = [], lineOffset = 0, byteLocale2 = false, documentLine, partial = false) {
6213
+ constructor(budget, source, depth, warnings = [], lineOffset = 0, byteLocale2 = false, documentLine, partial = false, lineIndex = new SourceLineIndex(source, budget), sourceOffset = 0) {
6173
6214
  this.budget = budget;
6174
6215
  this.source = source;
6175
6216
  this.depth = depth;
@@ -6178,8 +6219,9 @@ var Lexer = class {
6178
6219
  this.byteLocale = byteLocale2;
6179
6220
  this.documentLine = documentLine;
6180
6221
  this.partial = partial;
6222
+ this.lineIndex = lineIndex;
6223
+ this.sourceOffset = sourceOffset;
6181
6224
  if (depth > 64) throw new ShellSyntaxError("Syntax nesting exceeds 64", 0);
6182
- for (let offset = source.indexOf("\n"); offset !== -1; offset = source.indexOf("\n", offset + 1)) this.newlineOffsets.push(offset);
6183
6225
  }
6184
6226
  budget;
6185
6227
  source;
@@ -6189,6 +6231,8 @@ var Lexer = class {
6189
6231
  byteLocale;
6190
6232
  documentLine;
6191
6233
  partial;
6234
+ lineIndex;
6235
+ sourceOffset;
6192
6236
  position = 0;
6193
6237
  operandDepth = 0;
6194
6238
  printedNewlineReduction = 0;
@@ -6197,16 +6241,8 @@ var Lexer = class {
6197
6241
  conditional = false;
6198
6242
  conditionalPattern;
6199
6243
  documents = [];
6200
- newlineOffsets = [];
6201
6244
  lineAt(position) {
6202
- let low = 0;
6203
- let high = this.newlineOffsets.length;
6204
- while (low < high) {
6205
- const middle = low + Math.floor((high - low) / 2);
6206
- if (this.newlineOffsets[middle] < position) low = middle + 1;
6207
- else high = middle;
6208
- }
6209
- return this.lineOffset + low + 1;
6245
+ return this.lineOffset + this.lineIndex.lineAt(this.sourceOffset + position) - this.lineIndex.lineAt(this.sourceOffset) + 1;
6210
6246
  }
6211
6247
  error(message2, unclosedQuote) {
6212
6248
  throw new ShellSyntaxError(message2, this.position, 2, void 0, unclosedQuote);
@@ -6595,7 +6631,7 @@ shell: command substitution: line ${line}: \`${sourceLine}'
6595
6631
  let script;
6596
6632
  try {
6597
6633
  this.budget.admit();
6598
- nested = new Parser(this.budget, this.source.slice(start), this.depth + this.operandDepth + 1, this.warnings, this.lineAt(start) - 1, void 0, this.byteLocale);
6634
+ nested = new Parser(this.budget, this.source.slice(start), this.depth + this.operandDepth + 1, this.warnings, this.lineAt(start) - 1, void 0, this.byteLocale, false, this.lineIndex, this.sourceOffset + start);
6599
6635
  script = nested.script(/* @__PURE__ */ new Set([")"]));
6600
6636
  } catch (error) {
6601
6637
  if (this.documentLine !== void 0 && error instanceof ShellSyntaxError && !/nesting|exceeds/u.test(error.reason)) throw this.documentSubstitutionError(this.source.slice(start), error);
@@ -6676,11 +6712,11 @@ shell: command substitution: line ${line}: \`${sourceLine}'
6676
6712
  }
6677
6713
  };
6678
6714
  var Parser = class {
6679
- constructor(budget, source, depth, warnings = [], lineOffset = 0, position, byteLocale2 = false, partial = false) {
6715
+ constructor(budget, source, depth, warnings = [], lineOffset = 0, position, byteLocale2 = false, partial = false, lineIndex = new SourceLineIndex(source, budget), sourceOffset = 0) {
6680
6716
  this.budget = budget;
6681
6717
  if (position === void 0 && depth === 0 && source.includes("\0")) throw new ShellSyntaxError("NUL bytes are not valid shell source", source.indexOf("\0"));
6682
6718
  budget.admit();
6683
- this.lexer = new Lexer(budget, source, depth, warnings, lineOffset, byteLocale2, void 0, partial);
6719
+ this.lexer = new Lexer(budget, source, depth, warnings, lineOffset, byteLocale2, void 0, partial, lineIndex, sourceOffset);
6684
6720
  this.lexer.position = position ?? 0;
6685
6721
  this.current = this.lexer.next();
6686
6722
  }
@@ -7038,10 +7074,11 @@ function* hereDocumentWords(document, line, byteLocale2, warnings, budget = new
7038
7074
  yield* new Lexer(budget, document.body, document.depth, warnings, line - 1, byteLocale2, line).documentWords();
7039
7075
  }
7040
7076
  }
7041
- function parseShellUnit(source, position = 0, byteLocale2 = false, budget = new ParseBudget()) {
7077
+ function parseShellUnit(source, position = 0, byteLocale2 = false, budget = new ParseBudget(), lineIndex = new SourceLineIndex(source, budget)) {
7042
7078
  const warnings = [];
7043
7079
  budget.admit();
7044
- const parser = new Parser(budget, source, 0, warnings, 0, position, byteLocale2);
7080
+ if (lineIndex.source !== source || lineIndex.budget !== budget) throw new TypeError("Source line index belongs to a different source or parse budget");
7081
+ const parser = new Parser(budget, source, 0, warnings, 0, position, byteLocale2, false, lineIndex);
7045
7082
  const script = parser.script(/* @__PURE__ */ new Set(), true);
7046
7083
  const next = parser.current.end;
7047
7084
  const nul = source.indexOf("\0", position);
@@ -7049,11 +7086,12 @@ function parseShellUnit(source, position = 0, byteLocale2 = false, budget = new
7049
7086
  budget.admit(2);
7050
7087
  return { script: { ...script, ...warnings.length ? { warnings } : {} }, next };
7051
7088
  }
7052
- function parseShellInputUnit(source, byteLocale2 = false, budget = new ParseBudget()) {
7089
+ function parseShellInputUnit(source, byteLocale2 = false, budget = new ParseBudget(), lineIndex = new SourceLineIndex(source, budget)) {
7053
7090
  const warnings = [];
7054
7091
  try {
7055
7092
  budget.admit();
7056
- const parser = new Parser(budget, source, 0, warnings, 0, 0, byteLocale2, true);
7093
+ if (lineIndex.source !== source || lineIndex.budget !== budget) throw new TypeError("Source line index belongs to a different source or parse budget");
7094
+ const parser = new Parser(budget, source, 0, warnings, 0, 0, byteLocale2, true, lineIndex);
7057
7095
  const script = parser.script(/* @__PURE__ */ new Set(), true);
7058
7096
  budget.admit(2);
7059
7097
  return { script: { ...script, ...warnings.length ? { warnings } : {} }, next: parser.current.end };
@@ -13424,12 +13462,13 @@ ${prefix2} line ${offset + line}: \`${source.split("\n")[line - 1] ?? ""}'
13424
13462
  return error.exitCode;
13425
13463
  }
13426
13464
  async runCommandString(source, state, io) {
13465
+ const lineIndex = new SourceLineIndex(source, this.budget.parsing);
13427
13466
  let position = 0;
13428
13467
  let status = 0;
13429
13468
  try {
13430
13469
  do {
13431
13470
  this.signal.throwIfAborted();
13432
- const unit = parseShellUnit(source, position, byteLocale(state.variables), this.budget.parsing);
13471
+ const unit = parseShellUnit(source, position, byteLocale(state.variables), this.budget.parsing, lineIndex);
13433
13472
  for (const warning of unit.script.warnings ?? []) await writeText(io.stderr, `${io.scriptName}: warning: ${warning}
13434
13473
  `);
13435
13474
  if (unit.script.lists.length) {
@@ -13455,6 +13494,7 @@ ${prefix2} line ${offset + line}: \`${source.split("\n")[line - 1] ?? ""}'
13455
13494
  }
13456
13495
  async runStandardInput(input3, state, io) {
13457
13496
  let source = "";
13497
+ let lineIndex = new SourceLineIndex(source, this.budget.parsing);
13458
13498
  let offset = 0;
13459
13499
  let status = 0;
13460
13500
  let lines3 = 0;
@@ -13463,10 +13503,13 @@ ${prefix2} line ${offset + line}: \`${source.split("\n")[line - 1] ?? ""}'
13463
13503
  this.signal.throwIfAborted();
13464
13504
  const bytes2 = await input3.sourceLine();
13465
13505
  const eof = bytes2 === void 0;
13466
- if (bytes2) source += this.sourceText(bytes2, io.scriptName ?? "shell");
13506
+ if (bytes2) {
13507
+ lineIndex.append(this.sourceText(bytes2, io.scriptName ?? "shell"));
13508
+ source = lineIndex.source;
13509
+ }
13467
13510
  const unitIO = { ...io, diagnosticOffset: offset };
13468
13511
  try {
13469
- const unit = eof ? parseShellUnit(source, 0, byteLocale(state.variables), this.budget.parsing) : parseShellInputUnit(source, byteLocale(state.variables), this.budget.parsing);
13512
+ const unit = eof ? parseShellUnit(source, 0, byteLocale(state.variables), this.budget.parsing, lineIndex) : parseShellInputUnit(source, byteLocale(state.variables), this.budget.parsing, lineIndex);
13470
13513
  if (unit) {
13471
13514
  for (const warning of unit.script.warnings ?? []) await writeText(io.stderr, `${io.scriptName}: warning: ${warning}
13472
13515
  `);
@@ -13477,6 +13520,7 @@ ${prefix2} line ${offset + line}: \`${source.split("\n")[line - 1] ?? ""}'
13477
13520
  }
13478
13521
  offset += source.slice(0, unit.next).split("\n").length - 1;
13479
13522
  source = source.slice(unit.next);
13523
+ lineIndex = new SourceLineIndex(source, this.budget.parsing);
13480
13524
  }
13481
13525
  } catch (error) {
13482
13526
  if (!(error instanceof ShellSyntaxError)) throw error;
@@ -13726,11 +13770,12 @@ ${prefix2} line ${offset + line}: \`${source.split("\n")[line - 1] ?? ""}'
13726
13770
  }
13727
13771
  if (direct && environmentInterpreter) return this.envShebang(context, state, io, environmentInterpreter[1], target, args, { path, source });
13728
13772
  const units = [];
13773
+ const lineIndex = new SourceLineIndex(source, this.budget.parsing);
13729
13774
  try {
13730
13775
  let position = 0;
13731
13776
  do {
13732
13777
  this.signal.throwIfAborted();
13733
- const unit = parseShellUnit(source, position, byteLocale(context.env), this.budget.parsing);
13778
+ const unit = parseShellUnit(source, position, byteLocale(context.env), this.budget.parsing, lineIndex);
13734
13779
  units.push(unit.script);
13735
13780
  position = unit.next;
13736
13781
  } while (position < source.length);
@@ -13757,13 +13802,14 @@ ${prefix2} line ${offset + line}: \`${source.split("\n")[line - 1] ?? ""}'
13757
13802
  return status;
13758
13803
  }
13759
13804
  async runCurrentText(source, state, io, fatalSyntax, syntaxName) {
13805
+ const lineIndex = new SourceLineIndex(source, this.budget.parsing);
13760
13806
  let position = 0;
13761
13807
  let status = 0;
13762
13808
  let executed = false;
13763
13809
  try {
13764
13810
  do {
13765
13811
  this.signal.throwIfAborted();
13766
- const unit = parseShellUnit(source, position, byteLocale(state.variables), this.budget.parsing);
13812
+ const unit = parseShellUnit(source, position, byteLocale(state.variables), this.budget.parsing, lineIndex);
13767
13813
  for (const warning of unit.script.warnings ?? []) await writeText(io.stderr, `${io.scriptName ?? "shell"}: warning: ${warning}
13768
13814
  `);
13769
13815
  if (unit.script.lists.length) {
@@ -16160,7 +16206,8 @@ var Shell = class {
16160
16206
  let failed = false;
16161
16207
  try {
16162
16208
  try {
16163
- let unit = parseShellUnit(source, 0, byteLocale({ ...this.#options.env, ...options3.env }), budget.parsing);
16209
+ const lineIndex = new SourceLineIndex(source, budget.parsing);
16210
+ let unit = parseShellUnit(source, 0, byteLocale({ ...this.#options.env, ...options3.env }), budget.parsing, lineIndex);
16164
16211
  stdin = new ShellInput(typeof options3.stdin === "string" || options3.stdin instanceof Uint8Array ? toByteSource(options3.stdin) : options3.stdin ?? toByteSource(""), budget);
16165
16212
  io.stdin = stdin;
16166
16213
  await interruptible(this.#ready, budget.signal);
@@ -16217,7 +16264,7 @@ var Shell = class {
16217
16264
  }
16218
16265
  if (unit.next >= source.length) break;
16219
16266
  budget.signal.throwIfAborted();
16220
- unit = parseShellUnit(source, unit.next, byteLocale(state.variables), budget.parsing);
16267
+ unit = parseShellUnit(source, unit.next, byteLocale(state.variables), budget.parsing, lineIndex);
16221
16268
  }
16222
16269
  } catch (error) {
16223
16270
  if (!(error instanceof ShellSyntaxError)) throw error;