ooxml-core 0.11.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.
@@ -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, masterMovePins = /* @__PURE__ */ new Set()) {
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.");
@@ -6365,12 +6365,17 @@ function admitted(root, shapeId, masterMovePins = /* @__PURE__ */ new Set()) {
6365
6365
  "UNSUPPORTED_GEOMETRY_EDIT",
6366
6366
  "Only local 2D shapes are admitted; line routing and glue are unsupported."
6367
6367
  );
6368
- if (!(numeric3(local.get("Width")) > 0) || !(numeric3(local.get("Height")) > 0))
6369
- 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.");
6370
6371
  return shape;
6371
6372
  }
6372
- function protectedShape(shape, document) {
6373
+ function protectedShape(shape, document, masterMovePins = /* @__PURE__ */ new Set()) {
6373
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
+ });
6374
6379
  const styles = /* @__PURE__ */ new Map();
6375
6380
  for (const container of children(document, "StyleSheets"))
6376
6381
  for (const node of children(container, "StyleSheet")) {
@@ -6378,9 +6383,13 @@ function protectedShape(shape, document) {
6378
6383
  if (!id || styles.has(id)) fail("EDIT_PROTECTED_CELL", "Ambiguous protection style IDs.");
6379
6384
  styles.set(id, node);
6380
6385
  }
6381
- const inactive = (cell) => {
6386
+ const validateProtection = (cell) => {
6382
6387
  try {
6383
- 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))
6384
6393
  fail("EDIT_PROTECTED_CELL", "Inherited protection is active or invalid.");
6385
6394
  const source = executableCellFormula(attribute2(cell, "F"));
6386
6395
  if (!source) return;
@@ -6391,12 +6400,12 @@ function protectedShape(shape, document) {
6391
6400
  source,
6392
6401
  () => fail("EDIT_PROTECTED_CELL", "Inherited protection has dependencies.")
6393
6402
  );
6394
- if (result.unit !== "scalar" || result.value !== 0)
6395
- 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.");
6396
6405
  } catch (error) {
6397
6406
  fail(
6398
6407
  "EDIT_PROTECTED_CELL",
6399
- `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"}`
6400
6409
  );
6401
6410
  }
6402
6411
  };
@@ -6408,16 +6417,18 @@ function protectedShape(shape, document) {
6408
6417
  if (!style) fail("EDIT_PROTECTED_CELL", "Protection style ancestry cannot be resolved.");
6409
6418
  const cell = cells(style).get(lock), parent = attribute2(style, category);
6410
6419
  if (cell && attribute2(cell, "F") !== "Inh") {
6411
- inactive(cell);
6420
+ validateProtection(cell);
6412
6421
  return cell;
6413
6422
  }
6414
6423
  if (cell) {
6415
- inactive(cell);
6424
+ validateProtection(cell);
6416
6425
  if (parent === void 0 || parent === id)
6417
6426
  fail("EDIT_PROTECTED_CELL", "Inherited protection has no provable parent.");
6418
6427
  const inherited = resolve(parent, category, lock, seen);
6419
6428
  if (!inherited)
6420
- 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.");
6421
6432
  return inherited;
6422
6433
  }
6423
6434
  return parent !== void 0 && parent !== id ? resolve(parent, category, lock, seen) : void 0;
@@ -6494,6 +6505,130 @@ function resizeGeometry(shape, roots, edit, check) {
6494
6505
  }
6495
6506
  }
6496
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
+
6497
6632
  // src/visio/edit-geometry.ts
6498
6633
  function createRectangle(root, edit) {
6499
6634
  const doc = root.ownerDocument;
@@ -6556,7 +6691,8 @@ function createRectangle(root, edit) {
6556
6691
  container.appendChild(shape);
6557
6692
  return shape;
6558
6693
  }
6559
- function applyGeometryEdit(roots, document, edit, check, masterMovePins = /* @__PURE__ */ new Set()) {
6694
+ function applyGeometryEdit(roots, document, edit, check, masterMoveProof = emptyMasterMoveProof()) {
6695
+ const masterMovePins = masterMoveProof.pins, masterDimensions = masterMoveProof.dimensions;
6560
6696
  check();
6561
6697
  const root = roots.get(edit.pageId);
6562
6698
  if (!root) fail("EDIT_TARGET_NOT_FOUND", "Page does not exist.");
@@ -6571,9 +6707,10 @@ function applyGeometryEdit(roots, document, edit, check, masterMovePins = /* @__
6571
6707
  const shape = admitted(
6572
6708
  root,
6573
6709
  edit.shapeId,
6574
- edit.type === "move-shape" ? masterMovePins : /* @__PURE__ */ new Set()
6710
+ edit.type === "move-shape" ? masterMovePins : /* @__PURE__ */ new Set(),
6711
+ edit.type === "move-shape" ? masterDimensions : /* @__PURE__ */ new Map()
6575
6712
  );
6576
- protectedShape(shape, document);
6713
+ protectedShape(shape, document, edit.type === "move-shape" ? masterMovePins : /* @__PURE__ */ new Set());
6577
6714
  if (edit.type !== "delete-shape") {
6578
6715
  for (const connections2 of children(root, "Connects"))
6579
6716
  for (const connection of children(connections2, "Connect"))
@@ -6595,9 +6732,10 @@ function applyGeometryEdit(roots, document, edit, check, masterMovePins = /* @__
6595
6732
  return [edit.pageId];
6596
6733
  }
6597
6734
  if (edit.type === "move-shape") {
6735
+ const proven = masterDimensions.get(shape);
6598
6736
  expected = {
6599
- width: numeric3(local.get("Width")),
6600
- height: numeric3(local.get("Height")),
6737
+ width: numeric3(local.get("Width"), proven?.width),
6738
+ height: numeric3(local.get("Height"), proven?.height),
6601
6739
  x: edit.x,
6602
6740
  y: edit.y
6603
6741
  };
@@ -6605,10 +6743,7 @@ function applyGeometryEdit(roots, document, edit, check, masterMovePins = /* @__
6605
6743
  ["PinX", edit.x, "LockMoveX"],
6606
6744
  ["PinY", edit.y, "LockMoveY"]
6607
6745
  ]) {
6608
- if (numeric3(
6609
- local.get(name),
6610
- name === "PinX" ? numeric3(local.get("Width")) / 2 : numeric3(local.get("Height")) / 2
6611
- ) === value)
6746
+ if (numeric3(local.get(name), name === "PinX" ? expected.width / 2 : expected.height / 2) === value)
6612
6747
  continue;
6613
6748
  unlocked(lock);
6614
6749
  editableCell(local.get(name));
@@ -6651,10 +6786,14 @@ function applyGeometryEdit(roots, document, edit, check, masterMovePins = /* @__
6651
6786
  }
6652
6787
  if (!changed.length) return [];
6653
6788
  const affectedPages = recalculateVisioCells(roots, changed, { check, masterMovePins });
6654
- const result = cells(
6655
- admitted(root, edit.shapeId, edit.type === "move-shape" ? masterMovePins : /* @__PURE__ */ new Set())
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()
6656
6794
  );
6657
- 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))
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))
6658
6797
  fail(
6659
6798
  "EDIT_UNSUPPORTED_DEPENDENCY",
6660
6799
  "Dependent formulas would violate the requested geometry or fixed rotation pin."
@@ -6701,117 +6840,29 @@ function analyzeVisioMasterFormula(source, options) {
6701
6840
  return { ...analysis, references: [...references.values()], dynamic: dynamic2, readsText, readsTheme };
6702
6841
  }
6703
6842
 
6704
- // src/visio/edit-master-move.ts
6705
- var protection = [
6706
- "LockMoveX",
6707
- "LockMoveY",
6708
- "LockWidth",
6709
- "LockHeight",
6710
- "LockAspect",
6711
- "LockDelete"
6712
- ];
6713
- var dimensions2 = ["PinX", "PinY", "Width", "Height", "LocPinX", "LocPinY"];
6714
- function prepareMasterMovePins(roots, commands, bindings, check) {
6715
- const result = /* @__PURE__ */ new Set();
6716
- let work = 1e5;
6717
- const charge = (amount = 1) => {
6718
- check();
6719
- work -= amount;
6720
- if (work < 0)
6721
- fail("EDIT_UNSUPPORTED_PACKAGE_DEPENDENCY", "Master move preparation budget exceeded.");
6722
- };
6723
- const analyze = (formula) => {
6724
- charge(formula.length);
6725
- return analyzeVisioFormula(formula);
6726
- };
6727
- for (const command2 of commands) {
6728
- charge();
6729
- const root = roots.get(command2.pageId);
6730
- const instance = children(children(root, "Shapes")[0], "Shape").find(
6731
- (shape) => attribute2(shape, "ID") === command2.shapeId
6732
- );
6733
- if (!instance?.hasAttribute("Master")) continue;
6734
- if (command2.type !== "move-shape")
6735
- fail("UNSUPPORTED_GEOMETRY_EDIT", "Master-linked resizing and deletion remain unsupported.");
6736
- const binding = bindings.find((candidate) => candidate.instance === instance);
6737
- if (!binding) fail("UNSUPPORTED_GEOMETRY_EDIT", "A unique effective master root is required.");
6738
- for (const node of [instance, binding.template]) {
6739
- charge();
6740
- if (attribute2(node, "Type") !== "Shape" || children(node, "Shapes").length || children(node, "ForeignData").length || children(node, "Rel").length || ["1", "true"].includes(attribute2(node, "Del") ?? ""))
6741
- fail("UNSUPPORTED_GEOMETRY_EDIT", "Master moves require top-level local 2D shape roots.");
6742
- }
6743
- for (const name of ["BeginX", "BeginY", "EndX", "EndY"])
6744
- if (binding.cells.has(name.toLowerCase()))
6745
- fail("UNSUPPORTED_GEOMETRY_EDIT", "Master lines and endpoint routing remain unsupported.");
6746
- const oneD = binding.cells.get("oned")?.node;
6747
- charge();
6748
- if (oneD && (numeric3(oneD) !== 0 || visioFormulaCachedValue(attribute2(oneD, "V") ?? "", attribute2(oneD, "U")).unit !== "scalar" || executableCellFormula(attribute2(oneD, "F"))))
6749
- fail("UNSUPPORTED_GEOMETRY_EDIT", "A static effective 2D master is required.");
6750
- const local = cells(instance);
6751
- for (const name of dimensions2) {
6752
- charge();
6753
- const node = local.get(name);
6754
- numeric3(node);
6755
- if (visioFormulaCachedValue("0", attribute2(node, "U") ?? "DL").unit !== "length")
6756
- fail("EDIT_FORMULA_UNIT", "Master transform caches require length units.");
6757
- }
6758
- if (numeric3(local.get("Width")) <= 0 || numeric3(local.get("Height")) <= 0)
6759
- fail("UNSUPPORTED_GEOMETRY_EDIT", "Positive explicit local dimensions are required.");
6760
- for (const name of protection) {
6761
- charge();
6762
- const node = binding.cells.get(name.toLowerCase())?.node;
6763
- if (!node || visioFormulaCachedValue(attribute2(node, "V") ?? "", attribute2(node, "U")).unit !== "scalar" || numeric3(node) !== 0)
6764
- fail(
6765
- "EDIT_PROTECTED_CELL",
6766
- "Effective master protection must be explicitly proven inactive."
6767
- );
6768
- const formula = executableCellFormula(attribute2(node, "F"));
6769
- if (formula) {
6770
- const analysis = analyze(formula);
6771
- if (analysis.dynamic || analysis.references.length || analysis.unsupportedFunctions.length)
6772
- fail("EDIT_PROTECTED_CELL", "Effective master protection dependencies are unsupported.");
6773
- const value = evaluateVisioFormula(
6774
- formula,
6775
- () => fail("EDIT_PROTECTED_CELL", "Unexpected protection dependency."),
6776
- { onStep: () => charge() }
6777
- );
6778
- if (value.unit !== "scalar" || value.value !== 0)
6779
- fail("EDIT_PROTECTED_CELL", "Effective master protection is active or stale.");
6780
- }
6781
- }
6782
- for (const name of ["PinX", "PinY"]) {
6783
- charge();
6784
- const node = local.get(name);
6785
- if (binding.cells.get(name.toLowerCase())?.node !== node)
6786
- fail("EDIT_PROTECTED_CELL", "The rotation pin must be an explicit local override.");
6787
- charge(executableCellFormula(attribute2(node, "F"))?.length ?? 0);
6788
- editableCell(node);
6789
- const inherited = binding.inheritedCells.get(name.toLowerCase())?.node;
6790
- numeric3(inherited);
6791
- if (visioFormulaCachedValue("0", attribute2(inherited, "U") ?? "DL").unit !== "length")
6792
- fail("EDIT_FORMULA_UNIT", "Inherited rotation pins require length units.");
6793
- const formula = executableCellFormula(attribute2(inherited, "F"));
6794
- if (formula) {
6795
- const analysis = analyze(formula);
6796
- if (analysis.guarded || analysis.dynamic || analysis.unsupportedFunctions.length)
6797
- fail("EDIT_PROTECTED_CELL", "Protected or redirected master pins cannot be overridden.");
6798
- }
6799
- result.add(node);
6800
- }
6801
- }
6802
- if (result.size) {
6803
- const indexed = indexCells(roots, { check });
6804
- const pins = new Set(
6805
- [...indexed.values()].filter((cell) => cell.node && result.has(cell.node)).map(key)
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"}`
6806
6863
  );
6807
- for (const cell of indexed.values())
6808
- if (charge(), cell.dependencies.some((dependency) => pins.has(dependency)))
6809
- fail("EDIT_UNSUPPORTED_DEPENDENCY", "A page cache depends on a master rotation pin.");
6810
6864
  }
6811
- return result;
6812
6865
  }
6813
-
6814
- // src/visio/edit-master-index.ts
6815
6866
  function masterCells(sheet, charge = () => {
6816
6867
  }) {
6817
6868
  const result = /* @__PURE__ */ new Map();
@@ -6869,7 +6920,7 @@ function assertMasterMarkup(root, known, check) {
6869
6920
  }
6870
6921
  }
6871
6922
  function masterStyleCells(document, template, instance, check, charge = () => {
6872
- }) {
6923
+ }, verifyMovementProtection = false) {
6873
6924
  const styles = /* @__PURE__ */ new Map();
6874
6925
  for (const container of children(document, "StyleSheets"))
6875
6926
  for (const style of children(container, "StyleSheet")) {
@@ -6894,6 +6945,10 @@ function masterStyleCells(document, template, instance, check, charge = () => {
6894
6945
  for (const [name, node] of own) {
6895
6946
  charge();
6896
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
+ }
6897
6952
  }
6898
6953
  return result2;
6899
6954
  };
@@ -6965,12 +7020,20 @@ async function assertVisioMasterIndependence(pkg, roots, commands, check) {
6965
7020
  const instances = [...roots].flatMap(
6966
7021
  ([pageId, root]) => masterShapes(root).filter((shape) => shape.hasAttribute("Master")).map((instance) => ({ pageId, instance }))
6967
7022
  );
6968
- if (!instances.length) return /* @__PURE__ */ new Set();
7023
+ if (!instances.length) return emptyMasterMoveProof();
6969
7024
  const documentPart = await related(pkg, "", "document");
6970
7025
  if (!documentPart) problem("Missing master document relationship.");
6971
7026
  const document = await visioXml(pkg, documentPart, "VisioDocument");
6972
7027
  const mastersPart = await related(pkg, documentPart, "masters", false);
6973
- 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
+ }
6974
7037
  const definitions = /* @__PURE__ */ new Map();
6975
7038
  for (const node of children(await visioXml(pkg, mastersPart, "Masters"), "Master")) {
6976
7039
  const id = attribute2(node, "ID");
@@ -6985,6 +7048,12 @@ async function assertVisioMasterIndependence(pkg, roots, commands, check) {
6985
7048
  if (--buildWork < 0) problem("Master effective-cell construction budget exceeded.");
6986
7049
  };
6987
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
+ }
6988
7057
  const pageShapes = /* @__PURE__ */ new Map();
6989
7058
  for (const [pageId, root] of roots)
6990
7059
  for (const shape of masterShapes(root)) {
@@ -7044,7 +7113,15 @@ async function assertVisioMasterIndependence(pkg, roots, commands, check) {
7044
7113
  const templateId = attribute2(template, "ID");
7045
7114
  if (!templateId || context.has(templateId)) problem("Master-local sheet IDs are ambiguous.");
7046
7115
  const local = byTemplate.get(templateId), cells3 = /* @__PURE__ */ new Map();
7047
- 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
+ ))
7048
7125
  cells3.set(name, { node, kind: "style" });
7049
7126
  overlay(cells3, masterCells(template, charge), "template", charge);
7050
7127
  const inheritedCells = new Map(cells3);
@@ -7174,7 +7251,7 @@ async function assertVisioMasterIndependence(pkg, roots, commands, check) {
7174
7251
  for (const binding of bindings)
7175
7252
  for (const name of binding.cells.keys()) {
7176
7253
  const source = binding.cells.get(name);
7177
- if (["pinx", "piny"].includes(name) && source?.kind === "instance" && movePins.has(source.node))
7254
+ if (["pinx", "piny"].includes(name) && source?.kind === "instance" && movePins.pins.has(source.node))
7178
7255
  continue;
7179
7256
  inspect2(binding, name);
7180
7257
  }
@@ -7298,7 +7375,7 @@ async function assertGeometryPackageScope(pkg, pagePaths, commands, check, roots
7298
7375
  });
7299
7376
  }
7300
7377
  }
7301
- let movePins = /* @__PURE__ */ new Set();
7378
+ let movePins = emptyMasterMoveProof();
7302
7379
  if (hasMasterInstances) {
7303
7380
  for (const command2 of commands) {
7304
7381
  const root = roots.get(command2.pageId);
@@ -7308,10 +7385,10 @@ async function assertGeometryPackageScope(pkg, pagePaths, commands, check, roots
7308
7385
  );
7309
7386
  if (target?.hasAttribute("MasterShape") && !target.hasAttribute("Master"))
7310
7387
  fail("UNSUPPORTED_GEOMETRY_EDIT", "Editing master-linked shapes is unsupported.");
7311
- if (target?.hasAttribute("Master") && (command2.type !== "move-shape" || !["PinX", "PinY", "Width", "Height", "LocPinX", "LocPinY"].every(
7388
+ if (target?.hasAttribute("Master") && (command2.type !== "move-shape" || !["PinX", "PinY"].every(
7312
7389
  (name) => children(target, "Cell").some((node) => attribute2(node, "N") === name)
7313
7390
  )))
7314
- fail("UNSUPPORTED_GEOMETRY_EDIT", "Master moves require complete local transform caches.");
7391
+ fail("UNSUPPORTED_GEOMETRY_EDIT", "Master moves require explicit local rotation pins.");
7315
7392
  }
7316
7393
  movePins = await assertVisioMasterIndependence(pkg, roots, commands, check);
7317
7394
  }
@@ -7408,7 +7485,7 @@ async function editVsdx(input, edits, options = {}) {
7408
7485
  const roots = /* @__PURE__ */ new Map();
7409
7486
  const geometry = commands.some((command2) => command2.type !== "replace-plain-text");
7410
7487
  let document;
7411
- let masterMovePins = /* @__PURE__ */ new Set();
7488
+ let masterMovePins = emptyMasterMoveProof();
7412
7489
  if (geometry) {
7413
7490
  for (const [pageId, path2] of pages) {
7414
7491
  const sourceRoot = await visioXml(pkg, path2, "PageContents");