@poe-platform/safe-bash 0.1.755 → 0.1.757

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.
Files changed (131) hide show
  1. package/dist/image-ast/index.browser.js +30 -6
  2. package/dist/image-ast/index.js +30 -6
  3. package/dist/pdf-ast/canvas.d.ts +1 -0
  4. package/dist/pdf-ast/index.js +26 -2
  5. package/dist/safe-bash/chunks/{chunk-LESPJ3OG.js → chunk-WNWIBBJZ.js} +15 -2
  6. package/dist/safe-bash/command-chunks/{chunk-S4J6MSLY.js → chunk-444OTXM7.js} +3 -3
  7. package/dist/safe-bash/command-chunks/{chunk-6AIOGLZO.js → chunk-CE6Z2ULX.js} +2 -2
  8. package/dist/safe-bash/command-chunks/{chunk-5VSGEE6J.js → chunk-F4IQCXZG.js} +5 -5
  9. package/dist/safe-bash/command-chunks/{chunk-F5MORDSU.js → chunk-FDNCPZQS.js} +32 -1
  10. package/dist/safe-bash/command-chunks/{chunk-SG3ZDZCX.js → chunk-FLMLM7Y4.js} +2 -2
  11. package/dist/safe-bash/command-chunks/{chunk-XRVNFK7Z.js → chunk-H2FQA4OU.js} +26 -2
  12. package/dist/safe-bash/command-chunks/{chunk-CT3FB722.js → chunk-J7UMKBRK.js} +1 -1
  13. package/dist/safe-bash/command-chunks/{chunk-KB2LQ4HG.js → chunk-KBBI4CSU.js} +2 -2
  14. package/dist/safe-bash/command-chunks/{chunk-QQOAK7JQ.js → chunk-KKJCKPTA.js} +1 -1
  15. package/dist/safe-bash/command-chunks/{chunk-7KS6PX4U.js → chunk-KSIGF4AG.js} +3 -3
  16. package/dist/safe-bash/command-chunks/{chunk-4HQ7WYSI.js → chunk-MED2BOOW.js} +30 -5
  17. package/dist/safe-bash/command-chunks/{chunk-JRNLDPLI.js → chunk-OZSWW23M.js} +1 -1
  18. package/dist/safe-bash/command-chunks/{chunk-DKQ5REXF.js → chunk-QDPRSPHQ.js} +1 -1
  19. package/dist/safe-bash/command-chunks/{chunk-WOPU2VWF.js → chunk-RID3B5RE.js} +1 -1
  20. package/dist/safe-bash/command-chunks/{chunk-DVZCHNB5.js → chunk-S4MLIYSN.js} +7 -7
  21. package/dist/safe-bash/command-chunks/{chunk-REYTQLLB.js → chunk-TT2DMDBY.js} +1 -1
  22. package/dist/safe-bash/command-chunks/{chunk-UGX6MXDD.js → chunk-UIIT4ULR.js} +3 -3
  23. package/dist/safe-bash/command-chunks/{chunk-MENC7RPR.js → chunk-WI35236J.js} +1 -1
  24. package/dist/safe-bash/command-chunks/{chunk-A6NFLWZI.js → chunk-WKPOGTZY.js} +22 -6
  25. package/dist/safe-bash/command-chunks/{chunk-3DOHQQJR.js → chunk-Y64PA6IA.js} +8 -8
  26. package/dist/safe-bash/command-chunks/{chunk-6Z7OS3TZ.js → chunk-ZP5KDHB4.js} +7 -7
  27. package/dist/safe-bash/commands/pandoc/index.d.ts +1 -1
  28. package/dist/safe-bash/commands/pandoc/index.js +5 -3
  29. package/dist/safe-bash/commands/python/index.browser.js +1 -1
  30. package/dist/safe-bash/commands/python/index.js +6 -0
  31. package/dist/safe-bash/commands/python/jspi.js +11 -2
  32. package/dist/safe-bash/core.browser.js +6 -4
  33. package/dist/safe-bash-command-csvkit/index.js +8 -8
  34. package/dist/safe-bash-command-ffmpeg/index.js +20 -2
  35. package/dist/safe-bash-command-imagemagick/index.js +2 -2
  36. package/dist/safe-bash-command-pandoc/command.js +3 -3
  37. package/dist/safe-bash-command-pandoc/index.js +3 -3
  38. package/dist/safe-bash-command-pdfimages/index.js +26 -2
  39. package/dist/safe-bash-command-pdfinfo/index.js +26 -2
  40. package/dist/safe-bash-command-pdftk/index.js +26 -2
  41. package/dist/safe-bash-command-pdftoppm/index.js +26 -2
  42. package/dist/safe-bash-command-pdftotext/index.js +26 -2
  43. package/dist/safe-bash-command-qpdf/index.js +26 -2
  44. package/dist/safe-bash-command-sips/index.js +2 -2
  45. package/dist/safe-bash-command-soffice/index.js +17 -17
  46. package/dist/safe-bash-command-ssconvert/core.js +8 -8
  47. package/dist/safe-bash-command-ssconvert/formats/csv.js +9 -9
  48. package/dist/safe-bash-command-ssconvert/formats/ods.js +8 -8
  49. package/dist/safe-bash-command-ssconvert/formats/spreadsheetml.js +1 -1
  50. package/dist/safe-bash-command-ssconvert/formats/xls.js +9 -8
  51. package/dist/safe-bash-command-ssconvert/formats/xlsx.js +8 -8
  52. package/dist/safe-bash-command-ssconvert/index.js +133 -29
  53. package/dist/safe-bash-command-wkhtmltopdf/index.js +26 -2
  54. package/dist/safe-bash-contracts/filesystem-descriptor.js +1 -1
  55. package/dist/safe-bash-contracts/filesystem-output.js +1 -1
  56. package/dist/safe-bash-mcp/index.js +4 -4
  57. package/dist/spreadsheet-engine/formulas/ast.d.ts +13 -0
  58. package/dist/spreadsheet-engine/formulas/conventions.js +1 -1
  59. package/dist/spreadsheet-engine/formulas/dependencies.js +2 -2
  60. package/dist/spreadsheet-engine/formulas/evaluator.js +2 -2
  61. package/dist/spreadsheet-engine/formulas/named-expressions.d.ts +2 -2
  62. package/dist/spreadsheet-engine/formulas/named-expressions.js +31 -5
  63. package/dist/spreadsheet-engine/formulas/parser.js +34 -0
  64. package/dist/spreadsheet-engine/formulas/rewriting.js +19 -1
  65. package/dist/spreadsheet-engine/formulas/serialization.js +6 -0
  66. package/dist/spreadsheet-format-xls/biff-write-formulas.js +2 -0
  67. package/dist/xlsx-ast/formula-semantics.js +2 -0
  68. package/package.json +2 -2
  69. package/third-party/pdf-ast/THIRD_PARTY_NOTICES.md +1 -1
  70. package/dist/safe-bash/chunks/browser-ECQX6GMK.js +0 -6766
  71. package/dist/safe-bash/chunks/bz2-4OP3OWW3.js +0 -8
  72. package/dist/safe-bash/chunks/chunk-22XPAAOI.js +0 -173
  73. package/dist/safe-bash/chunks/chunk-44WUNUPV.js +0 -649
  74. package/dist/safe-bash/chunks/chunk-4E3SGG37.js +0 -876
  75. package/dist/safe-bash/chunks/chunk-4QTSSQKP.js +0 -898
  76. package/dist/safe-bash/chunks/chunk-5UVGPVXP.js +0 -410
  77. package/dist/safe-bash/chunks/chunk-64OE6Q6X.js +0 -3487
  78. package/dist/safe-bash/chunks/chunk-6IIFUPN2.js +0 -1526
  79. package/dist/safe-bash/chunks/chunk-6XDKK63A.js +0 -38959
  80. package/dist/safe-bash/chunks/chunk-BENDLTQD.js +0 -7065
  81. package/dist/safe-bash/chunks/chunk-BMO5LWEX.js +0 -534
  82. package/dist/safe-bash/chunks/chunk-BPMCPTNP.js +0 -1920
  83. package/dist/safe-bash/chunks/chunk-BRJTAWP5.js +0 -2955
  84. package/dist/safe-bash/chunks/chunk-C3GEIN7Q.js +0 -20054
  85. package/dist/safe-bash/chunks/chunk-CEWCRI6H.js +0 -2813
  86. package/dist/safe-bash/chunks/chunk-CGL53DQQ.js +0 -37
  87. package/dist/safe-bash/chunks/chunk-CTYJJD4O.js +0 -869
  88. package/dist/safe-bash/chunks/chunk-CWSS4MQA.js +0 -7
  89. package/dist/safe-bash/chunks/chunk-DLIGMTCP.js +0 -3266
  90. package/dist/safe-bash/chunks/chunk-EMAJ7WUW.js +0 -1031
  91. package/dist/safe-bash/chunks/chunk-FDKIZ2IJ.js +0 -1950
  92. package/dist/safe-bash/chunks/chunk-FZWJ2A7V.js +0 -3093
  93. package/dist/safe-bash/chunks/chunk-G2VCIF2J.js +0 -22
  94. package/dist/safe-bash/chunks/chunk-GVKBUQDX.js +0 -2649
  95. package/dist/safe-bash/chunks/chunk-IO2OGW3E.js +0 -28051
  96. package/dist/safe-bash/chunks/chunk-ISCZG7WA.js +0 -2648
  97. package/dist/safe-bash/chunks/chunk-JEFBTRY7.js +0 -174814
  98. package/dist/safe-bash/chunks/chunk-KJHDD4A2.js +0 -759
  99. package/dist/safe-bash/chunks/chunk-LB6HVRXS.js +0 -857
  100. package/dist/safe-bash/chunks/chunk-LLWAJOZH.js +0 -15
  101. package/dist/safe-bash/chunks/chunk-LMUKYZIJ.js +0 -708
  102. package/dist/safe-bash/chunks/chunk-M5SCNKIK.js +0 -2012
  103. package/dist/safe-bash/chunks/chunk-MJPFHANT.js +0 -3350
  104. package/dist/safe-bash/chunks/chunk-MZQW2DOL.js +0 -82
  105. package/dist/safe-bash/chunks/chunk-NB2V7EOY.js +0 -1348
  106. package/dist/safe-bash/chunks/chunk-NJVGOIYN.js +0 -17
  107. package/dist/safe-bash/chunks/chunk-OLNZHDIQ.js +0 -5141
  108. package/dist/safe-bash/chunks/chunk-OUUVROTM.js +0 -38
  109. package/dist/safe-bash/chunks/chunk-PA6GYKBQ.js +0 -151
  110. package/dist/safe-bash/chunks/chunk-PEFHZ226.js +0 -6957
  111. package/dist/safe-bash/chunks/chunk-QBB5P5KW.js +0 -4839
  112. package/dist/safe-bash/chunks/chunk-QHB7HBLA.js +0 -2317
  113. package/dist/safe-bash/chunks/chunk-RSAWYAEH.js +0 -973
  114. package/dist/safe-bash/chunks/chunk-UWLYRWT4.js +0 -739
  115. package/dist/safe-bash/chunks/chunk-V463NBQH.js +0 -13
  116. package/dist/safe-bash/chunks/chunk-WPUALYUS.js +0 -843
  117. package/dist/safe-bash/chunks/chunk-XHKFSRGU.js +0 -5747
  118. package/dist/safe-bash/chunks/chunk-XHRCLZ3N.js +0 -13391
  119. package/dist/safe-bash/chunks/chunk-XPF5XHLY.js +0 -15
  120. package/dist/safe-bash/chunks/chunk-ZBFOWARG.js +0 -305
  121. package/dist/safe-bash/chunks/chunk-ZG7GWQ5P.js +0 -1859
  122. package/dist/safe-bash/chunks/model-store-EIY3ZQLZ.js +0 -10
  123. package/dist/safe-bash/chunks/pdf-renderer-XIFUTX34.js +0 -22
  124. package/dist/safe-bash/chunks/pptx-ZL6L7KP2-O425BFIU.js +0 -30658
  125. package/dist/safe-bash/chunks/src-HHEPGR7U.js +0 -18969
  126. package/dist/safe-bash/chunks/src-V4VCM5OX.js +0 -187
  127. package/dist/safe-bash/chunks/usage-6TGVA2OM.js +0 -35
  128. package/dist/safe-bash/chunks/xz-EGQGQUEI.js +0 -8
  129. package/dist/safe-bash/chunks/xz-K2E2WLM6.js +0 -9
  130. package/dist/safe-bash/chunks/zstd-6JBLP5EF.js +0 -8
  131. package/dist/safe-bash/git_rust-C3QYOAZL.wasm +0 -0
@@ -40688,7 +40688,7 @@ var init_dist = __esm({
40688
40688
  this.cachedContentAst = parseContentStream(bytes);
40689
40689
  this.isolatedInitialStream = false;
40690
40690
  const stm = cosStream(bytes, { compress });
40691
- dictSet(this.pageDict, "Contents", this.cosDoc.allocateObject(stm));
40691
+ this.replaceContentStream(stm);
40692
40692
  this.cachedContentsNode = dictGet(this.pageDict, "Contents");
40693
40693
  }
40694
40694
  getIsolatedContentAst() {
@@ -40705,9 +40705,33 @@ var init_dist = __esm({
40705
40705
  this.cachedContentAst = [...nodes];
40706
40706
  const bytes = serializeContentAst(this.cachedContentAst);
40707
40707
  const streamObj = cosStream(bytes, { compress });
40708
- dictSet(this.pageDict, "Contents", this.cosDoc.allocateObject(streamObj));
40708
+ this.replaceContentStream(streamObj);
40709
40709
  this.cachedContentsNode = dictGet(this.pageDict, "Contents");
40710
40710
  }
40711
+ replaceContentStream(stream) {
40712
+ const contents = dictGet(this.pageDict, "Contents");
40713
+ if (contents?.kind === "ref") {
40714
+ let references = 0;
40715
+ const pending = [...this.cosDoc.objects.values()].map((object) => object.value);
40716
+ const visited = /* @__PURE__ */ new Set();
40717
+ while (pending.length > 0 && references < 2) {
40718
+ const node = pending.pop();
40719
+ if (node.kind === "ref") {
40720
+ if (node.objectNumber === contents.objectNumber && node.generationNumber === contents.generationNumber) references++;
40721
+ } else if (!visited.has(node)) {
40722
+ visited.add(node);
40723
+ if (node.kind === "array") for (const item of node.items) pending.push(item);
40724
+ else if (node.kind === "dict") for (const entry of node.entries) pending.push(entry.value);
40725
+ else if (node.kind === "stream") pending.push(node.dict);
40726
+ }
40727
+ }
40728
+ if (references === 1) {
40729
+ this.cosDoc.setObject(contents.objectNumber, stream, contents.generationNumber);
40730
+ return;
40731
+ }
40732
+ }
40733
+ dictSet(this.pageDict, "Contents", this.cosDoc.allocateObject(stream));
40734
+ }
40711
40735
  drawText(text, options) {
40712
40736
  const size = options.size ?? options.fontSize ?? 12;
40713
40737
  const color = options.color ?? { r: 0, g: 0, b: 0 };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  openCommandFile
3
- } from "../safe-bash/command-chunks/chunk-7KS6PX4U.js";
3
+ } from "../safe-bash/command-chunks/chunk-KSIGF4AG.js";
4
4
  import "../safe-bash/command-chunks/chunk-PTLDMI4O.js";
5
5
  import "../safe-bash/command-chunks/chunk-U6CJOXRY.js";
6
6
  import "../safe-bash/command-chunks/chunk-WYJTWJZ5.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  openCommandFile
3
- } from "../safe-bash/command-chunks/chunk-7KS6PX4U.js";
3
+ } from "../safe-bash/command-chunks/chunk-KSIGF4AG.js";
4
4
  import {
5
5
  assertCountedFileOutput,
6
6
  bindFileOutputBudget,
@@ -14397,7 +14397,7 @@ function forwardFileDescriptor(descriptor, operation, capabilities, snapshot = (
14397
14397
  write: (retained, buffer, position, options) => operation("write", options, () => retained.write(buffer, position, options)),
14398
14398
  truncate: (retained, length, options) => operation("ftruncate", options, () => retained.truncate(length, options)),
14399
14399
  sync: (retained, dataOnly, options) => operation(dataOnly ? "fdatasync" : "fsync", options, () => retained.sync(dataOnly, options)),
14400
- close: (retained) => operation("close", {}, () => retained.close())
14400
+ close: (retained, options) => operation("close", {}, () => retained.close(options))
14401
14401
  };
14402
14402
  }
14403
14403
  function integer(value, syscall, path6) {
@@ -14565,10 +14565,10 @@ var ManagedFileDescriptor = class {
14565
14565
  await backend.sync(backend.resource, dataOnly, forwarded);
14566
14566
  });
14567
14567
  }
14568
- close() {
14568
+ close(options = {}) {
14569
14569
  this.#closing ??= this.#pending.then(async () => {
14570
14570
  try {
14571
- await this.#backend.close(this.#backend.resource);
14571
+ await this.#backend.close(this.#backend.resource, options);
14572
14572
  } finally {
14573
14573
  this.#backend = void 0;
14574
14574
  this.#getPosition = void 0;
@@ -14626,7 +14626,7 @@ async function openFileDescriptor(path6, options, capabilities, acquire) {
14626
14626
  signal?.throwIfAborted();
14627
14627
  return descriptor;
14628
14628
  } catch (error) {
14629
- await finishCleanup(() => backend.close(backend.resource), true);
14629
+ await finishCleanup(() => backend.close(backend.resource, {}), true);
14630
14630
  signal?.throwIfAborted();
14631
14631
  throw error;
14632
14632
  }
@@ -13,6 +13,17 @@ export interface Axis {
13
13
  readonly value: number;
14
14
  readonly relative: boolean;
15
15
  }
16
+ /** A binary-format name use retains identity while copies displace its definition.
17
+ * Offsets apply to references resolved at the current definition's declaration
18
+ * anchor. Copy adds row/column deltas only in relative mode and always adds tab
19
+ * displacement unless sheetRelative is false; moving leaves offsets intact. */
20
+ export interface NameRelocation {
21
+ readonly relative: boolean;
22
+ readonly row: number;
23
+ readonly column: number;
24
+ readonly sheet: number;
25
+ readonly sheetRelative?: boolean;
26
+ }
16
27
  export interface ReferenceEndpoint {
17
28
  readonly row?: Axis;
18
29
  readonly column?: Axis;
@@ -62,6 +73,7 @@ export type FormulaNode = Span & ({
62
73
  readonly kind: "name";
63
74
  readonly name: string;
64
75
  readonly sheet?: string;
76
+ readonly relocation?: NameRelocation;
65
77
  /** Empty means the current workbook; without a sheet it selects only global names. */
66
78
  readonly workbook?: string;
67
79
  } | {
@@ -117,6 +129,7 @@ export interface FormulaGrammar {
117
129
  readonly quotedLabels?: "openformula" | "calc";
118
130
  /** Permit ssconvert's live label anchors in internal workbook expressions. */
119
131
  readonly internalLabels?: boolean;
132
+ readonly internalNames?: boolean;
120
133
  readonly quotedErrors?: boolean;
121
134
  readonly rangeSeparator?: string;
122
135
  readonly sheetSpans?: boolean;
@@ -25,7 +25,7 @@ export const odfGrammar = Object.freeze({ ...gnumericGrammar,
25
25
  prefixes: Object.freeze(["of:=", "oooc:=", "="]), functionPrefixes: Object.freeze(["ORG.GNUMERIC.", "COM.MICROSOFT."])
26
26
  });
27
27
  /** Internal OpenFormula preserves relative sheets alongside live label anchors. */
28
- export const internalOdfGrammar = Object.freeze({ ...odfGrammar, internalLabels: true });
28
+ export const internalOdfGrammar = Object.freeze({ ...odfGrammar, internalLabels: true, internalNames: true });
29
29
  export const sylkGrammar = Object.freeze({ ...gnumericGrammar, id: "sylk", address: "r1c1" });
30
30
  /** Native SYLK output quotes strings without escaping; its reader does not invert that operation. */
31
31
  export const sylkWriterGrammar = Object.freeze({ ...sylkGrammar, id: "sylk-writer", stringEscape: "raw" });
@@ -80,7 +80,7 @@ export function buildDependencyGraph(book, roots, resolve, parse, tick, onRange,
80
80
  const name = named(node, position);
81
81
  if (!name || names.has(name))
82
82
  return [];
83
- return staticRanges(parseNamedExpression(name, book, parse, tick, maximumDepth), position, new Set([...names, name]), depth + 1);
83
+ return staticRanges(parseNamedExpression(name, book, parse, tick, maximumDepth, node.relocation), position, new Set([...names, name]), depth + 1);
84
84
  }
85
85
  if (node.kind === "call" && (node.name === "IF" || node.name === "CHOOSE")) {
86
86
  const ranges = [];
@@ -188,7 +188,7 @@ export function buildDependencyGraph(book, roots, resolve, parse, tick, onRange,
188
188
  if (node.kind === "name" && (node.workbook === undefined || node.workbook === "")) {
189
189
  const name = named(node, position);
190
190
  if (name && !names.has(name)) {
191
- pending.push({ node: parseNamedExpression(name, book, parse, tick, maximumDepth), position, names: new Set([...names, name]), depth: depth + 1 });
191
+ pending.push({ node: parseNamedExpression(name, book, parse, tick, maximumDepth, node.relocation), position, names: new Set([...names, name]), depth: depth + 1 });
192
192
  }
193
193
  }
194
194
  const children = node.kind === "unary" || node.kind === "parentheses" ? [node.child] : node.kind === "binary" ? [node.left, node.right] : node.kind === "call" ? node.args : node.kind === "array" ? node.rows.flat() : [];
@@ -175,7 +175,7 @@ export function* recalculateWorkbookSteps(input, context, options = false, onDia
175
175
  const name = book.names?.find(entry => entry.sheet === sheet && matches(entry)) ?? book.names?.find(entry => entry.sheet === undefined && matches(entry));
176
176
  if (!name || names.has(name))
177
177
  return error("#REF!");
178
- return indirectRange(parseNamedExpression(name, book, parse, tick, context.limits.formulaDependencyDepth ?? Infinity), position, new Set([...names, name]), depth + 1);
178
+ return indirectRange(parseNamedExpression(name, book, parse, tick, context.limits.formulaDependencyDepth ?? Infinity, node.relocation), position, new Set([...names, name]), depth + 1);
179
179
  }
180
180
  function scalar(value, position) {
181
181
  // OpenFormula §5.10.4 selects at the formula position when the consumer
@@ -264,7 +264,7 @@ export function* recalculateWorkbookSteps(input, context, options = false, onDia
264
264
  const name = book.names?.find(entry => entry.sheet === sheet && matches(entry)) ?? book.names?.find(entry => entry.sheet === undefined && matches(entry));
265
265
  if (!name || names.has(name))
266
266
  return error("#NAME?");
267
- return evaluate(parseNamedExpression(name, book, parse, tick, context.limits.formulaDependencyDepth ?? Infinity), position, array, new Set([...names, name]), wantReference);
267
+ return evaluate(parseNamedExpression(name, book, parse, tick, context.limits.formulaDependencyDepth ?? Infinity, node.relocation), position, array, new Set([...names, name]), wantReference);
268
268
  }
269
269
  if (node.kind === "unary") {
270
270
  const apply = (value) => {
@@ -1,6 +1,6 @@
1
1
  import { type NamedExpression, type Workbook } from "../../spreadsheet-ast/index.js";
2
- import type { FormulaNode, ParsePosition } from "./ast.js";
2
+ import type { FormulaNode, NameRelocation, ParsePosition } from "./ast.js";
3
3
  /** Parse relative offsets at the declaration anchor and bind nested names there.
4
4
  * References and functions in the resulting expression still use the caller's
5
5
  * evaluation position, as in native expr_name_eval. */
6
- export declare function parseNamedExpression(name: NamedExpression, book: Workbook, parse: (source: string, position: ParsePosition, arrayStringLiterals?: boolean) => FormulaNode, tick: () => void, maximumDepth?: number): FormulaNode;
6
+ export declare function parseNamedExpression(name: NamedExpression, book: Workbook, parse: (source: string, position: ParsePosition, arrayStringLiterals?: boolean) => FormulaNode, tick: () => void, maximumDepth?: number, relocation?: NameRelocation): FormulaNode;
@@ -4,23 +4,49 @@ import { foldSheetName } from "../../spreadsheet-ast/case-fold.js";
4
4
  /** Parse relative offsets at the declaration anchor and bind nested names there.
5
5
  * References and functions in the resulting expression still use the caller's
6
6
  * evaluation position, as in native expr_name_eval. */
7
- export function parseNamedExpression(name, book, parse, tick, maximumDepth = Infinity) {
7
+ export function parseNamedExpression(name, book, parse, tick, maximumDepth = Infinity, relocation) {
8
8
  if (name.expression === "" || name.expression === "=") {
9
9
  tick();
10
10
  return { kind: "literal", value: { kind: "blank" }, start: 0, end: 0 };
11
11
  }
12
12
  const position = name.position ?? { sheet: name.sheet ?? book.sheets[0]?.id ?? "", row: 0, column: 0 };
13
+ function displace(ref, fallback) {
14
+ if (!relocation || ref.workbook !== undefined)
15
+ return ref;
16
+ const origin = book.sheets.findIndex(sheet => sheet.id === position.sheet);
17
+ const index = ref.sheetRelative ? origin + (ref.sheetOffset ?? 0) : ref.sheet !== undefined || fallback !== undefined
18
+ ? book.sheets.findIndex(sheet => foldSheetName(sheet.name) === foldSheetName(ref.sheet ?? fallback)) : origin;
19
+ const target = index >= 0 ? book.sheets[index + relocation.sheet] : undefined;
20
+ if (!target)
21
+ return undefined;
22
+ const axis = (value, key) => ({ value: value.value + (value.relative ? position[key] : 0) + relocation[key], relative: false });
23
+ return { ...ref, sheet: target.name, sheetRelative: false, ...(ref.row ? { row: axis(ref.row, "row") } : {}), ...(ref.column ? { column: axis(ref.column, "column") } : {}) };
24
+ }
13
25
  function bind(node, depth = 0) {
14
26
  tick();
15
27
  if (depth > maximumDepth)
16
28
  throw new SsconvertError("resource-limit", "ssconvert formula dependency depth limit exceeded");
17
- if (node.kind === "name" && (node.workbook === undefined || node.workbook === "" && node.sheet !== undefined)) {
29
+ if (node.kind === "reference" && relocation) {
30
+ const first = displace(node.first), last = node.last ? displace(node.last, node.first.sheet) : undefined;
31
+ if (!first || node.last && !last)
32
+ return { kind: "literal", value: { kind: "error", value: "#REF!" }, start: node.start, end: node.end };
33
+ return { ...node, first, ...(last ? { last } : {}) };
34
+ }
35
+ if (node.kind === "name" && (node.workbook === undefined || node.workbook === "")) {
36
+ const inherited = relocation ? { ...relocation,
37
+ row: relocation.row + (node.relocation?.row ?? 0), column: relocation.column + (node.relocation?.column ?? 0),
38
+ sheet: relocation.sheet + (node.relocation?.sheet ?? 0) } : node.relocation;
39
+ const bound = inherited ? { ...node, relocation: inherited } : node;
40
+ if (node.workbook === "" && node.sheet === undefined)
41
+ return bound;
18
42
  const scope = node.sheet === undefined ? name.sheet : book.sheets.find(sheet => foldSheetName(sheet.name) === foldSheetName(node.sheet))?.id;
19
43
  const target = resolveName(book, node.name, scope);
20
- if (target?.sheet === undefined)
21
- return { kind: "name", name: node.name, workbook: "", start: node.start, end: node.end };
44
+ if (target?.sheet === undefined) {
45
+ const { sheet: ignoredSheet, ...global } = bound;
46
+ return { ...global, workbook: "" };
47
+ }
22
48
  const sheet = book.sheets.find(sheet => sheet.id === target.sheet);
23
- return sheet ? { ...node, sheet: sheet.name } : node;
49
+ return sheet ? { ...bound, sheet: sheet.name } : bound;
24
50
  }
25
51
  if (node.kind === "parentheses" || node.kind === "unary")
26
52
  return { ...node, child: bind(node.child, depth + 1) };
@@ -335,6 +335,40 @@ export function parseExpression(source, options) {
335
335
  throw new SsconvertError("resource-limit", "ssconvert formula node limit exceeded");
336
336
  try {
337
337
  const c = source[offset];
338
+ if (source.startsWith("@name.", offset)) {
339
+ if (grammar.id !== "gnumeric" && !grammar.internalNames)
340
+ fail("Internal live name in native formula");
341
+ offset += 6;
342
+ const relative = source.startsWith("relative", offset);
343
+ if (!relative && !source.startsWith("absolute", offset))
344
+ fail("Invalid live name mode");
345
+ offset += 8;
346
+ const fixedSheet = source.startsWith(".fixed-sheet", offset);
347
+ if (fixedSheet)
348
+ offset += 12;
349
+ if (source[offset++] !== "[")
350
+ fail("Invalid live name mode");
351
+ const displacement = (separator) => {
352
+ const start = offset;
353
+ if (source[offset] === "-")
354
+ offset++;
355
+ const begin = offset;
356
+ while (digit(source[offset]))
357
+ offset++;
358
+ const value = Number(source.slice(start, offset));
359
+ if (offset === begin || !Number.isSafeInteger(value) || source[offset++] !== separator)
360
+ fail("Invalid live name displacement");
361
+ return value;
362
+ };
363
+ const row = displacement(","), column = displacement(","), sheet = displacement("]");
364
+ if (!relative && (row !== 0 || column !== 0) || source[offset++] !== ":" || source[offset] !== '"')
365
+ fail("Invalid live name");
366
+ const name = quoted('"', grammar.stringEscape);
367
+ if (!name)
368
+ fail("Empty live name");
369
+ options.onName?.(name);
370
+ return node({ kind: "name", name, workbook: "", relocation: { relative, row, column, sheet, ...(fixedSheet ? { sheetRelative: false } : {}) }, start, end: offset });
371
+ }
338
372
  if (c === "@" && !internalLabels)
339
373
  fail("Internal label reference in native formula");
340
374
  if (c === "@" && internalLabels) {
@@ -1,6 +1,6 @@
1
1
  import { SsconvertError } from "../contracts.js";
2
2
  import { foldSheetName } from "../../spreadsheet-ast/case-fold.js";
3
- import { serializeReference, serializeLabelReference, quoteFormulaString } from "./serialization.js";
3
+ import { serializeExpression, serializeReference, serializeLabelReference, quoteFormulaString } from "./serialization.js";
4
4
  export function visitFormula(node, visitor) {
5
5
  visitor(node);
6
6
  if (node.kind === "unary" || node.kind === "parentheses")
@@ -106,6 +106,24 @@ export function rewriteReferences(document, edit) {
106
106
  : serializeReference(first, last, document.grammar, position) });
107
107
  }
108
108
  }
109
+ else if (node.kind === "name" && node.relocation && edit.translation === "copy") {
110
+ const relocation = { ...node.relocation };
111
+ if (relocation.relative) {
112
+ relocation.row += target.row - document.position.row;
113
+ relocation.column += target.column - document.position.column;
114
+ }
115
+ if (relocation.sheetRelative !== false && target.sheet !== document.position.sheet) {
116
+ const origin = document.sheetOrder?.indexOf(document.position.sheet) ?? -1;
117
+ const destination = document.sheetOrder?.indexOf(target.sheet) ?? -1;
118
+ if (origin < 0 || destination < 0)
119
+ throw new SsconvertError("invalid-request", "Cross-sheet formula copy requires workbook tab order");
120
+ relocation.sheet += destination - origin;
121
+ }
122
+ if (![relocation.row, relocation.column, relocation.sheet].every(Number.isSafeInteger))
123
+ throw new SsconvertError("invalid-request", "Invalid live name displacement");
124
+ const text = serializeExpression({ ...document, root: { ...node, relocation } }, document.grammar, false).slice(document.grammar.prefixes[0]?.length ?? 0);
125
+ changes.push({ start: node.start, end: node.end, text });
126
+ }
109
127
  else if (node.kind === "name" && (node.workbook === undefined || node.workbook === "") && node.sheet && renamedSheet(node.sheet) !== undefined) {
110
128
  const text = quoteFormulaString(renamedSheet(node.sheet), "'", document.grammar) + document.grammar.sheetSeparator + node.name;
111
129
  changes.push({ start: node.start, end: node.end, text: document.grammar.bracketReferences ? "[" + text + "]" : text });
@@ -161,6 +161,12 @@ export function serializeExpression(document, grammar = document.grammar, preser
161
161
  case "reference": return value.label ? grammar.quotedLabels === "openformula" && options.quotedLabel
162
162
  ? quoteFormulaString(options.quotedLabel(value), "'", grammar) : serializeLabelReference(value, grammar, position) : serializeReference(options.relativeSheets === "fixed" ? { ...value.first, sheetRelative: false } : value.first, options.relativeSheets === "fixed" && value.last ? { ...value.last, sheetRelative: false } : value.last, grammar, position);
163
163
  case "name": {
164
+ if (value.relocation) {
165
+ if (grammar.id !== "gnumeric" && !grammar.internalNames)
166
+ throw new SsconvertError("unsupported-feature", "Unsupported ssconvert feature: live name relocation in target grammar");
167
+ const { relative, row, column, sheet } = value.relocation;
168
+ return `@name.${relative ? "relative" : "absolute"}${value.relocation.sheetRelative === false ? ".fixed-sheet" : ""}[${row},${column},${sheet}]:` + quoteFormulaString(value.name, '"', grammar);
169
+ }
164
170
  if (grammar.qualifiedNames === false && (value.sheet !== undefined || value.workbook !== undefined))
165
171
  throw new SsconvertError("unsupported-feature", "Unsupported ssconvert feature: qualified formula name in target grammar");
166
172
  if (value.workbook === "" && grammar.bracketReferences && value.sheet === undefined)
@@ -366,6 +366,8 @@ export class BiffFormulaWriter {
366
366
  push(first);
367
367
  }
368
368
  else if (node.kind === "name") {
369
+ if (node.relocation)
370
+ throw new SsconvertError("unsupported-feature", "Unsupported ssconvert feature: live name relocation in BIFF output");
369
371
  if (node.workbook) {
370
372
  const bookIndex = this.externalBook(node.workbook), book = this.externalBooks[bookIndex];
371
373
  const scope = node.sheet === undefined ? undefined : this.externalScope(bookIndex, node.sheet);
@@ -19,6 +19,8 @@ export function nativeOpenFormula(source, position, context, arrayStringLiterals
19
19
  throw new SsconvertError("unsupported-feature", "Unsupported ssconvert feature: automatic label intersection in Gnumeric output");
20
20
  if (node.kind === "reference" && node.label)
21
21
  throw new SsconvertError("unsupported-feature", "Unsupported ssconvert feature: live label reference in Gnumeric output");
22
+ if (node.kind === "name" && node.relocation)
23
+ throw new SsconvertError("unsupported-feature", "Unsupported ssconvert feature: live name relocation in Gnumeric output");
22
24
  });
23
25
  if (!source.startsWith("of:="))
24
26
  return source;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poe-platform/safe-bash",
3
- "version": "0.1.755",
3
+ "version": "0.1.757",
4
4
  "description": "Extensible virtual shell with pluggable filesystems and streaming commands",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -837,7 +837,7 @@
837
837
  "access": "public"
838
838
  },
839
839
  "dependencies": {
840
- "@poe-platform/safe-fs": "0.1.755",
840
+ "@poe-platform/safe-fs": "0.1.757",
841
841
  "pdf-lib": "1.17.1",
842
842
  "@noble/hashes": "2.4.0",
843
843
  "pako": "3.0.1",
@@ -286,7 +286,7 @@ cases exercise direct and chained references to the shading stream.
286
286
  `tests/test_writer.py`, replacing its downloaded PDF with an in-memory page
287
287
  and checking every copy and save/reopen. Page copying follows `_writer.py`
288
288
  `_add_page`: each occurrence gets a distinct page dictionary while resources
289
- can remain shared. Content edits replace the page's Contents reference so
289
+ can remain shared. Edits to shared content replace the page's Contents reference so
290
290
  other pages retain their original stream. pypdf attribution/license is above.
291
291
 
292
292
  Windows Symbol cmap selection in `src/content/evaluator.ts` follows PDF.js