ooxml-core 0.10.0 → 0.12.0

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 (60) hide show
  1. package/README.md +10 -6
  2. package/dist/automation/docx.d.ts +13 -0
  3. package/dist/automation/docx.d.ts.map +1 -0
  4. package/dist/automation/index.cjs +36953 -0
  5. package/dist/automation/index.d.ts +6 -0
  6. package/dist/automation/index.d.ts.map +1 -0
  7. package/dist/automation/index.mjs +36939 -0
  8. package/dist/automation/node.cjs +103 -0
  9. package/dist/automation/node.d.ts +16 -0
  10. package/dist/automation/node.d.ts.map +1 -0
  11. package/dist/automation/node.mjs +101 -0
  12. package/dist/automation/visio.d.ts +30 -0
  13. package/dist/automation/visio.d.ts.map +1 -0
  14. package/dist/automation/xlsx.d.ts +25 -0
  15. package/dist/automation/xlsx.d.ts.map +1 -0
  16. package/dist/pptx/automation/index.cjs +149047 -0
  17. package/dist/pptx/automation/index.d.ts +1474 -0
  18. package/dist/pptx/automation/index.d.ts.map +1 -0
  19. package/dist/pptx/automation/index.mjs +148926 -0
  20. package/dist/pptx/chunks/{index-BWUBPGgv.d.ts → index-BWRd8p4y.d.ts} +2 -2
  21. package/dist/pptx/chunks/{index-BWUBPGgv.d.ts.map → index-BWRd8p4y.d.ts.map} +1 -1
  22. package/dist/pptx/chunks/index-LoCVDu8Z.d.ts +9644 -0
  23. package/dist/pptx/chunks/index-LoCVDu8Z.d.ts.map +1 -0
  24. package/dist/pptx/chunks/{text-operations-IlJiffp7.d.ts → text-operations-2tKzrY5o.d.ts} +7381 -7381
  25. package/dist/pptx/chunks/text-operations-2tKzrY5o.d.ts.map +1 -0
  26. package/dist/pptx/cli/index.d.ts +1 -1
  27. package/dist/pptx/converter/index.d.ts +1 -1
  28. package/dist/pptx/index.d.ts +4 -9644
  29. package/dist/visio/edit-geometry-admission.d.ts +6 -3
  30. package/dist/visio/edit-geometry-admission.d.ts.map +1 -1
  31. package/dist/visio/edit-geometry.d.ts +2 -1
  32. package/dist/visio/edit-geometry.d.ts.map +1 -1
  33. package/dist/visio/edit-master-index.d.ts +1 -1
  34. package/dist/visio/edit-master-index.d.ts.map +1 -1
  35. package/dist/visio/edit-master-move.d.ts +20 -0
  36. package/dist/visio/edit-master-move.d.ts.map +1 -0
  37. package/dist/visio/edit-master-scope.d.ts +2 -1
  38. package/dist/visio/edit-master-scope.d.ts.map +1 -1
  39. package/dist/visio/edit-recalculate-index.d.ts +2 -0
  40. package/dist/visio/edit-recalculate-index.d.ts.map +1 -1
  41. package/dist/visio/edit-scope.d.ts +2 -1
  42. package/dist/visio/edit-scope.d.ts.map +1 -1
  43. package/dist/visio/edit.d.ts.map +1 -1
  44. package/dist/visio/index.cjs +250 -36
  45. package/dist/visio/index.mjs +250 -36
  46. package/dist/xlsx/formula/area-index.d.ts +3 -3
  47. package/dist/xlsx/formula/area-index.d.ts.map +1 -1
  48. package/dist/xlsx/formula/engine-core.d.ts +4 -1
  49. package/dist/xlsx/formula/engine-core.d.ts.map +1 -1
  50. package/dist/xlsx/formula/engine-host.d.ts +2 -0
  51. package/dist/xlsx/formula/engine-host.d.ts.map +1 -1
  52. package/dist/xlsx/formula/engine-order.d.ts +11 -0
  53. package/dist/xlsx/formula/engine-order.d.ts.map +1 -0
  54. package/dist/xlsx/formula/spill.d.ts.map +1 -1
  55. package/dist/xlsx/formula/store.d.ts.map +1 -1
  56. package/dist/xlsx/index.cjs +102 -64
  57. package/dist/xlsx/index.mjs +102 -64
  58. package/package.json +21 -3
  59. package/dist/pptx/chunks/text-operations-IlJiffp7.d.ts.map +0 -1
  60. package/dist/pptx/index.d.ts.map +0 -1
@@ -6183,7 +6183,7 @@ function recalculateVisioCells(roots, changed, options = {}) {
6183
6183
  if (active.size >= maxDepth)
6184
6184
  fail("LIMIT_FORMULA_DEPTH", "ShapeSheet dependency depth limit exceeded.");
6185
6185
  const item = cells3.get(id);
6186
- if (!item || item.unsafe)
6186
+ if (!item || item.unsafe && (!item.node || !options.masterMovePins?.has(item.node)))
6187
6187
  fail(
6188
6188
  "EDIT_UNSUPPORTED_DEPENDENCY",
6189
6189
  "Affected formula references missing, inherited or grouped cells."
@@ -6336,7 +6336,7 @@ function setCell(shape, name, value, formula) {
6336
6336
  if (formula) node.setAttribute("F", formula);
6337
6337
  else if (attribute2(node, "F") !== "No Formula") node.removeAttribute("F");
6338
6338
  }
6339
- function admitted(root, shapeId) {
6339
+ function admitted(root, shapeId, masterMovePins = /* @__PURE__ */ new Set(), masterDimensions = /* @__PURE__ */ new Map()) {
6340
6340
  const containers = children(root, "Shapes");
6341
6341
  if (containers.length !== 1)
6342
6342
  fail("UNSUPPORTED_GEOMETRY_EDIT", "One local Shapes container is required.");
@@ -6346,7 +6346,10 @@ function admitted(root, shapeId) {
6346
6346
  if (candidates.length !== 1)
6347
6347
  fail("EDIT_TARGET_NOT_FOUND", "A unique top-level local shape is required.");
6348
6348
  const shape = candidates[0];
6349
- if (shape.hasAttribute("Master") || shape.hasAttribute("MasterShape") || ["1", "true"].includes(attribute2(shape, "Del") ?? "") || children(shape, "Shapes").length || children(shape, "ForeignData").length || children(shape, "Rel").length || attribute2(shape, "Type") && attribute2(shape, "Type") !== "Shape")
6349
+ if ((shape.hasAttribute("Master") || shape.hasAttribute("MasterShape")) && !["PinX", "PinY"].every((name) => {
6350
+ const cell = cells(shape).get(name);
6351
+ return cell && masterMovePins.has(cell);
6352
+ }) || ["1", "true"].includes(attribute2(shape, "Del") ?? "") || children(shape, "Shapes").length || children(shape, "ForeignData").length || children(shape, "Rel").length || attribute2(shape, "Type") && attribute2(shape, "Type") !== "Shape")
6350
6353
  fail(
6351
6354
  "UNSUPPORTED_GEOMETRY_EDIT",
6352
6355
  "Master, group, foreign, deleted and non-shape operations are unsupported."
@@ -6362,12 +6365,17 @@ function admitted(root, shapeId) {
6362
6365
  "UNSUPPORTED_GEOMETRY_EDIT",
6363
6366
  "Only local 2D shapes are admitted; line routing and glue are unsupported."
6364
6367
  );
6365
- if (!(numeric3(local.get("Width")) > 0) || !(numeric3(local.get("Height")) > 0))
6366
- fail("UNSUPPORTED_GEOMETRY_EDIT", "Positive local Width and Height caches are required.");
6368
+ const proven = masterDimensions.get(shape);
6369
+ if (!(numeric3(local.get("Width"), proven?.width) > 0) || !(numeric3(local.get("Height"), proven?.height) > 0))
6370
+ fail("UNSUPPORTED_GEOMETRY_EDIT", "Positive proven Width and Height caches are required.");
6367
6371
  return shape;
6368
6372
  }
6369
- function protectedShape(shape, document) {
6373
+ function protectedShape(shape, document, masterMovePins = /* @__PURE__ */ new Set()) {
6370
6374
  const local = cells(shape);
6375
+ const certifiedMove = shape.hasAttribute("Master") && ["PinX", "PinY"].every((name) => {
6376
+ const node = local.get(name);
6377
+ return node !== void 0 && masterMovePins.has(node);
6378
+ });
6371
6379
  const styles = /* @__PURE__ */ new Map();
6372
6380
  for (const container of children(document, "StyleSheets"))
6373
6381
  for (const node of children(container, "StyleSheet")) {
@@ -6375,9 +6383,13 @@ function protectedShape(shape, document) {
6375
6383
  if (!id || styles.has(id)) fail("EDIT_PROTECTED_CELL", "Ambiguous protection style IDs.");
6376
6384
  styles.set(id, node);
6377
6385
  }
6378
- const inactive = (cell) => {
6386
+ const validateProtection = (cell) => {
6379
6387
  try {
6380
- if (cell.hasAttribute("E") || visioFormulaCachedValue(attribute2(cell, "V") ?? "", attribute2(cell, "U")).unit !== "scalar" || numeric3(cell) !== 0)
6388
+ const cached2 = numeric3(cell);
6389
+ const operationIndependent = certifiedMove && ["LockWidth", "LockHeight", "LockAspect", "LockDelete"].includes(
6390
+ attribute2(cell, "N") ?? ""
6391
+ );
6392
+ if (cell.hasAttribute("E") || visioFormulaCachedValue(attribute2(cell, "V") ?? "", attribute2(cell, "U")).unit !== "scalar" || !(cached2 === 0 || operationIndependent && cached2 === 1))
6381
6393
  fail("EDIT_PROTECTED_CELL", "Inherited protection is active or invalid.");
6382
6394
  const source = executableCellFormula(attribute2(cell, "F"));
6383
6395
  if (!source) return;
@@ -6388,12 +6400,12 @@ function protectedShape(shape, document) {
6388
6400
  source,
6389
6401
  () => fail("EDIT_PROTECTED_CELL", "Inherited protection has dependencies.")
6390
6402
  );
6391
- if (result.unit !== "scalar" || result.value !== 0)
6392
- fail("EDIT_PROTECTED_CELL", "Inherited protection formula is active or stale.");
6403
+ if (result.unit !== "scalar" || result.value !== cached2)
6404
+ fail("EDIT_PROTECTED_CELL", "Inherited protection formula cache is stale.");
6393
6405
  } catch (error) {
6394
6406
  fail(
6395
6407
  "EDIT_PROTECTED_CELL",
6396
- `Inherited protection cannot be proven inactive: ${error instanceof Error ? error.message : "invalid cache"}`
6408
+ `Inherited protection cannot be proven safe for this operation: ${error instanceof Error ? error.message : "invalid cache"}`
6397
6409
  );
6398
6410
  }
6399
6411
  };
@@ -6405,16 +6417,18 @@ function protectedShape(shape, document) {
6405
6417
  if (!style) fail("EDIT_PROTECTED_CELL", "Protection style ancestry cannot be resolved.");
6406
6418
  const cell = cells(style).get(lock), parent = attribute2(style, category);
6407
6419
  if (cell && attribute2(cell, "F") !== "Inh") {
6408
- inactive(cell);
6420
+ validateProtection(cell);
6409
6421
  return cell;
6410
6422
  }
6411
6423
  if (cell) {
6412
- inactive(cell);
6424
+ validateProtection(cell);
6413
6425
  if (parent === void 0 || parent === id)
6414
6426
  fail("EDIT_PROTECTED_CELL", "Inherited protection has no provable parent.");
6415
6427
  const inherited = resolve(parent, category, lock, seen);
6416
6428
  if (!inherited)
6417
- fail("EDIT_PROTECTED_CELL", "Inherited protection has no explicit inactive ancestor.");
6429
+ fail("EDIT_PROTECTED_CELL", "Inherited protection has no explicit provable ancestor.");
6430
+ if (numeric3(cell) !== numeric3(inherited))
6431
+ fail("EDIT_PROTECTED_CELL", "Delegated protection cache disagrees with its ancestor.");
6418
6432
  return inherited;
6419
6433
  }
6420
6434
  return parent !== void 0 && parent !== id ? resolve(parent, category, lock, seen) : void 0;
@@ -6491,6 +6505,130 @@ function resizeGeometry(shape, roots, edit, check) {
6491
6505
  }
6492
6506
  }
6493
6507
 
6508
+ // src/visio/edit-master-move.ts
6509
+ var protection = [
6510
+ "LockMoveX",
6511
+ "LockMoveY",
6512
+ "LockWidth",
6513
+ "LockHeight",
6514
+ "LockAspect",
6515
+ "LockDelete"
6516
+ ];
6517
+ var dimensions2 = ["PinX", "PinY", "Width", "Height", "LocPinX", "LocPinY"];
6518
+ var emptyMasterMoveProof = () => ({
6519
+ pins: /* @__PURE__ */ new Set(),
6520
+ dimensions: /* @__PURE__ */ new Map()
6521
+ });
6522
+ function prepareMasterMovePins(roots, commands, bindings, check) {
6523
+ const result = /* @__PURE__ */ new Set();
6524
+ const provenDimensions = /* @__PURE__ */ new Map();
6525
+ let work = 1e5;
6526
+ const charge = (amount = 1) => {
6527
+ check();
6528
+ work -= amount;
6529
+ if (work < 0)
6530
+ fail("EDIT_UNSUPPORTED_PACKAGE_DEPENDENCY", "Master move preparation budget exceeded.");
6531
+ };
6532
+ const analyze = (formula) => {
6533
+ charge(formula.length);
6534
+ return analyzeVisioFormula(formula);
6535
+ };
6536
+ for (const command2 of commands) {
6537
+ charge();
6538
+ const root = roots.get(command2.pageId);
6539
+ const instance = children(children(root, "Shapes")[0], "Shape").find(
6540
+ (shape) => attribute2(shape, "ID") === command2.shapeId
6541
+ );
6542
+ if (!instance?.hasAttribute("Master")) continue;
6543
+ if (command2.type !== "move-shape")
6544
+ fail("UNSUPPORTED_GEOMETRY_EDIT", "Master-linked resizing and deletion remain unsupported.");
6545
+ const binding = bindings.find((candidate) => candidate.instance === instance);
6546
+ if (!binding) fail("UNSUPPORTED_GEOMETRY_EDIT", "A unique effective master root is required.");
6547
+ for (const node of [instance, binding.template]) {
6548
+ charge();
6549
+ if (attribute2(node, "Type") !== "Shape" || children(node, "Shapes").length || children(node, "ForeignData").length || children(node, "Rel").length || ["1", "true"].includes(attribute2(node, "Del") ?? ""))
6550
+ fail("UNSUPPORTED_GEOMETRY_EDIT", "Master moves require top-level local 2D shape roots.");
6551
+ }
6552
+ for (const name of ["BeginX", "BeginY", "EndX", "EndY"])
6553
+ if (binding.cells.has(name.toLowerCase()))
6554
+ fail("UNSUPPORTED_GEOMETRY_EDIT", "Master lines and endpoint routing remain unsupported.");
6555
+ const oneD = binding.cells.get("oned")?.node;
6556
+ charge();
6557
+ if (oneD && (numeric3(oneD) !== 0 || visioFormulaCachedValue(attribute2(oneD, "V") ?? "", attribute2(oneD, "U")).unit !== "scalar" || executableCellFormula(attribute2(oneD, "F"))))
6558
+ fail("UNSUPPORTED_GEOMETRY_EDIT", "A static effective 2D master is required.");
6559
+ const local = cells(instance);
6560
+ for (const name of dimensions2) {
6561
+ const effective = binding.cells.get(name.toLowerCase())?.node;
6562
+ for (const node of /* @__PURE__ */ new Set([effective, ...local.has(name) ? [local.get(name)] : []])) {
6563
+ charge();
6564
+ numeric3(node);
6565
+ if (visioFormulaCachedValue("0", attribute2(node, "U") ?? "DL").unit !== "length")
6566
+ fail("EDIT_FORMULA_UNIT", "Master transform caches require length units.");
6567
+ }
6568
+ }
6569
+ const dimension = (name) => numeric3(local.get(name) ?? binding.cells.get(name.toLowerCase())?.node);
6570
+ const width = dimension("Width"), height = dimension("Height");
6571
+ if (width <= 0 || height <= 0)
6572
+ fail("UNSUPPORTED_GEOMETRY_EDIT", "Positive proven effective dimensions are required.");
6573
+ provenDimensions.set(instance, { width, height });
6574
+ for (const name of protection) {
6575
+ charge();
6576
+ const node = binding.cells.get(name.toLowerCase())?.node;
6577
+ const cached2 = node ? numeric3(node) : NaN;
6578
+ const moving = name === "LockMoveX" || name === "LockMoveY";
6579
+ if (!node || visioFormulaCachedValue(attribute2(node, "V") ?? "", attribute2(node, "U")).unit !== "scalar" || ![0, 1].includes(cached2) || moving && cached2 !== 0)
6580
+ fail(
6581
+ "EDIT_PROTECTED_CELL",
6582
+ "Effective master protection must be proven boolean with inactive movement locks."
6583
+ );
6584
+ const formula = executableCellFormula(attribute2(node, "F"));
6585
+ if (formula) {
6586
+ const analysis = analyze(formula);
6587
+ if (analysis.dynamic || analysis.references.length || analysis.unsupportedFunctions.length)
6588
+ fail("EDIT_PROTECTED_CELL", "Effective master protection dependencies are unsupported.");
6589
+ const value = evaluateVisioFormula(
6590
+ formula,
6591
+ () => fail("EDIT_PROTECTED_CELL", "Unexpected protection dependency."),
6592
+ { onStep: () => charge() }
6593
+ );
6594
+ if (value.unit !== "scalar" || value.value !== cached2)
6595
+ fail("EDIT_PROTECTED_CELL", "Effective master protection cache is stale.");
6596
+ }
6597
+ }
6598
+ for (const name of ["PinX", "PinY"]) {
6599
+ charge();
6600
+ const node = local.get(name);
6601
+ if (!node)
6602
+ fail("EDIT_PROTECTED_CELL", "The rotation pin must be an explicit local override.");
6603
+ if (binding.cells.get(name.toLowerCase())?.node !== node)
6604
+ fail("EDIT_PROTECTED_CELL", "The rotation pin must be an explicit local override.");
6605
+ charge(executableCellFormula(attribute2(node, "F"))?.length ?? 0);
6606
+ editableCell(node);
6607
+ const inherited = binding.inheritedCells.get(name.toLowerCase())?.node;
6608
+ numeric3(inherited);
6609
+ if (visioFormulaCachedValue("0", attribute2(inherited, "U") ?? "DL").unit !== "length")
6610
+ fail("EDIT_FORMULA_UNIT", "Inherited rotation pins require length units.");
6611
+ const formula = executableCellFormula(attribute2(inherited, "F"));
6612
+ if (formula) {
6613
+ const analysis = analyze(formula);
6614
+ if (analysis.guarded || analysis.dynamic || analysis.unsupportedFunctions.length)
6615
+ fail("EDIT_PROTECTED_CELL", "Protected or redirected master pins cannot be overridden.");
6616
+ }
6617
+ result.add(node);
6618
+ }
6619
+ }
6620
+ if (result.size) {
6621
+ const indexed = indexCells(roots, { check });
6622
+ const pins = new Set(
6623
+ [...indexed.values()].filter((cell) => cell.node && result.has(cell.node)).map(key)
6624
+ );
6625
+ for (const cell of indexed.values())
6626
+ if (charge(), cell.dependencies.some((dependency) => pins.has(dependency)))
6627
+ fail("EDIT_UNSUPPORTED_DEPENDENCY", "A page cache depends on a master rotation pin.");
6628
+ }
6629
+ return { pins: result, dimensions: provenDimensions };
6630
+ }
6631
+
6494
6632
  // src/visio/edit-geometry.ts
6495
6633
  function createRectangle(root, edit) {
6496
6634
  const doc = root.ownerDocument;
@@ -6553,7 +6691,8 @@ function createRectangle(root, edit) {
6553
6691
  container.appendChild(shape);
6554
6692
  return shape;
6555
6693
  }
6556
- function applyGeometryEdit(roots, document, edit, check) {
6694
+ function applyGeometryEdit(roots, document, edit, check, masterMoveProof = emptyMasterMoveProof()) {
6695
+ const masterMovePins = masterMoveProof.pins, masterDimensions = masterMoveProof.dimensions;
6557
6696
  check();
6558
6697
  const root = roots.get(edit.pageId);
6559
6698
  if (!root) fail("EDIT_TARGET_NOT_FOUND", "Page does not exist.");
@@ -6565,8 +6704,13 @@ function applyGeometryEdit(roots, document, edit, check) {
6565
6704
  expected = { width: edit.width, height: edit.height, x: edit.x, y: edit.y };
6566
6705
  for (const name of ["Width", "Height", "PinX", "PinY"]) add(name);
6567
6706
  } else {
6568
- const shape = admitted(root, edit.shapeId);
6569
- protectedShape(shape, document);
6707
+ const shape = admitted(
6708
+ root,
6709
+ edit.shapeId,
6710
+ edit.type === "move-shape" ? masterMovePins : /* @__PURE__ */ new Set(),
6711
+ edit.type === "move-shape" ? masterDimensions : /* @__PURE__ */ new Map()
6712
+ );
6713
+ protectedShape(shape, document, edit.type === "move-shape" ? masterMovePins : /* @__PURE__ */ new Set());
6570
6714
  if (edit.type !== "delete-shape") {
6571
6715
  for (const connections2 of children(root, "Connects"))
6572
6716
  for (const connection of children(connections2, "Connect"))
@@ -6588,9 +6732,10 @@ function applyGeometryEdit(roots, document, edit, check) {
6588
6732
  return [edit.pageId];
6589
6733
  }
6590
6734
  if (edit.type === "move-shape") {
6735
+ const proven = masterDimensions.get(shape);
6591
6736
  expected = {
6592
- width: numeric3(local.get("Width")),
6593
- height: numeric3(local.get("Height")),
6737
+ width: numeric3(local.get("Width"), proven?.width),
6738
+ height: numeric3(local.get("Height"), proven?.height),
6594
6739
  x: edit.x,
6595
6740
  y: edit.y
6596
6741
  };
@@ -6598,10 +6743,7 @@ function applyGeometryEdit(roots, document, edit, check) {
6598
6743
  ["PinX", edit.x, "LockMoveX"],
6599
6744
  ["PinY", edit.y, "LockMoveY"]
6600
6745
  ]) {
6601
- if (numeric3(
6602
- local.get(name),
6603
- name === "PinX" ? numeric3(local.get("Width")) / 2 : numeric3(local.get("Height")) / 2
6604
- ) === value)
6746
+ if (numeric3(local.get(name), name === "PinX" ? expected.width / 2 : expected.height / 2) === value)
6605
6747
  continue;
6606
6748
  unlocked(lock);
6607
6749
  editableCell(local.get(name));
@@ -6643,9 +6785,15 @@ function applyGeometryEdit(roots, document, edit, check) {
6643
6785
  }
6644
6786
  }
6645
6787
  if (!changed.length) return [];
6646
- const affectedPages = recalculateVisioCells(roots, changed, { check });
6647
- const result = cells(admitted(root, edit.shapeId));
6648
- if (expected && (numeric3(result.get("Width")) !== expected.width || numeric3(result.get("Height")) !== expected.height || numeric3(result.get("PinX"), expected.width / 2) !== expected.x || numeric3(result.get("PinY"), expected.height / 2) !== expected.y))
6788
+ const affectedPages = recalculateVisioCells(roots, changed, { check, masterMovePins });
6789
+ const resultShape = admitted(
6790
+ root,
6791
+ edit.shapeId,
6792
+ edit.type === "move-shape" ? masterMovePins : /* @__PURE__ */ new Set(),
6793
+ edit.type === "move-shape" ? masterDimensions : /* @__PURE__ */ new Map()
6794
+ );
6795
+ const result = cells(resultShape), provenResult = masterDimensions.get(resultShape);
6796
+ if (expected && (numeric3(result.get("Width"), provenResult?.width) !== expected.width || numeric3(result.get("Height"), provenResult?.height) !== expected.height || numeric3(result.get("PinX"), expected.width / 2) !== expected.x || numeric3(result.get("PinY"), expected.height / 2) !== expected.y))
6649
6797
  fail(
6650
6798
  "EDIT_UNSUPPORTED_DEPENDENCY",
6651
6799
  "Dependent formulas would violate the requested geometry or fixed rotation pin."
@@ -6693,6 +6841,28 @@ function analyzeVisioMasterFormula(source, options) {
6693
6841
  }
6694
6842
 
6695
6843
  // src/visio/edit-master-index.ts
6844
+ function inheritedProtection(node, ancestor) {
6845
+ try {
6846
+ const boolean2 = (cell) => {
6847
+ if (!cell || cell.hasAttribute("E"))
6848
+ fail("EDIT_PROTECTED_CELL", "Inherited protection has an unresolved or error cache.");
6849
+ const value = visioFormulaCachedValue(attribute2(cell, "V") ?? "", attribute2(cell, "U"));
6850
+ if (value.unit !== "scalar" || ![0, 1].includes(value.value))
6851
+ fail("EDIT_PROTECTED_CELL", "Inherited protection requires scalar boolean caches.");
6852
+ return value.value;
6853
+ };
6854
+ if (boolean2(node) !== boolean2(ancestor))
6855
+ fail(
6856
+ "EDIT_PROTECTED_CELL",
6857
+ "Delegated master style protection cache disagrees with its ancestor."
6858
+ );
6859
+ } catch (error) {
6860
+ fail(
6861
+ "EDIT_PROTECTED_CELL",
6862
+ `Inherited master style protection cannot be proven: ${error instanceof Error ? error.message : "invalid cache"}`
6863
+ );
6864
+ }
6865
+ }
6696
6866
  function masterCells(sheet, charge = () => {
6697
6867
  }) {
6698
6868
  const result = /* @__PURE__ */ new Map();
@@ -6750,7 +6920,7 @@ function assertMasterMarkup(root, known, check) {
6750
6920
  }
6751
6921
  }
6752
6922
  function masterStyleCells(document, template, instance, check, charge = () => {
6753
- }) {
6923
+ }, verifyMovementProtection = false) {
6754
6924
  const styles = /* @__PURE__ */ new Map();
6755
6925
  for (const container of children(document, "StyleSheets"))
6756
6926
  for (const style of children(container, "StyleSheet")) {
@@ -6775,6 +6945,10 @@ function masterStyleCells(document, template, instance, check, charge = () => {
6775
6945
  for (const [name, node] of own) {
6776
6946
  charge();
6777
6947
  if (attribute2(node, "F") !== "Inh") result2.set(name, node);
6948
+ else if (verifyMovementProtection && /^lock(move[xy]|width|height|aspect|delete)$/.test(name)) {
6949
+ charge();
6950
+ inheritedProtection(node, result2.get(name));
6951
+ }
6778
6952
  }
6779
6953
  return result2;
6780
6954
  };
@@ -6846,12 +7020,20 @@ async function assertVisioMasterIndependence(pkg, roots, commands, check) {
6846
7020
  const instances = [...roots].flatMap(
6847
7021
  ([pageId, root]) => masterShapes(root).filter((shape) => shape.hasAttribute("Master")).map((instance) => ({ pageId, instance }))
6848
7022
  );
6849
- if (!instances.length) return;
7023
+ if (!instances.length) return emptyMasterMoveProof();
6850
7024
  const documentPart = await related(pkg, "", "document");
6851
7025
  if (!documentPart) problem("Missing master document relationship.");
6852
7026
  const document = await visioXml(pkg, documentPart, "VisioDocument");
6853
7027
  const mastersPart = await related(pkg, documentPart, "masters", false);
6854
- if (!mastersPart) problem("Active master definitions are missing.");
7028
+ if (!mastersPart) {
7029
+ if (commands.some(
7030
+ (command2) => instances.some(
7031
+ (item) => item.pageId === command2.pageId && attribute2(item.instance, "ID") === command2.shapeId
7032
+ )
7033
+ ))
7034
+ fail("UNSUPPORTED_GEOMETRY_EDIT", "Active master definitions are missing.");
7035
+ problem("Active master definitions are missing.");
7036
+ }
6855
7037
  const definitions = /* @__PURE__ */ new Map();
6856
7038
  for (const node of children(await visioXml(pkg, mastersPart, "Masters"), "Master")) {
6857
7039
  const id = attribute2(node, "ID");
@@ -6866,6 +7048,12 @@ async function assertVisioMasterIndependence(pkg, roots, commands, check) {
6866
7048
  if (--buildWork < 0) problem("Master effective-cell construction budget exceeded.");
6867
7049
  };
6868
7050
  const pageBindings = /* @__PURE__ */ new Map();
7051
+ const movingTargets = /* @__PURE__ */ new Set();
7052
+ for (const command2 of commands) {
7053
+ charge();
7054
+ if (command2.type === "move-shape")
7055
+ movingTargets.add(JSON.stringify([command2.pageId, command2.shapeId]));
7056
+ }
6869
7057
  const pageShapes = /* @__PURE__ */ new Map();
6870
7058
  for (const [pageId, root] of roots)
6871
7059
  for (const shape of masterShapes(root)) {
@@ -6925,15 +7113,25 @@ async function assertVisioMasterIndependence(pkg, roots, commands, check) {
6925
7113
  const templateId = attribute2(template, "ID");
6926
7114
  if (!templateId || context.has(templateId)) problem("Master-local sheet IDs are ambiguous.");
6927
7115
  const local = byTemplate.get(templateId), cells3 = /* @__PURE__ */ new Map();
6928
- for (const [name, node] of masterStyleCells(document, template, local, check, charge))
7116
+ const movedInstance = local === instance && movingTargets.has(JSON.stringify([pageId, attribute2(local, "ID")]));
7117
+ for (const [name, node] of masterStyleCells(
7118
+ document,
7119
+ template,
7120
+ local,
7121
+ check,
7122
+ charge,
7123
+ movedInstance
7124
+ ))
6929
7125
  cells3.set(name, { node, kind: "style" });
6930
7126
  overlay(cells3, masterCells(template, charge), "template", charge);
7127
+ const inheritedCells = new Map(cells3);
6931
7128
  overlay(cells3, masterCells(local, charge), "instance", charge);
6932
7129
  const binding = {
6933
7130
  id: `${pageId}:${attribute2(instance, "ID")}:${templateId}`,
6934
7131
  pageId,
6935
7132
  template,
6936
7133
  cells: cells3,
7134
+ inheritedCells,
6937
7135
  context,
6938
7136
  ...local ? { instance: local } : {}
6939
7137
  };
@@ -6944,6 +7142,7 @@ async function assertVisioMasterIndependence(pkg, roots, commands, check) {
6944
7142
  for (const id of byTemplate.keys())
6945
7143
  if (!context.has(id)) problem("MasterShape refers to a missing template.");
6946
7144
  }
7145
+ const movePins = prepareMasterMovePins(roots, commands, bindings, check);
6947
7146
  const changed = commands.flatMap(
6948
7147
  (command2) => command2.type === "delete-shape" ? [] : (command2.type === "move-shape" ? ["PinX", "PinY"] : command2.type === "resize-shape" ? ["Width", "Height"] : ["Width", "Height", "PinX", "PinY"]).map((cell) => ({ pageId: command2.pageId, shapeId: command2.shapeId, cell }))
6949
7148
  );
@@ -6971,6 +7170,7 @@ async function assertVisioMasterIndependence(pkg, roots, commands, check) {
6971
7170
  template: shape,
6972
7171
  instance: shape,
6973
7172
  cells: cells3,
7173
+ inheritedCells: /* @__PURE__ */ new Map(),
6974
7174
  context: /* @__PURE__ */ new Map()
6975
7175
  };
6976
7176
  pageInputs.set(id, result);
@@ -7048,7 +7248,14 @@ async function assertVisioMasterIndependence(pkg, roots, commands, check) {
7048
7248
  active.delete(id);
7049
7249
  done.add(id);
7050
7250
  };
7051
- for (const binding of bindings) for (const name of binding.cells.keys()) inspect2(binding, name);
7251
+ for (const binding of bindings)
7252
+ for (const name of binding.cells.keys()) {
7253
+ const source = binding.cells.get(name);
7254
+ if (["pinx", "piny"].includes(name) && source?.kind === "instance" && movePins.pins.has(source.node))
7255
+ continue;
7256
+ inspect2(binding, name);
7257
+ }
7258
+ return movePins;
7052
7259
  }
7053
7260
 
7054
7261
  // src/visio/edit-scope.ts
@@ -7168,6 +7375,7 @@ async function assertGeometryPackageScope(pkg, pagePaths, commands, check, roots
7168
7375
  });
7169
7376
  }
7170
7377
  }
7378
+ let movePins = emptyMasterMoveProof();
7171
7379
  if (hasMasterInstances) {
7172
7380
  for (const command2 of commands) {
7173
7381
  const root = roots.get(command2.pageId);
@@ -7175,12 +7383,16 @@ async function assertGeometryPackageScope(pkg, pagePaths, commands, check, roots
7175
7383
  const target = Array.from(root.getElementsByTagNameNS(root.namespaceURI, "Shape")).find(
7176
7384
  (shape) => attribute2(shape, "ID") === command2.shapeId
7177
7385
  );
7178
- if (target?.hasAttribute("Master") || target?.hasAttribute("MasterShape"))
7386
+ if (target?.hasAttribute("MasterShape") && !target.hasAttribute("Master"))
7179
7387
  fail("UNSUPPORTED_GEOMETRY_EDIT", "Editing master-linked shapes is unsupported.");
7388
+ if (target?.hasAttribute("Master") && (command2.type !== "move-shape" || !["PinX", "PinY"].every(
7389
+ (name) => children(target, "Cell").some((node) => attribute2(node, "N") === name)
7390
+ )))
7391
+ fail("UNSUPPORTED_GEOMETRY_EDIT", "Master moves require explicit local rotation pins.");
7180
7392
  }
7181
- await assertVisioMasterIndependence(pkg, roots, commands, check);
7393
+ movePins = await assertVisioMasterIndependence(pkg, roots, commands, check);
7182
7394
  }
7183
- if (!documentRoot) return;
7395
+ if (!documentRoot) return movePins;
7184
7396
  const styles = /* @__PURE__ */ new Map();
7185
7397
  for (const container of children(documentRoot, "StyleSheets"))
7186
7398
  for (const style of children(container, "StyleSheet")) {
@@ -7245,6 +7457,7 @@ async function assertGeometryPackageScope(pkg, pagePaths, commands, check, roots
7245
7457
  }
7246
7458
  }
7247
7459
  }
7460
+ return movePins;
7248
7461
  }
7249
7462
 
7250
7463
  // src/visio/edit.ts
@@ -7272,12 +7485,13 @@ async function editVsdx(input, edits, options = {}) {
7272
7485
  const roots = /* @__PURE__ */ new Map();
7273
7486
  const geometry = commands.some((command2) => command2.type !== "replace-plain-text");
7274
7487
  let document;
7488
+ let masterMovePins = emptyMasterMoveProof();
7275
7489
  if (geometry) {
7276
7490
  for (const [pageId, path2] of pages) {
7277
7491
  const sourceRoot = await visioXml(pkg, path2, "PageContents");
7278
7492
  roots.set(pageId, sourceRoot.ownerDocument.cloneNode(true).documentElement);
7279
7493
  }
7280
- await assertGeometryPackageScope(
7494
+ masterMovePins = await assertGeometryPackageScope(
7281
7495
  pkg,
7282
7496
  new Set(pages.values()),
7283
7497
  commands.filter((command2) => command2.type !== "replace-plain-text"),
@@ -7304,7 +7518,7 @@ async function editVsdx(input, edits, options = {}) {
7304
7518
  textChanged = true;
7305
7519
  }
7306
7520
  } else {
7307
- for (const pageId of applyGeometryEdit(roots, document, command2, check))
7521
+ for (const pageId of applyGeometryEdit(roots, document, command2, check, masterMovePins))
7308
7522
  dirty.set(pages.get(pageId), roots.get(pageId));
7309
7523
  }
7310
7524
  }