@superdoc/mcp 1.6.1-next.1 → 1.7.0-next.1

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 (2) hide show
  1. package/dist/index.js +1075 -360
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -31600,7 +31600,7 @@ var init_host = __esm(() => {
31600
31600
  });
31601
31601
 
31602
31602
  // ../../packages/sdk/langs/node/src/runtime/sdk-version.generated.ts
31603
- var SDK_VERSION = "2.19.1-next.1";
31603
+ var SDK_VERSION = "2.20.0-next.1";
31604
31604
 
31605
31605
  // ../../packages/sdk/langs/node/src/runtime/embedded-platform.ts
31606
31606
  import { accessSync, chmodSync, constants, existsSync, statSync } from "node:fs";
@@ -104793,6 +104793,50 @@ var init_export_types = __esm(() => {
104793
104793
  SD_EXPORT_MODES = ["review-preserving", "final", "original"];
104794
104794
  });
104795
104795
 
104796
+ // ../../packages/document-api/dist/write/operation-cancellation.js
104797
+ function cancelledBeforeDispatch() {
104798
+ return new OperationCancellationError("CANCELLED", CANCELLED_MESSAGE, { cause: "cancelled" });
104799
+ }
104800
+ function isAbortSignal(value) {
104801
+ if (typeof value !== "object" || value === null)
104802
+ return false;
104803
+ const signal = value;
104804
+ return typeof signal.aborted === "boolean" && typeof signal.addEventListener === "function";
104805
+ }
104806
+ function assertOperationCanStart(options) {
104807
+ if (options === undefined)
104808
+ return;
104809
+ if (options.signal !== undefined && !isAbortSignal(options.signal)) {
104810
+ throw new DocumentApiValidationError("VALIDATION_ERROR", "signal must be an AbortSignal.", {
104811
+ field: "signal"
104812
+ });
104813
+ }
104814
+ if (options.timeoutMs !== undefined) {
104815
+ if (typeof options.timeoutMs !== "number" || !Number.isFinite(options.timeoutMs) || options.timeoutMs < 0) {
104816
+ throw new DocumentApiValidationError("VALIDATION_ERROR", "timeoutMs must be a finite number of milliseconds, 0 or greater.", {
104817
+ field: "timeoutMs",
104818
+ value: options.timeoutMs
104819
+ });
104820
+ }
104821
+ }
104822
+ if (options.signal?.aborted || options.timeoutMs !== undefined && options.timeoutMs <= 0) {
104823
+ throw cancelledBeforeDispatch();
104824
+ }
104825
+ }
104826
+ var OperationCancellationError, CANCELLED_MESSAGE = "The operation was cancelled before it changed the document.";
104827
+ var init_operation_cancellation = __esm(() => {
104828
+ init_errors5();
104829
+ OperationCancellationError = class OperationCancellationError extends Error {
104830
+ constructor(code, message, details) {
104831
+ super(message);
104832
+ this.name = "OperationCancellationError";
104833
+ this.code = code;
104834
+ this.details = details;
104835
+ Object.setPrototypeOf(this, OperationCancellationError.prototype);
104836
+ }
104837
+ };
104838
+ });
104839
+
104796
104840
  // ../../packages/document-api/dist/validation/selection-target-validator.js
104797
104841
  function isSelectionEdgeNodeAddress(value) {
104798
104842
  if (!isRecord6(value))
@@ -105540,6 +105584,7 @@ function validateStructuralInsertInput(input) {
105540
105584
  validateDocumentFragment(content);
105541
105585
  }
105542
105586
  function executeInsert(selectionAdapter, writeAdapter, input, options) {
105587
+ assertOperationCanStart(options);
105543
105588
  validateInsertInput(input);
105544
105589
  if (isStructuralInsertInput(input)) {
105545
105590
  return writeAdapter.insertStructured(input, normalizeMutationOptions(options));
@@ -105564,6 +105609,7 @@ var init_insert = __esm(() => {
105564
105609
  init_write();
105565
105610
  init_placement();
105566
105611
  init_errors5();
105612
+ init_operation_cancellation();
105567
105613
  init_validation_primitives();
105568
105614
  init_selection_target_validator();
105569
105615
  init_fragment_validator();
@@ -120857,7 +120903,8 @@ function createDocumentApi(adapters) {
120857
120903
  info(input) {
120858
120904
  return executeInfo(adapters.info, input);
120859
120905
  },
120860
- extract(input) {
120906
+ extract(input, options) {
120907
+ assertOperationCanStart(options);
120861
120908
  return executeExtract(adapters.extract, input);
120862
120909
  },
120863
120910
  clearContent(input, options) {
@@ -122032,7 +122079,8 @@ function createDocumentApi(adapters) {
122032
122079
  preview(input) {
122033
122080
  return adapters.mutations.preview(input);
122034
122081
  },
122035
- apply(input) {
122082
+ apply(input, options) {
122083
+ assertOperationCanStart(options);
122036
122084
  return adapters.mutations.apply(input);
122037
122085
  }
122038
122086
  },
@@ -122169,6 +122217,7 @@ var init_dist = __esm(() => {
122169
122217
  init_find_text();
122170
122218
  init_blocks();
122171
122219
  init_track_changes();
122220
+ init_operation_cancellation();
122172
122221
  init_capabilities();
122173
122222
  init_operation_definitions();
122174
122223
  init_invoke();
@@ -127288,7 +127337,8 @@ function buildStructuralBoundaryMap(bytes) {
127288
127337
  sdtOrdinal: sdtCounter,
127289
127338
  wrapperLocked: lockPolicy.wrapperLocked,
127290
127339
  contentLocked: lockPolicy.contentLocked,
127291
- contentEditable: !lockPolicy.contentLocked && isSdtContentEditable(sdtXml)
127340
+ contentEditable: !lockPolicy.contentLocked && isSdtContentEditable(sdtXml),
127341
+ textAtomic: isTextAtomicBlockSdt(sdtXml)
127292
127342
  });
127293
127343
  sdtCounter += 1;
127294
127344
  } else if (tag.local === "customXml") {
@@ -127311,6 +127361,7 @@ function recordParagraph2(input) {
127311
127361
  const blockCustomXmlPath = [];
127312
127362
  let hasLockedBlockSdt = false;
127313
127363
  let hasNonEditableBlockSdtContent = false;
127364
+ let hasTextAtomicBlockSdt = false;
127314
127365
  let hasContentLockedBlockSdt = false;
127315
127366
  let lastTable = -1;
127316
127367
  let lastRow = -1;
@@ -127330,6 +127381,7 @@ function recordParagraph2(input) {
127330
127381
  blockSdtPath.push(frame.sdtOrdinal);
127331
127382
  hasLockedBlockSdt || (hasLockedBlockSdt = frame.wrapperLocked);
127332
127383
  hasNonEditableBlockSdtContent || (hasNonEditableBlockSdtContent = !frame.contentEditable);
127384
+ hasTextAtomicBlockSdt || (hasTextAtomicBlockSdt = frame.textAtomic);
127333
127385
  hasContentLockedBlockSdt || (hasContentLockedBlockSdt = frame.contentLocked);
127334
127386
  } else if (frame.kind === "customXml") {
127335
127387
  blockCustomXmlPath.push(frame.customXmlOrdinal);
@@ -127342,6 +127394,7 @@ function recordParagraph2(input) {
127342
127394
  blockSdtPath,
127343
127395
  hasLockedBlockSdt,
127344
127396
  hasNonEditableBlockSdtContent,
127397
+ hasTextAtomicBlockSdt,
127345
127398
  hasContentLockedBlockSdt,
127346
127399
  blockCustomXmlPath,
127347
127400
  sectionIndex: input.sectionIndex,
@@ -127351,6 +127404,13 @@ function recordParagraph2(input) {
127351
127404
  carriesSectionBreak: carriesSectionBreak(input.paragraphXml)
127352
127405
  };
127353
127406
  }
127407
+ function isTextAtomicBlockSdt(sdtXml) {
127408
+ const contentMatch = /<(?:[\w.-]+:)?sdtContent\b/iu.exec(sdtXml);
127409
+ if (!contentMatch)
127410
+ return false;
127411
+ const properties = sdtXml.slice(0, contentMatch.index);
127412
+ return /<(?:[\w.-]+:)?(?:checkbox|dropDownList)\b/iu.test(properties);
127413
+ }
127354
127414
  function blockSdtLockPolicy(sdtXml) {
127355
127415
  const properties = /<(?:[\w.-]+:)?sdtPr\b[^>]*>([\s\S]*?)<\/(?:[\w.-]+:)?sdtPr\s*>/.exec(sdtXml)?.[1];
127356
127416
  if (!properties)
@@ -165856,7 +165916,7 @@ function planDirectInlineEdit(paragraphBytes, startOffset, endOffset, newText, c
165856
165916
  if (tocPlan)
165857
165917
  return tocPlan;
165858
165918
  if (startOffset === endOffset) {
165859
- const beside = planCollapsedInsertBesideContainer(paragraphBytes, xml, model.pieces, startOffset, newText);
165919
+ const beside = planCollapsedInsertBesideContainer(paragraphBytes, xml, model.pieces, startOffset, newText, collapsedInlineAffinity);
165860
165920
  if (beside)
165861
165921
  return beside;
165862
165922
  }
@@ -166330,19 +166390,22 @@ function planCollapsedInsert(paragraphBytes, xml, pieces, leaves, at, newText, t
166330
166390
  runPropertiesXml: carrier?.runProperties ?? paragraphMarkRPr
166331
166391
  };
166332
166392
  }
166333
- function planCollapsedInsertBesideContainer(paragraphBytes, xml, pieces, at, newText) {
166393
+ function planCollapsedInsertBesideContainer(paragraphBytes, xml, pieces, at, newText, collapsedInlineAffinity) {
166334
166394
  if (newText.length === 0)
166335
166395
  return null;
166336
166396
  for (const piece of pieces) {
166337
166397
  if (piece.kind !== "container")
166338
166398
  continue;
166339
- if (piece.containerKind !== "hyperlink" && piece.containerKind !== "fldSimple")
166399
+ if (piece.containerKind !== "hyperlink" && piece.containerKind !== "fldSimple" && piece.containerKind !== "sdt")
166340
166400
  continue;
166341
166401
  if (piece.visibleEnd <= piece.visibleStart)
166342
166402
  continue;
166343
166403
  const atLeading = piece.visibleStart === at && !hasVisibleSiblingEndingAt(pieces, at);
166344
166404
  const atTrailing = piece.visibleEnd === at && !hasVisibleSiblingStartingAt(pieces, at);
166345
- if (!atLeading && !atTrailing)
166405
+ const isSdt = piece.containerKind === "sdt";
166406
+ const leading = isSdt ? piece.visibleStart === at && collapsedInlineAffinity === "upstream" : atLeading;
166407
+ const trailing = isSdt ? piece.visibleEnd === at && collapsedInlineAffinity === "downstream" : atTrailing;
166408
+ if (!leading && !trailing)
166346
166409
  continue;
166347
166410
  const blocked = findBlockingPiece(pieces, at, at);
166348
166411
  if (blocked)
@@ -166354,7 +166417,7 @@ function planCollapsedInsertBesideContainer(paragraphBytes, xml, pieces, at, new
166354
166417
  const freshRunQnames = paragraphRunQnames(xml);
166355
166418
  if (!freshRunQnames)
166356
166419
  return { ok: false, reason: "invalid-range" };
166357
- const insertByte = atLeading ? Math.min(piece.byteStart, ...leadingRangeStarts.map((marker) => marker.runByteStart ?? marker.byteStart)) : Math.max(piece.byteEnd, ...trailingRangeEnds.map((marker) => marker.runByteEnd ?? marker.byteEnd));
166420
+ const insertByte = leading ? Math.min(piece.byteStart, ...leadingRangeStarts.map((marker) => marker.runByteStart ?? marker.byteStart)) : Math.max(piece.byteEnd, ...trailingRangeEnds.map((marker) => marker.runByteEnd ?? marker.byteEnd));
166358
166421
  const op = {
166359
166422
  start: insertByte,
166360
166423
  end: insertByte,
@@ -166363,7 +166426,8 @@ function planCollapsedInsertBesideContainer(paragraphBytes, xml, pieces, at, new
166363
166426
  return {
166364
166427
  ok: true,
166365
166428
  bytes: spliceBytes(paragraphBytes, [op]),
166366
- runPropertiesXml: paragraphMarkRPr
166429
+ runPropertiesXml: paragraphMarkRPr,
166430
+ ...isSdt ? { requiresCollaborationSessionSync: true } : {}
166367
166431
  };
166368
166432
  }
166369
166433
  return null;
@@ -171992,6 +172056,7 @@ function isTerminalDeletionOfPendingFullParagraphInsertion(fragment3, entries) {
171992
172056
  }
171993
172057
  function collectTextCandidates(lookupContext, partXml, entries, storyId) {
171994
172058
  const out = [];
172059
+ const bookmarkGroups = collectBookmarkRevisionGroups(entries.filter((entry) => entry.type === "insertion").flatMap((entry) => entry.fragments), partXml);
171995
172060
  for (const entry of entries) {
171996
172061
  if (entry.type !== "insertion" || entry.subtype !== "text-insertion")
171997
172062
  continue;
@@ -172003,6 +172068,8 @@ function collectTextCandidates(lookupContext, partXml, entries, storyId) {
172003
172068
  continue;
172004
172069
  if (entry.fragments.length === 0)
172005
172070
  continue;
172071
+ if (entry.fragments.every((fragment3) => bookmarkGroups.has(fragment3)))
172072
+ continue;
172006
172073
  if (!entry.fragments.every((fragment3) => fragment3.kind === "ins"))
172007
172074
  continue;
172008
172075
  let paragraphStart = null;
@@ -173852,6 +173919,7 @@ var init_review_groups = __esm(() => {
173852
173919
  init_structural_groups();
173853
173920
  init_numbering_catalog();
173854
173921
  init_field_paragraph_deletion_groups();
173922
+ init_bookmark_revision_groups();
173855
173923
  init_field_paragraph_range_deletion_groups();
173856
173924
  init_image_paragraph_deletion_groups();
173857
173925
  });
@@ -194696,7 +194764,7 @@ var init_created_text_span_proof = __esm(() => {
194696
194764
  });
194697
194765
 
194698
194766
  // ../../../v2/editor-core/dist/document/transactions/content-locked-block-sdt.js
194699
- function isParagraphInsideContentLockedBlockSdt(state, address2) {
194767
+ function isParagraphInsideNonEditableBlockSdt(state, address2) {
194700
194768
  const index = address2.storyId === state.mainStoryId ? getMainParagraphIndexFromState(state) : getStoryParagraphIndexFromState(state, address2.storyId);
194701
194769
  const entry = index?.byParaId(address2.blockId);
194702
194770
  if (!entry || entry.directBodyChildOrdinal != null || entry.containingBodyChildOrdinal == null) {
@@ -194711,7 +194779,7 @@ function isParagraphInsideContentLockedBlockSdt(state, address2) {
194711
194779
  return false;
194712
194780
  const map3 = buildStructuralBoundaryMap(scanBytes);
194713
194781
  const context = map3.byBlockId(entry.blockId) ?? map3.contexts[entry.ordinal - (chunk?.scanParagraphStartOrdinal ?? 0)] ?? null;
194714
- return context?.hasContentLockedBlockSdt === true;
194782
+ return context?.hasContentLockedBlockSdt === true || context?.hasTextAtomicBlockSdt === true;
194715
194783
  }
194716
194784
  function provesNoSdtCarrier(bytes) {
194717
194785
  if (bytes.length === 0 || bytes.includes(0))
@@ -198895,7 +198963,7 @@ function runEditTextCommit(input) {
198895
198963
  return rejected2(txId, "unsupported-context");
198896
198964
  return rejected2(txId, classifyCrossBlockEditText(bytes, op));
198897
198965
  }
198898
- if (isParagraphInsideContentLockedBlockSdt(state, {
198966
+ if (isParagraphInsideNonEditableBlockSdt(state, {
198899
198967
  storyId: op.on.storyId,
198900
198968
  partUri: op.on.partUri,
198901
198969
  blockId: op.on.startBlockId
@@ -198959,7 +199027,10 @@ function runDirectEditTextBatchCommit(input, edits) {
198959
199027
  for (const [blockId, blockEdits] of byBlock) {
198960
199028
  let blockUsedOverlapCompiler = false;
198961
199029
  const paragraph = index.byParaId(blockId);
198962
- if (!paragraph || index.duplicateParaIds.has(blockId) || paragraph.partUri !== partUri || paragraph.partRevision !== first.on.partRevision || paragraph.storyRevision !== first.on.storyRevision || isParagraphInsideContentLockedBlockSdt(state, { storyId, partUri, blockId })) {
199030
+ if (isParagraphInsideNonEditableBlockSdt(state, { storyId, partUri, blockId })) {
199031
+ return rejected2(txId, "text-range-in-sdt");
199032
+ }
199033
+ if (!paragraph || index.duplicateParaIds.has(blockId) || paragraph.partUri !== partUri || paragraph.partRevision !== first.on.partRevision || paragraph.storyRevision !== first.on.storyRevision) {
198963
199034
  return rejected2(txId, "patch-precondition-failed");
198964
199035
  }
198965
199036
  for (const edit of blockEdits) {
@@ -199378,7 +199449,10 @@ function runTrackedEditTextBatchCommit(input, edits) {
199378
199449
  let requiresCollaborationSessionSync = false;
199379
199450
  for (const [blockId, blockEdits] of byBlock) {
199380
199451
  const paragraph = index.byParaId(blockId);
199381
- if (!paragraph || index.duplicateParaIds.has(blockId) || paragraph.partUri !== partUri || paragraph.partRevision !== first.on.partRevision || paragraph.storyRevision !== first.on.storyRevision || isParagraphInsideContentLockedBlockSdt(state, { storyId, partUri, blockId })) {
199452
+ if (isParagraphInsideNonEditableBlockSdt(state, { storyId, partUri, blockId })) {
199453
+ return rejected2(txId, "text-range-in-sdt");
199454
+ }
199455
+ if (!paragraph || index.duplicateParaIds.has(blockId) || paragraph.partUri !== partUri || paragraph.partRevision !== first.on.partRevision || paragraph.storyRevision !== first.on.storyRevision) {
199382
199456
  return rejected2(txId, "patch-precondition-failed");
199383
199457
  }
199384
199458
  for (const edit of blockEdits) {
@@ -199774,7 +199848,7 @@ function runInsertInlineControlCommit(input) {
199774
199848
  if (op.on.startByte < 0 || op.on.endByte > bytes.length || op.on.startByte > op.on.endByte) {
199775
199849
  return rejected2(txId, "invalid-range");
199776
199850
  }
199777
- if (isParagraphInsideContentLockedBlockSdt(state, {
199851
+ if (isParagraphInsideNonEditableBlockSdt(state, {
199778
199852
  storyId: op.on.storyId,
199779
199853
  partUri: op.on.partUri,
199780
199854
  blockId: op.on.startBlockId
@@ -217912,6 +217986,45 @@ function collectFieldChar(fieldChars, { tag, start, end }) {
217912
217986
  locked: lock === "true" || lock === "1" || lock === "on"
217913
217987
  });
217914
217988
  }
217989
+ function createFieldTokenCollector(fieldChars, instructionTokens) {
217990
+ const instructionContexts = [];
217991
+ return {
217992
+ onOpenTag({ tag, start, end, namespaceBindings }) {
217993
+ const parent = instructionContexts.at(-1);
217994
+ const inWordRun = parent?.inWordRun ?? false;
217995
+ const isWord = tag.namespaceUri === NS_W || tag.namespaceUri === NS_WSTRICT;
217996
+ const isMce = tag.namespaceUri === NS_MC;
217997
+ const isRunProxy = isMce && (tag.localName === "AlternateContent" || tag.localName === "Choice" || tag.localName === "Fallback");
217998
+ const context = {
217999
+ inWordRun: isWord && tag.localName === "r" || isRunProxy && inWordRun,
218000
+ deleted: (parent?.deleted ?? false) || isWord && (tag.localName === "del" || tag.localName === "moveFrom"),
218001
+ effective: parent?.effective ?? true,
218002
+ choiceSelected: isMce && tag.localName === "AlternateContent" ? false : undefined
218003
+ };
218004
+ if (isMce && parent?.choiceSelected != null) {
218005
+ if (tag.localName === "Choice") {
218006
+ const requires = readXmlAttribute(tag, "", "Requires")?.value.trim().split(/\s+/).filter(Boolean) ?? [];
218007
+ const selected = !parent.choiceSelected && requires.length > 0 && requires.every((prefix) => UNDERSTOOD_FIELD_INSTRUCTION_NAMESPACES.has(namespaceBindings[prefix] ?? ""));
218008
+ context.effective && (context.effective = selected);
218009
+ if (selected)
218010
+ parent.choiceSelected = true;
218011
+ } else if (tag.localName === "Fallback") {
218012
+ context.effective && (context.effective = !parent.choiceSelected);
218013
+ }
218014
+ }
218015
+ instructionContexts.push(context);
218016
+ if (!isWord)
218017
+ return;
218018
+ if (tag.localName === "tab" && inWordRun && !context.deleted && context.effective) {
218019
+ instructionTokens.push({ start, text: "\t", inlineTab: true });
218020
+ }
218021
+ collectFieldChar(fieldChars, { tag, start, end, namespaceBindings });
218022
+ },
218023
+ onCloseTag() {
218024
+ instructionContexts.pop();
218025
+ }
218026
+ };
218027
+ }
217915
218028
  function buildFieldCatalogFromXml(input, xml, utf8Offsets) {
217916
218029
  let paragraphScan = input.sharedParagraphScan ?? null;
217917
218030
  const ownerResolution = {
@@ -217976,12 +218089,29 @@ function buildFieldCatalogFromXml(input, xml, utf8Offsets) {
217976
218089
  }
217977
218090
  const discovered = [];
217978
218091
  const fieldChars = input.preparedFieldChars ?? discovered;
218092
+ const instructionTokens = [...input.preparedInstructionTokens ?? []];
217979
218093
  if (input.preparedFieldChars === undefined && /<(?:[\w.-]+:)?fldChar\b/.test(xml)) {
217980
- walkXmlElements(xml, { onOpenTag: (event) => collectFieldChar(discovered, event) });
218094
+ walkXmlElements(xml, createFieldTokenCollector(discovered, instructionTokens));
218095
+ }
218096
+ if (fieldChars.length > 0) {
218097
+ const instrTextRe = /<[\w.-]+:instrText\b[^>]*>([\s\S]*?)<\/[\w.-]+:instrText>/g;
218098
+ for (let match = instrTextRe.exec(xml);match; match = instrTextRe.exec(xml)) {
218099
+ instructionTokens.push({ start: match.index, text: decodeXmlText(match[1]) });
218100
+ }
218101
+ instructionTokens.sort((left, right) => left.start - right.start);
217981
218102
  }
217982
- const instrTextRe = /<([\w.-]+):instrText\b[^>]*>([\s\S]*?)<\/[\w.-]+:instrText>/g;
218103
+ let instructionIndex = 0;
217983
218104
  const stack = [];
217984
218105
  for (const marker of fieldChars) {
218106
+ while (instructionIndex < instructionTokens.length && instructionTokens[instructionIndex].start < marker.start) {
218107
+ const token = instructionTokens[instructionIndex++];
218108
+ if (token.inlineTab && stack.at(-1)?.separateAt != null)
218109
+ continue;
218110
+ for (const frame of stack) {
218111
+ if (frame.separateAt == null)
218112
+ frame.instructionFragments.push(token.text);
218113
+ }
218114
+ }
217985
218115
  const charType = marker.type;
217986
218116
  const matchStart = marker.start;
217987
218117
  const matchEnd = marker.end;
@@ -218016,16 +218146,7 @@ function buildFieldCatalogFromXml(input, xml, utf8Offsets) {
218016
218146
  const fieldEnd = endEnclosingRunEnd;
218017
218147
  const resultStart = frame.resultStartOffset ?? fieldEnd;
218018
218148
  const resultEnd = Math.max(resultStart, enclosingRunStart(xml, matchStart));
218019
- const instrSpanStart = frame.beginOffset;
218020
- const instrSpanEnd = frame.separateAt ?? matchStart;
218021
- const instrSlice = xml.slice(instrSpanStart, instrSpanEnd);
218022
- const instrTextParts = [];
218023
- let instrM;
218024
- const instrLocal = new RegExp(instrTextRe.source, "g");
218025
- while ((instrM = instrLocal.exec(instrSlice)) != null) {
218026
- instrTextParts.push(decodeXmlText(instrM[2] ?? ""));
218027
- }
218028
- const instructionText = instrTextParts.join("").trim();
218149
+ const instructionText = frame.instructionFragments.join("").trim();
218029
218150
  const resultText = frame.separateAt != null ? extractText(xml.slice(resultStart, resultEnd)) : "";
218030
218151
  const paraId = enclosingParaId(frame.beginOffset);
218031
218152
  const byteStart = byteOffsetAt3(utf8Offsets, fieldStart);
@@ -218539,12 +218660,13 @@ async function buildFieldCatalogForStoryCooperatively(input) {
218539
218660
  }
218540
218661
  }
218541
218662
  const preparedFieldChars = [];
218663
+ const preparedInstructionTokens = [];
218542
218664
  if (/<(?:[\w.-]+:)?fldChar\b/.test(decoded.xml)) {
218543
218665
  let aborted2 = false;
218544
218666
  let yieldFailed = false;
218545
218667
  let yieldError;
218546
218668
  await walkXmlElementsCooperatively(decoded.xml, {
218547
- onOpenTag: (event) => collectFieldChar(preparedFieldChars, event),
218669
+ ...createFieldTokenCollector(preparedFieldChars, preparedInstructionTokens),
218548
218670
  yieldPoint: async () => {
218549
218671
  let current;
218550
218672
  try {
@@ -218576,6 +218698,7 @@ async function buildFieldCatalogForStoryCooperatively(input) {
218576
218698
  storyId: input.storyId,
218577
218699
  partUri: input.partUri,
218578
218700
  preparedFieldChars,
218701
+ preparedInstructionTokens,
218579
218702
  ...paragraphOwnerResolver ? { paragraphOwnerResolver } : { sharedParagraphScan }
218580
218703
  }, decoded.xml, utf8Offsets);
218581
218704
  catalog.ownerResolution.packedRejectionReason = ownerDiagnostics.rejectionReason;
@@ -218606,7 +218729,7 @@ function listFieldCatalogsForState(state) {
218606
218729
  }
218607
218730
  return out;
218608
218731
  }
218609
- var TD53, UTF8_OFFSET_CHECKPOINT_STRIDE = 256, FIELD_CANDIDATE_BYTES, FIELD_CANDIDATE_SEARCHES, STATE_CACHE2, STATE_IN_FLIGHT, DECODED_PART_IN_FLIGHT;
218732
+ var TD53, UTF8_OFFSET_CHECKPOINT_STRIDE = 256, UNDERSTOOD_FIELD_INSTRUCTION_NAMESPACES, FIELD_CANDIDATE_BYTES, FIELD_CANDIDATE_SEARCHES, STATE_CACHE2, STATE_IN_FLIGHT, DECODED_PART_IN_FLIGHT;
218610
218733
  var init_field_catalog = __esm(() => {
218611
218734
  init_sd_document_state();
218612
218735
  init_xml_text();
@@ -218615,6 +218738,7 @@ var init_field_catalog = __esm(() => {
218615
218738
  init_part_wml_scan_cache();
218616
218739
  init_field_paragraph_owner();
218617
218740
  TD53 = new TextDecoder;
218741
+ UNDERSTOOD_FIELD_INSTRUCTION_NAMESPACES = new Set([NS_W, NS_WSTRICT, NS_W14]);
218618
218742
  FIELD_CANDIDATE_BYTES = [["fldSimple", 3], ["fldChar", 3], ["instrText", 7]];
218619
218743
  FIELD_CANDIDATE_SEARCHES = FIELD_CANDIDATE_BYTES.map(([token, anchorOffset]) => ({
218620
218744
  token: new TextEncoder().encode(token),
@@ -224191,11 +224315,11 @@ function runTrackedTextMoveCommit(input) {
224191
224315
  if (source.value.entry.storyId !== input.state.mainStoryId) {
224192
224316
  return rejected10(input.txId, "tracked-text-move-cross-story");
224193
224317
  }
224194
- if (isParagraphInsideContentLockedBlockSdt(input.state, {
224318
+ if (isParagraphInsideNonEditableBlockSdt(input.state, {
224195
224319
  storyId: source.value.entry.storyId,
224196
224320
  partUri: source.value.entry.partUri,
224197
224321
  blockId: source.value.entry.blockId
224198
- }) || isParagraphInsideContentLockedBlockSdt(input.state, {
224322
+ }) || isParagraphInsideNonEditableBlockSdt(input.state, {
224199
224323
  storyId: destination.entry.storyId,
224200
224324
  partUri: destination.entry.partUri,
224201
224325
  blockId: destination.entry.blockId
@@ -246317,6 +246441,7 @@ class TxContext {
246317
246441
  }
246318
246442
  commitInsertComment(op) {
246319
246443
  const replay = this.compareCommentCreateMetadata;
246444
+ const commentDate = replay ? replay.date ?? undefined : this.txTimestamp;
246320
246445
  const commentAuthor = replay?.author ?? op.author ?? this.author;
246321
246446
  if (!commentAuthor)
246322
246447
  return rejected20(this.txId, "no-author-configured");
@@ -246398,7 +246523,7 @@ class TxContext {
246398
246523
  paraId: nextParaId,
246399
246524
  author: commentAuthor,
246400
246525
  body: op.body,
246401
- ...replay?.date ? { date: replay.date } : {},
246526
+ date: commentDate,
246402
246527
  isExplicitRoot: true,
246403
246528
  trackedChangeMetadata: op.trackedChangeMetadata,
246404
246529
  externalId: op.externalId,
@@ -246449,7 +246574,7 @@ class TxContext {
246449
246574
  paraId: nextParaId,
246450
246575
  author: commentAuthor,
246451
246576
  body: op.body,
246452
- ...replay?.date ? { date: replay.date } : {},
246577
+ date: commentDate,
246453
246578
  isExplicitRoot: true,
246454
246579
  trackedChangeMetadata: op.trackedChangeMetadata,
246455
246580
  externalId: op.externalId,
@@ -246682,6 +246807,7 @@ class TxContext {
246682
246807
  paraId: nextParaId,
246683
246808
  author: commentAuthor,
246684
246809
  body: op.body,
246810
+ date: this.txTimestamp,
246685
246811
  isExplicitRoot: true,
246686
246812
  trackedChangeMetadata: op.trackedChangeMetadata,
246687
246813
  externalId: op.externalId,
@@ -246713,6 +246839,7 @@ class TxContext {
246713
246839
  paraId: nextParaId,
246714
246840
  author: commentAuthor,
246715
246841
  body: op.body,
246842
+ date: this.txTimestamp,
246716
246843
  isExplicitRoot: true,
246717
246844
  trackedChangeMetadata: op.trackedChangeMetadata,
246718
246845
  externalId: op.externalId,
@@ -247013,6 +247140,7 @@ class TxContext {
247013
247140
  paraId: nextParaId,
247014
247141
  author: commentAuthor,
247015
247142
  body: op.body,
247143
+ date: this.txTimestamp,
247016
247144
  trackedChangeMetadata: op.trackedChangeMetadata,
247017
247145
  externalId: op.externalId,
247018
247146
  authorId: op.authorId,
@@ -290292,6 +290420,107 @@ var init_section_xml = __esm(() => {
290292
290420
  SECTPR_CHILD_RANK = new Map(SECTPR_CHILD_ORDER.map((name, index) => [name, index]));
290293
290421
  });
290294
290422
 
290423
+ // ../../../v2/document-api-v2-adapter/dist/formatting/paragraph-property-order.js
290424
+ function setParagraphPropertyChild(children2, localName2, xml) {
290425
+ const parsed = parseSingleElement(xml);
290426
+ const existingIndex = children2.findIndex((child) => child.localName === localName2);
290427
+ if (existingIndex >= 0) {
290428
+ const next = [...children2];
290429
+ next[existingIndex] = parsed;
290430
+ return next;
290431
+ }
290432
+ const targetRank = PARAGRAPH_PROPERTY_CHILD_RANK.get(localName2);
290433
+ if (targetRank == null)
290434
+ throw new Error(`Unknown paragraph property child: ${localName2}`);
290435
+ let insertionIndex = 0;
290436
+ for (const [index, child] of children2.entries()) {
290437
+ const childRank = paragraphPropertyRankRange(child);
290438
+ if (!childRank)
290439
+ continue;
290440
+ if (childRank.minimum > targetRank) {
290441
+ return [...children2.slice(0, index), parsed, ...children2.slice(index)];
290442
+ }
290443
+ if (childRank.maximum >= targetRank) {
290444
+ throw new ParagraphPropertyMutationUnavailableError(`Cannot safely insert w:${localName2} within mc:AlternateContent paragraph properties`);
290445
+ }
290446
+ insertionIndex = index + 1;
290447
+ }
290448
+ return [...children2.slice(0, insertionIndex), parsed, ...children2.slice(insertionIndex)];
290449
+ }
290450
+ function paragraphPropertyRankRange(child) {
290451
+ const directRank = PARAGRAPH_PROPERTY_CHILD_RANK.get(child.localName);
290452
+ if (directRank != null)
290453
+ return { minimum: directRank, maximum: directRank };
290454
+ if (child.localName !== "AlternateContent")
290455
+ return null;
290456
+ const alternateContent = parseContainerXml(child.xml, "AlternateContent");
290457
+ if (!alternateContent)
290458
+ return null;
290459
+ const ranks = parseTopLevelChildren(alternateContent.inner).flatMap((branch) => {
290460
+ if (branch.localName !== "Choice" && branch.localName !== "Fallback")
290461
+ return [];
290462
+ const branchContainer = parseContainerXml(branch.xml, branch.localName);
290463
+ if (!branchContainer)
290464
+ return [];
290465
+ return parseTopLevelChildren(branchContainer.inner).flatMap((candidate2) => {
290466
+ const range = paragraphPropertyRankRange(candidate2);
290467
+ return range ? [range.minimum, range.maximum] : [];
290468
+ });
290469
+ });
290470
+ if (ranks.length === 0)
290471
+ return null;
290472
+ return { minimum: Math.min(...ranks), maximum: Math.max(...ranks) };
290473
+ }
290474
+ var PARAGRAPH_PROPERTY_CHILD_ORDER, PARAGRAPH_PROPERTY_CHILD_RANK, ParagraphPropertyMutationUnavailableError;
290475
+ var init_paragraph_property_order = __esm(() => {
290476
+ init_common();
290477
+ PARAGRAPH_PROPERTY_CHILD_ORDER = [
290478
+ "pStyle",
290479
+ "keepNext",
290480
+ "keepLines",
290481
+ "pageBreakBefore",
290482
+ "framePr",
290483
+ "widowControl",
290484
+ "numPr",
290485
+ "suppressLineNumbers",
290486
+ "pBdr",
290487
+ "shd",
290488
+ "tabs",
290489
+ "suppressAutoHyphens",
290490
+ "kinsoku",
290491
+ "wordWrap",
290492
+ "overflowPunct",
290493
+ "topLinePunct",
290494
+ "autoSpaceDE",
290495
+ "autoSpaceDN",
290496
+ "bidi",
290497
+ "adjustRightInd",
290498
+ "snapToGrid",
290499
+ "spacing",
290500
+ "ind",
290501
+ "contextualSpacing",
290502
+ "mirrorIndents",
290503
+ "suppressOverlap",
290504
+ "jc",
290505
+ "textDirection",
290506
+ "textAlignment",
290507
+ "textboxTightWrap",
290508
+ "outlineLvl",
290509
+ "divId",
290510
+ "cnfStyle",
290511
+ "rPr",
290512
+ "sectPr",
290513
+ "pPrChange"
290514
+ ];
290515
+ PARAGRAPH_PROPERTY_CHILD_RANK = new Map(PARAGRAPH_PROPERTY_CHILD_ORDER.map((name, index) => [name, index]));
290516
+ ParagraphPropertyMutationUnavailableError = class ParagraphPropertyMutationUnavailableError extends Error {
290517
+ constructor(message) {
290518
+ super(message);
290519
+ this.name = "ParagraphPropertyMutationUnavailableError";
290520
+ }
290521
+ };
290522
+ });
290523
+
290295
290524
  // ../../../v2/document-api-v2-adapter/dist/references/date-time-field.js
290296
290525
  function readDateTimePictureSwitch(instruction) {
290297
290526
  return /\\@\s+"([^"]*)"/u.exec(instruction)?.[1] ?? null;
@@ -292099,17 +292328,18 @@ function buildTocFieldBodyXml(context, instruction, options) {
292099
292328
  return buildComplexFieldXml(instruction, buildTocFieldResultXml(context, instruction, options));
292100
292329
  }
292101
292330
  function buildTocFieldResultXml(context, instruction, options) {
292102
- if (shouldUseV1EmptyTocSourceSet(instruction)) {
292103
- return buildTextRunXml("No table of contents entries found.");
292104
- }
292105
- const entries = buildTocEntries(context, instruction, options?.currentField, options?.preservedTocPages, options?.tocBookmarkNames);
292331
+ return buildTocFieldResult(context, instruction, options).xml;
292332
+ }
292333
+ function buildTocFieldResult(context, instruction, options) {
292334
+ const emptyText = shouldUseV1EmptyTocSourceSet(instruction) ? "No table of contents entries found." : "";
292335
+ const entries = emptyText ? [] : buildTocEntries(context, instruction, options?.currentField, options?.preservedTocPages, options?.tocBookmarkNames);
292106
292336
  if (options?.currentField) {
292107
- return buildTocResultXmlPreservingParagraphs(context, instruction, entries, options.currentField);
292337
+ return buildTocResultXmlPreservingParagraphs(context, instruction, entries, options.currentField, emptyText);
292108
292338
  }
292109
- return buildTocResultRunsXml(instruction, entries);
292339
+ return { xml: emptyText ? buildTextRunXml(emptyText) : buildTocResultRunsXml(instruction, entries) };
292110
292340
  }
292111
292341
  function buildTocFieldXml(context, instruction, options) {
292112
- const contentXml = options?.currentField && options.preserveParagraphs ? buildTocFieldBodyXml(context, instruction, options) : buildNewTocFieldContentXml(context, instruction, options?.seedParagraph, options?.currentField, options?.preservedTocPages, options?.reservedParaIds, options?.tocBookmarkNames);
292342
+ const contentXml = options?.currentField && options.preserveParagraphs ? buildTocFieldBodyXml(context, instruction, options) : buildNewTocFieldContentXml(context, instruction, options?.seedParagraph, options?.currentField, options?.preservedTocPages, options?.reservedParaIds, options?.tocBookmarkNames, options?.insertionByteStart);
292113
292343
  if (options?.bare)
292114
292344
  return contentXml;
292115
292345
  return "<w:sdt>" + "<w:sdtPr>" + "<w:docPartObj>" + '<w:docPartGallery w:val="Table of Contents"/>' + "<w:docPartUnique/>" + "</w:docPartObj>" + "</w:sdtPr>" + "<w:sdtContent>" + contentXml + "</w:sdtContent>" + "</w:sdt>";
@@ -292496,28 +292726,8 @@ function prepareTocSdtReplacement(context, entry, instruction, tocBookmarkNames)
292496
292726
  afterXml: buildNewTocFieldContentXml(context, instruction, paragraph2, entry, preservedTocPages, reservedParaIds, tocBookmarkNames)
292497
292727
  };
292498
292728
  }
292499
- function replaceTocSdtXml(context, entry, instruction, txIdPrefix) {
292500
- const prepared = prepareTocSdtReplacement(context, entry, instruction);
292501
- if (!prepared.ok)
292502
- return prepared;
292503
- const nextBytes = spliceBytes3(prepared.bytes, prepared.byteStart, prepared.byteEnd, encodeXml(prepared.afterXml));
292504
- return commitKernelStorySurfacePatch({
292505
- context,
292506
- txIdPrefix,
292507
- perPart: { [entry.partUri]: replaceWholePartEntry(prepared.bytes, nextBytes) },
292508
- storyIds: [entry.storyId],
292509
- signalLanesToRebuild: ["paragraphIndex", "headings", "noteAnchorRefs"]
292510
- });
292511
- }
292512
292729
  function replaceTocXml(context, entry, instruction, txIdPrefix) {
292513
- const sdtReplacement = replaceTocSdtXml(context, entry, instruction, txIdPrefix);
292514
- if (sdtReplacement.ok || sdtReplacement.message !== "Unable to locate the containing TOC content control.") {
292515
- return sdtReplacement;
292516
- }
292517
- return replaceBareTocFieldXml(context, entry, instruction, txIdPrefix);
292518
- }
292519
- function replaceBareTocFieldXml(context, entry, instruction, txIdPrefix) {
292520
- const prepared = prepareBareTocFieldReplacement(context, entry, instruction);
292730
+ const prepared = prepareTocReplacement(context, entry, instruction);
292521
292731
  if (!prepared.ok)
292522
292732
  return prepared;
292523
292733
  const nextBytes = spliceBytes3(prepared.bytes, prepared.byteStart, prepared.byteEnd, encodeXml(prepared.afterXml));
@@ -292529,6 +292739,10 @@ function replaceBareTocFieldXml(context, entry, instruction, txIdPrefix) {
292529
292739
  signalLanesToRebuild: ["paragraphIndex", "headings", "noteAnchorRefs"]
292530
292740
  });
292531
292741
  }
292742
+ function prepareTocReplacement(context, entry, instruction, tocBookmarkNames) {
292743
+ const sdt = prepareTocSdtReplacement(context, entry, instruction, tocBookmarkNames);
292744
+ return !sdt.ok && sdt.message === "Unable to locate the containing TOC content control." ? prepareBareTocFieldReplacement(context, entry, instruction, tocBookmarkNames) : sdt;
292745
+ }
292532
292746
  function prepareBareTocReplacement(context, entry, instruction, tocBookmarkNames) {
292533
292747
  const prepared = prepareBareTocFieldReplacement(context, entry, instruction, tocBookmarkNames);
292534
292748
  if (!prepared.ok)
@@ -292568,18 +292782,112 @@ function prepareBareTocFieldReplacement(context, entry, instruction, tocBookmark
292568
292782
  }
292569
292783
  const xml = TD83.decode(bytes);
292570
292784
  const preservedTocPages = readPreservedTocPagesFromPartXml(xml);
292571
- const nextFieldXml = shouldUseV1EmptyTocSourceSet(instruction) ? buildComplexFieldXml(instruction, buildTextRunXml("No table of contents entries found.")) : buildTocFieldBodyXml(context, instruction, { currentField: entry, preservedTocPages, tocBookmarkNames });
292785
+ const result = buildTocFieldResult(context, instruction, { currentField: entry, preservedTocPages, tocBookmarkNames });
292786
+ const nextFieldXml = buildComplexFieldXml(instruction, result.xml);
292787
+ const fieldStartChar = TD83.decode(bytes.subarray(0, entry.descriptor.byteStart)).length;
292788
+ const fieldEndChar = TD83.decode(bytes.subarray(0, entry.descriptor.byteEnd)).length;
292789
+ const paragraphStart = findEnclosingParagraphStart(xml, fieldStartChar, 0);
292790
+ const paragraphOpenEnd = paragraphStart >= 0 ? findXmlTagEnd4(xml, paragraphStart + 1) : -1;
292791
+ const paragraphCloseStart = xml.indexOf("</w:p>", fieldStartChar);
292792
+ const paragraphPropertiesStart = paragraphOpenEnd >= 0 ? skipXmlWhitespace(xml, paragraphOpenEnd) : -1;
292793
+ const paragraphProperties = paragraphOpenEnd >= 0 ? matchLeadingElement(xml.slice(paragraphPropertiesStart, fieldStartChar), "pPr") : "";
292794
+ const ownsFirstParagraph = entry.descriptor.complete && paragraphOpenEnd >= 0 && paragraphCloseStart >= fieldStartChar && readTocParagraphLevel(paragraphProperties) != null && xml.slice(paragraphPropertiesStart + paragraphProperties.length, fieldStartChar).trim() === "" && (fieldEndChar >= paragraphCloseStart || xml.slice(fieldEndChar, paragraphCloseStart).trim() === "");
292795
+ const replaceParagraphProperties = ownsFirstParagraph && result.firstParagraphProperties != null;
292796
+ const byteStart = replaceParagraphProperties ? encodeXml(xml.slice(0, paragraphOpenEnd)).length : entry.descriptor.byteStart;
292797
+ const nextParagraphProperties = replaceParagraphProperties ? preserveTocOwnerProperties(result.firstParagraphProperties, paragraphProperties) : "";
292798
+ const afterXml = nextParagraphProperties + nextFieldXml;
292799
+ const nextXml = TD83.decode(spliceBytes3(bytes, byteStart, entry.descriptor.byteEnd, encodeXml(afterXml)));
292800
+ if (collectXmlElementRanges(nextXml).errors.length > 0) {
292801
+ return {
292802
+ ok: false,
292803
+ code: "CAPABILITY_UNAVAILABLE",
292804
+ message: "The bare TOC replacement crosses unsupported XML boundaries."
292805
+ };
292806
+ }
292572
292807
  return {
292573
292808
  ok: true,
292574
292809
  bytes,
292575
- byteStart: entry.descriptor.byteStart,
292810
+ byteStart,
292576
292811
  byteEnd: entry.descriptor.byteEnd,
292577
- beforeXml: TD83.decode(bytes.subarray(entry.descriptor.byteStart, entry.descriptor.byteEnd)),
292578
- afterXml: nextFieldXml
292812
+ beforeXml: TD83.decode(bytes.subarray(byteStart, entry.descriptor.byteEnd)),
292813
+ afterXml
292579
292814
  };
292580
292815
  }
292816
+ function findDirectChild(xml, localName2) {
292817
+ return scanDirectElementChildren(xml).find((child) => xmlLocalName(child.qname) === localName2);
292818
+ }
292819
+ function removeTocOwnerPropertiesFromTemplate(xml) {
292820
+ const properties = matchLeadingElement(xml, "pPr") || findDirectChild(xml, "pPr")?.xml;
292821
+ if (!properties)
292822
+ return xml;
292823
+ for (const child of scanDirectElementChildren(properties)) {
292824
+ if (["rPr", "sectPr", "pPrChange"].includes(xmlLocalName(child.qname))) {
292825
+ xml = xml.replace(child.xml, "");
292826
+ }
292827
+ }
292828
+ return xml;
292829
+ }
292830
+ function preserveTocOwnerProperties(template, ownerProperties) {
292831
+ const properties = removeTocOwnerPropertiesFromTemplate(template);
292832
+ const retained = ["rPr", "sectPr", "pPrChange"].map((name) => {
292833
+ const child = findDirectChild(ownerProperties, name);
292834
+ return child ? inheritRunNamespaceDeclarations(child.xml, ownerProperties, ownerProperties.indexOf(child.xml), ownerProperties.slice(0, findXmlTagEnd4(ownerProperties, 1))) : "";
292835
+ }).join("");
292836
+ const insertAt = properties.lastIndexOf("</");
292837
+ return properties.slice(0, insertAt) + retained + properties.slice(insertAt);
292838
+ }
292839
+ function removeTocSectionBoundaryFromTemplate(xml) {
292840
+ const properties = matchLeadingElement(xml, "pPr") || findDirectChild(xml, "pPr")?.xml;
292841
+ if (!properties)
292842
+ return xml;
292843
+ const section = findDirectChild(properties, "sectPr");
292844
+ return section ? xml.replace(section.xml, "") : xml;
292845
+ }
292846
+ function readTocContinuationSectionPlacement(paragraphs, entryCount) {
292847
+ const byEntryIndex = new Map;
292848
+ const carriers = [];
292849
+ for (const [index, paragraph2] of paragraphs.entries()) {
292850
+ if (index === 0)
292851
+ continue;
292852
+ const properties = findDirectChild(paragraph2, "pPr");
292853
+ if (!properties || !findDirectChild(properties.xml, "sectPr"))
292854
+ continue;
292855
+ if (index === paragraphs.length - 1) {
292856
+ const lastEntryIndex = entryCount - 1;
292857
+ if (readTocParagraphTemplateText(paragraph2) && lastEntryIndex > 0 && !byEntryIndex.has(lastEntryIndex) && carriers.length === 0) {
292858
+ byEntryIndex.set(lastEntryIndex, paragraph2);
292859
+ } else {
292860
+ carriers.push(paragraph2);
292861
+ }
292862
+ } else if (index < entryCount) {
292863
+ byEntryIndex.set(index, paragraph2);
292864
+ } else {
292865
+ carriers.push(paragraph2);
292866
+ }
292867
+ }
292868
+ return { byEntryIndex, carriers };
292869
+ }
292870
+ function buildTocSectionOwnerParagraphOpen(template, owner) {
292871
+ const openEnd = findXmlTagEnd4(template, 1);
292872
+ const properties = inheritRunNamespaceDeclarations(template.slice(openEnd) || "<w:pPr></w:pPr>", template, openEnd, template.slice(0, openEnd));
292873
+ const ownerProperties = findDirectChild(owner, "pPr").xml;
292874
+ const retainedProperties = inheritRunNamespaceDeclarations(ownerProperties, owner, owner.indexOf(ownerProperties), readParagraphOpenTag(owner));
292875
+ return readParagraphOpenTag(owner) + preserveTocOwnerProperties(properties, retainedProperties);
292876
+ }
292877
+ function preserveTocContinuationSectionOpen(template, index, sectionOwners, usedParaIds) {
292878
+ const owner = sectionOwners.get(index);
292879
+ const open2 = removeTocSectionBoundaryFromTemplate(template);
292880
+ if (!owner)
292881
+ return open2 === template ? open2 : removeTocOwnerPropertiesFromTemplate(template);
292882
+ for (const id of collectParaIdsInXml(readParagraphOpenTag(owner)))
292883
+ usedParaIds.delete(id);
292884
+ return buildTocSectionOwnerParagraphOpen(open2, owner);
292885
+ }
292886
+ function buildTocSectionCarrierXml(owner) {
292887
+ return buildTocSectionOwnerParagraphOpen("<w:p><w:pPr></w:pPr>", owner) + "</w:p>";
292888
+ }
292581
292889
  function shouldUseV1EmptyTocSourceSet(instruction) {
292582
- return parseQuotedSwitch(instruction, "t") != null && parseNumericSwitchRange(instruction, "o") == null && !/\\u\b/i.test(instruction) && parseQuotedSwitch(instruction, "f") == null && parseNumericSwitchRange(instruction, "l") == null;
292890
+ return parseQuotedSwitch(instruction, "t") != null && parseNumericSwitchRange(instruction, "o") == null && !/\\u\b/i.test(instruction) && !parseTocTcSourceSelection(instruction).enabled;
292583
292891
  }
292584
292892
  function findLastSdtStart(xmlPrefix2) {
292585
292893
  let start = -1;
@@ -292873,6 +293181,104 @@ function resolveBookmarkSpanInParagraph(context, entry) {
292873
293181
  text: map3.visibleText().slice(startOffset, endOffset)
292874
293182
  };
292875
293183
  }
293184
+ function buildParagraphBookmarkMarkers(paragraph2, insertion, id) {
293185
+ const namespace = insertion.fieldSource || paragraph2.namespaceBindings?.w !== WORDPROCESSINGML_NAMESPACE5 ? ` xmlns:w="${WORDPROCESSINGML_NAMESPACE5}"` : "";
293186
+ return {
293187
+ startXml: `<w:bookmarkStart${namespace} w:id="${xmlEscapeAttr(String(id))}" w:name="${xmlEscapeAttr(insertion.name)}"${insertion.tableColumn ? ` w:colFirst="${insertion.tableColumn.colFirst}" w:colLast="${insertion.tableColumn.colLast}"` : ""}/>`,
293188
+ endXml: `<w:bookmarkEnd${namespace} w:id="${xmlEscapeAttr(String(id))}"/>`
293189
+ };
293190
+ }
293191
+ function readBookmarkInsertionNamespaceBindings(paragraph2, insertion) {
293192
+ if (!insertion.fieldSource)
293193
+ return new Map(Object.entries(paragraph2.namespaceBindings ?? {}));
293194
+ const relativeByte = insertion.fieldSource.byteStart - paragraph2.byteStart;
293195
+ const charStart = TD83.decode(encodeXml(paragraph2.rawXml).subarray(0, relativeByte)).length;
293196
+ const parsed = collectXmlElementRanges(paragraph2.rawXml, {
293197
+ fragment: true,
293198
+ additionalNamespaces: paragraph2.namespaceBindings
293199
+ });
293200
+ const parent = parsed.ranges.filter((range) => !range.tag.isSelfClosing && range.openEnd <= charStart && range.closeStart > charStart).sort((left, right) => right.start - left.start)[0];
293201
+ return parsed.errors.length || !parent ? null : new Map(Object.entries(parent.namespaceBindings));
293202
+ }
293203
+ function canPlaceBookmarkAtFieldSource(paragraph2, fieldSource) {
293204
+ return prepareBookmarkParagraphGroups([paragraph2], [{
293205
+ blockId: paragraph2.blockId,
293206
+ name: "_TocPlacement",
293207
+ fieldSource,
293208
+ startXml: `<w:bookmarkStart xmlns:w="${WORDPROCESSINGML_NAMESPACE5}" w:id="0" w:name="_TocPlacement"/>`,
293209
+ endXml: `<w:bookmarkEnd xmlns:w="${WORDPROCESSINGML_NAMESPACE5}" w:id="0"/>`
293210
+ }]) != null;
293211
+ }
293212
+ function prepareBookmarkParagraphGroups(paragraphs, insertions) {
293213
+ const paragraphsById = new Map;
293214
+ for (const paragraph2 of paragraphs) {
293215
+ paragraphsById.set(paragraph2.blockId, paragraphsById.has(paragraph2.blockId) ? null : paragraph2);
293216
+ }
293217
+ const groups = new Map;
293218
+ for (const insertion of insertions) {
293219
+ if (!paragraphsById.get(insertion.blockId))
293220
+ return null;
293221
+ const group = groups.get(insertion.blockId) ?? [];
293222
+ group.push(insertion);
293223
+ groups.set(insertion.blockId, group);
293224
+ }
293225
+ const result = [];
293226
+ for (const [blockId, group] of groups) {
293227
+ const paragraph2 = paragraphsById.get(blockId);
293228
+ const generic = group.filter((insertion) => !insertion.fieldSource);
293229
+ if (generic.length > 1)
293230
+ return null;
293231
+ const parsed = collectXmlElementRanges(paragraph2.rawXml, {
293232
+ fragment: true,
293233
+ additionalNamespaces: paragraph2.namespaceBindings
293234
+ });
293235
+ const root = parsed.ranges.find((range) => range.start === 0 && range.end === paragraph2.rawXml.length);
293236
+ if (parsed.errors.length || !root || root.tag.localName !== "p" || root.tag.namespaceUri !== WORDPROCESSINGML_NAMESPACE5)
293237
+ return null;
293238
+ const fields = group.filter((insertion) => insertion.fieldSource).sort((left, right) => right.fieldSource.byteStart - left.fieldSource.byteStart);
293239
+ const original = encodeXml(paragraph2.rawXml);
293240
+ let next = original;
293241
+ let previousStart = paragraph2.byteEnd;
293242
+ const keys = new Set;
293243
+ for (const insertion of fields) {
293244
+ const source = insertion.fieldSource;
293245
+ if (keys.has(source.key) || !Number.isInteger(source.byteStart) || !Number.isInteger(source.byteEnd) || source.byteStart < paragraph2.byteStart || source.byteEnd > previousStart || source.byteEnd <= source.byteStart)
293246
+ return null;
293247
+ keys.add(source.key);
293248
+ const start = source.byteStart - paragraph2.byteStart;
293249
+ const end = source.byteEnd - paragraph2.byteStart;
293250
+ const startChar = TD83.decode(original.subarray(0, start)).length;
293251
+ const endChar = TD83.decode(original.subarray(0, end)).length;
293252
+ if (encodeXml(paragraph2.rawXml.slice(0, startChar)).length !== start || encodeXml(paragraph2.rawXml.slice(0, endChar)).length !== end)
293253
+ return null;
293254
+ const first = parsed.ranges.find((range) => range.start === startChar && range.tag.namespaceUri === WORDPROCESSINGML_NAMESPACE5 && (range.tag.localName === "r" || range.tag.localName === "fldSimple"));
293255
+ const last = parsed.ranges.find((range) => range.end === endChar && range.tag.namespaceUri === WORDPROCESSINGML_NAMESPACE5 && range.tag.localName === first?.tag.localName);
293256
+ const parent = (range) => parsed.ranges.filter((candidate2) => candidate2.start < range.start && candidate2.end > range.end).sort((a, b) => b.start - a.start)[0];
293257
+ if (!first || !last || first.start < root.openEnd || last.end > root.closeStart || parent(first)?.start !== parent(last)?.start || first.tag.localName === "fldSimple" && first !== last)
293258
+ return null;
293259
+ if (first.tag.localName === "r") {
293260
+ const hasMarker = (run, kind) => parsed.ranges.some((range) => range.start >= run.start && range.end <= run.end && range.tag.namespaceUri === WORDPROCESSINGML_NAMESPACE5 && range.tag.localName === "fldChar" && range.tag.attributes.some((attribute) => attribute.namespaceUri === WORDPROCESSINGML_NAMESPACE5 && attribute.localName === "fldCharType" && attribute.value === kind));
293261
+ if (!hasMarker(first, "begin") || !hasMarker(last, "end"))
293262
+ return null;
293263
+ }
293264
+ next = spliceBytes3(next, end, end, encodeXml(insertion.endXml));
293265
+ next = spliceBytes3(next, start, start, encodeXml(insertion.startXml));
293266
+ previousStart = source.byteStart;
293267
+ }
293268
+ let xml = TD83.decode(next);
293269
+ if (generic[0]) {
293270
+ const withStart = injectParagraphPrefix(xml, generic[0].startXml);
293271
+ const withEnd = withStart && injectParagraphSuffix(withStart, generic[0].endXml);
293272
+ if (!withEnd)
293273
+ return null;
293274
+ xml = withEnd;
293275
+ }
293276
+ if (collectXmlElementRanges(xml, { fragment: true, additionalNamespaces: paragraph2.namespaceBindings }).errors.length)
293277
+ return null;
293278
+ result.push({ paragraph: paragraph2, xml });
293279
+ }
293280
+ return result;
293281
+ }
292876
293282
  function insertBookmarksIntoParagraphs(context, insertions, txIdPrefix) {
292877
293283
  if (insertions.length === 0) {
292878
293284
  return {
@@ -292881,59 +293287,46 @@ function insertBookmarksIntoParagraphs(context, insertions, txIdPrefix) {
292881
293287
  message: "At least one bookmark insertion is required."
292882
293288
  };
292883
293289
  }
292884
- const paragraphsByBlockId = new Map;
292885
- for (const paragraph2 of readBodyParagraphs(context)) {
292886
- paragraphsByBlockId.set(paragraph2.blockId, paragraphsByBlockId.has(paragraph2.blockId) ? null : paragraph2);
293290
+ const paragraphs = readBodyParagraphs(context);
293291
+ const paragraphGroups = new Map;
293292
+ for (const paragraph2 of paragraphs) {
293293
+ const group = paragraphGroups.get(paragraph2.blockId) ?? [];
293294
+ group.push(paragraph2);
293295
+ paragraphGroups.set(paragraph2.blockId, group);
292887
293296
  }
292888
293297
  const existingNames = new Set(readBookmarkEntries(context).map((entry) => entry.name));
292889
- const requestedBlockIds = new Set;
292890
293298
  const requestedNames = new Set;
292891
- const replacementsByPart = new Map;
292892
- const storyIds = new Set;
292893
293299
  const bookmarkIds = [];
292894
293300
  let nextBookmarkId = nextBookmarkNumericId(context);
293301
+ const markers = [];
292895
293302
  for (const insertion of insertions) {
292896
- if (requestedBlockIds.has(insertion.blockId)) {
292897
- return {
292898
- ok: false,
292899
- code: "INVALID_TARGET",
292900
- message: `Paragraph "${insertion.blockId}" was requested more than once.`
292901
- };
292902
- }
292903
293303
  if (existingNames.has(insertion.name) || requestedNames.has(insertion.name)) {
292904
- return {
292905
- ok: false,
292906
- code: "INVALID_TARGET",
292907
- message: `Bookmark name "${insertion.name}" already exists.`
292908
- };
293304
+ return { ok: false, code: "INVALID_TARGET", message: `Bookmark name "${insertion.name}" already exists.` };
292909
293305
  }
292910
- const paragraph2 = paragraphsByBlockId.get(insertion.blockId);
292911
- if (!paragraph2) {
293306
+ const targets = paragraphGroups.get(insertion.blockId);
293307
+ if (targets?.length !== 1)
292912
293308
  return {
292913
293309
  ok: false,
292914
293310
  code: "TARGET_NOT_FOUND",
292915
293311
  message: `Paragraph "${insertion.blockId}" was not found or is ambiguous.`
292916
293312
  };
292917
- }
292918
293313
  const bookmarkId = String(nextBookmarkId++);
292919
- const startFragment = `<w:bookmarkStart w:id="${xmlEscapeAttr(bookmarkId)}" w:name="${xmlEscapeAttr(insertion.name)}"${insertion.tableColumn ? ` w:colFirst="${insertion.tableColumn.colFirst}" w:colLast="${insertion.tableColumn.colLast}"` : ""}/>`;
292920
- const endFragment = `<w:bookmarkEnd w:id="${xmlEscapeAttr(bookmarkId)}"/>`;
292921
- const withStart = injectParagraphPrefix(paragraph2.rawXml, startFragment);
292922
- const withEnd = withStart ? injectParagraphSuffix(withStart, endFragment) : null;
292923
- if (!withEnd) {
292924
- return {
292925
- ok: false,
292926
- code: "INTERNAL_ERROR",
292927
- message: `Unable to inject bookmark markup into paragraph "${insertion.blockId}".`
292928
- };
292929
- }
293314
+ markers.push({ ...insertion, ...buildParagraphBookmarkMarkers(targets[0], insertion, bookmarkId) });
293315
+ bookmarkIds.push(bookmarkId);
293316
+ requestedNames.add(insertion.name);
293317
+ }
293318
+ const prepared = prepareBookmarkParagraphGroups(paragraphs, markers);
293319
+ if (!prepared)
293320
+ return { ok: false, code: "INVALID_TARGET", message: "Bookmark targets have unavailable or unsupported paragraph or field boundaries." };
293321
+ const replacementsByPart = new Map;
293322
+ const storyIds = new Set;
293323
+ const requestedBlockIds = new Set;
293324
+ for (const { paragraph: paragraph2, xml } of prepared) {
292930
293325
  const replacements = replacementsByPart.get(paragraph2.partUri) ?? [];
292931
- replacements.push({ paragraph: paragraph2, bytes: encodeXml(withEnd) });
293326
+ replacements.push({ paragraph: paragraph2, bytes: encodeXml(xml) });
292932
293327
  replacementsByPart.set(paragraph2.partUri, replacements);
292933
293328
  storyIds.add(paragraph2.storyId);
292934
- bookmarkIds.push(bookmarkId);
292935
- requestedBlockIds.add(insertion.blockId);
292936
- requestedNames.add(insertion.name);
293329
+ requestedBlockIds.add(paragraph2.blockId);
292937
293330
  }
292938
293331
  const perPart = {};
292939
293332
  for (const [partUri, replacements] of replacementsByPart) {
@@ -293390,6 +293783,34 @@ function parseQuotedSwitch(instruction, flag) {
293390
293783
  const re = new RegExp(`\\\\${escapeRegExp15(flag)}\\s+"([^"]*)"`);
293391
293784
  return re.exec(instruction)?.[1];
293392
293785
  }
293786
+ function parseTocFieldIdentifier(instruction) {
293787
+ return parseTocTcSourceSelection(instruction).identifier;
293788
+ }
293789
+ function parseTocTcSourceSelection(instruction) {
293790
+ const tokens = instruction.match(/"[^"]*"|[^\s"]+/g) ?? [];
293791
+ const fieldIndex = tokens.findIndex((token) => token.toLowerCase() === "\\f");
293792
+ const levelIndex = tokens.findIndex((token) => token.toLowerCase() === "\\l");
293793
+ const argument = (index) => {
293794
+ const value2 = index < 0 ? undefined : tokens[index + 1];
293795
+ if (value2 == null || value2.startsWith("\\"))
293796
+ return;
293797
+ return value2.startsWith('"') ? value2.slice(1, -1) : value2;
293798
+ };
293799
+ const identifier = argument(fieldIndex);
293800
+ const levelArgument = argument(levelIndex);
293801
+ const range = /^(\d+)-(\d+)$/.exec(levelArgument ?? "");
293802
+ return {
293803
+ enabled: fieldIndex >= 0 || levelIndex >= 0,
293804
+ hasFieldSwitch: fieldIndex >= 0,
293805
+ hasLevelSwitch: levelIndex >= 0,
293806
+ ...identifier != null ? { identifier } : {},
293807
+ ...levelArgument != null ? { levelArgument } : {},
293808
+ ...range ? { levels: { from: Number(range[1]), to: Number(range[2]) } } : {}
293809
+ };
293810
+ }
293811
+ function matchesTocTcSourceSelection(selection, entry) {
293812
+ return selection.enabled && entry.text.length > 0 && (selection.identifier == null || (entry.tableIdentifier ?? "C") === selection.identifier) && (selection.levels == null || entry.level >= selection.levels.from && entry.level <= selection.levels.to);
293813
+ }
293393
293814
  function parseNumericSwitchRange(instruction, flag) {
293394
293815
  const re = new RegExp(`\\\\${escapeRegExp15(flag)}\\s+"?(\\d+)-(\\d+)"?`);
293395
293816
  const match = re.exec(instruction);
@@ -293771,16 +294192,26 @@ function buildTocResultRunsXml(instruction, entries) {
293771
294192
  return chunks.join("");
293772
294193
  }).join("");
293773
294194
  }
293774
- function buildTocResultXmlPreservingParagraphs(context, instruction, entries, currentField) {
293775
- if (entries.length === 0)
293776
- return buildTextRunXml("");
294195
+ function buildTocResultXmlPreservingParagraphs(context, instruction, sourceEntries, currentField, emptyText = "") {
293777
294196
  const sourceParagraphs = readCurrentTocParagraphXmls(context, currentField, true);
293778
- const paragraphTemplates = buildTocParagraphTemplatesFromParagraphXml(sourceParagraphs.join(""));
294197
+ const sectionPlacement = readTocContinuationSectionPlacement(sourceParagraphs, sourceEntries.length);
294198
+ const sectionOwners = sectionPlacement.byEntryIndex;
294199
+ if (sourceEntries.length === 0) {
294200
+ const carriers = sectionPlacement.carriers.map(buildTocSectionCarrierXml);
294201
+ return { xml: buildTextRunXml(emptyText) + (carriers.length ? `</w:p>${carriers.join("").slice(0, -6)}` : "") };
294202
+ }
294203
+ const paragraphTemplates = buildTocParagraphTemplatesFromParagraphXml([
294204
+ removeTocOwnerPropertiesFromTemplate(sourceParagraphs[0] ?? ""),
294205
+ ...sourceParagraphs.slice(1)
294206
+ ].join(""));
293779
294207
  const entryRunPropertiesTemplates = readTocEntryRunPropertiesTemplates(context, currentField);
293780
- const entryRunProperties = resolveTocEntryRunProperties(entries, entryRunPropertiesTemplates);
294208
+ const entryRunProperties = resolveTocEntryRunProperties(sourceEntries, entryRunPropertiesTemplates);
294209
+ const entryParagraphOpens = resolveTocEntryParagraphOpens(sourceEntries, entryRunProperties, entryRunPropertiesTemplates, sourceParagraphs[0]);
294210
+ const entries = sourceEntries.map((entry, index) => applyCachedTcEntrySeparator(entry, entryRunProperties[index]));
294211
+ const withPageTab = createTocPageTabFallback(context, instruction, currentField.descriptor.byteStart);
293781
294212
  const documentParaIds = collectDocumentParaIds(context);
293782
294213
  const reusableParaIds = collectParaIdsInXml(sourceParagraphs.slice(1).join(""));
293783
- for (const id of collectParaIdsInXml(sourceParagraphs[0] ?? ""))
294214
+ for (const id of collectParaIdsInXml((sourceParagraphs[0] ?? "") + [...sectionOwners.values(), ...sectionPlacement.carriers].join("")))
293784
294215
  reusableParaIds.delete(id);
293785
294216
  const usedParaIds = new Set(documentParaIds);
293786
294217
  const nextParaId = createUniqueParaIdAllocator(documentParaIds);
@@ -293797,31 +294228,47 @@ function buildTocResultXmlPreservingParagraphs(context, instruction, entries, cu
293797
294228
  }
293798
294229
  let xml = buildTocEntryRunsXml(instruction, entries[0], entryRunProperties[0]);
293799
294230
  for (const [index, entry] of entries.slice(1).entries()) {
293800
- const retained = remainingTemplates.get(`${normalizeTocLevel(entry.level)}:${normalizeTocEntryText(entry.text)}`)?.pop();
294231
+ const retained = entryParagraphOpens[index + 1] ?? remainingTemplates.get(`${normalizeTocLevel(entry.level)}:${normalizeTocEntryText(entry.cachedParagraphText ?? entry.text)}`)?.pop();
293801
294232
  if (retained) {
293802
294233
  for (const id of collectParaIdsInXml(retained)) {
293803
294234
  if (reusableParaIds.delete(id))
293804
294235
  usedParaIds.delete(id);
293805
294236
  }
293806
294237
  }
293807
- xml += `</w:p>${dedupeParagraphOpenParaId(retained ?? buildTocContinuationParagraphOpen(entry, paragraphTemplates), usedParaIds, nextParaId)}` + buildTocEntryRunsXml(instruction, entry, entryRunProperties[index + 1]);
294238
+ xml += `</w:p>${dedupeParagraphOpenParaId(preserveTocContinuationSectionOpen(withPageTab(retained ?? buildTocContinuationParagraphOpen(entry, paragraphTemplates), entry), index + 1, sectionOwners, usedParaIds), usedParaIds, nextParaId)}` + buildTocEntryRunsXml(instruction, entry, entryRunProperties[index + 1]);
293808
294239
  }
293809
- return xml;
294240
+ for (const owner of sectionPlacement.carriers) {
294241
+ xml += `</w:p>${buildTocSectionCarrierXml(owner).slice(0, -6)}`;
294242
+ }
294243
+ const firstParagraphOpen = removeTocSectionBoundaryFromTemplate(withPageTab(entryParagraphOpens[0] ?? buildTocContinuationParagraphOpen(entries[0], paragraphTemplates), entries[0]));
294244
+ const firstParagraphOpenEnd = findXmlTagEnd4(firstParagraphOpen, 1);
294245
+ return {
294246
+ xml,
294247
+ firstParagraphProperties: inheritRunNamespaceDeclarations(firstParagraphOpen.slice(firstParagraphOpenEnd), firstParagraphOpen, firstParagraphOpenEnd, firstParagraphOpen.slice(0, firstParagraphOpenEnd))
294248
+ };
293810
294249
  }
293811
- function buildNewTocFieldContentXml(context, instruction, seedParagraph, currentField, preservedTocPages, reservedParaIds, tocBookmarkNames) {
294250
+ function buildNewTocFieldContentXml(context, instruction, seedParagraph, currentField, preservedTocPages, reservedParaIds, tocBookmarkNames, insertionByteStart) {
293812
294251
  const useEmptyPlaceholder = shouldUseV1EmptyTocSourceSet(instruction);
293813
294252
  const paragraphs = readBodyParagraphs(context, { includeListState: false });
293814
- const entries = useEmptyPlaceholder ? [] : buildTocEntries(context, instruction, currentField, preservedTocPages, tocBookmarkNames, paragraphs);
293815
- const paragraphTemplates = readDocumentTocParagraphTemplates(paragraphs);
294253
+ const sourceEntries = useEmptyPlaceholder ? [] : buildTocEntries(context, instruction, currentField, preservedTocPages, tocBookmarkNames, paragraphs);
294254
+ const paragraphTemplates = readDocumentTocParagraphTemplates(paragraphs, currentField?.blockId);
293816
294255
  const entryRunPropertiesTemplates = readTocEntryRunPropertiesTemplates(context, currentField);
293817
- const entryRunProperties = resolveTocEntryRunProperties(entries, entryRunPropertiesTemplates);
294256
+ const entryRunProperties = resolveTocEntryRunProperties(sourceEntries, entryRunPropertiesTemplates);
294257
+ const entryParagraphOpens = resolveTocEntryParagraphOpens(sourceEntries, entryRunProperties, entryRunPropertiesTemplates, seedParagraph?.rawXml);
294258
+ const entries = sourceEntries.map((entry, index) => applyCachedTcEntrySeparator(entry, entryRunProperties[index]));
294259
+ const withPageTab = createTocPageTabFallback(context, instruction, currentField?.descriptor.byteStart ?? insertionByteStart ?? seedParagraph?.byteStart ?? 0);
294260
+ const sectionPlacement = readTocContinuationSectionPlacement(currentField ? readCurrentTocParagraphXmls(context, currentField, true) : [], entries.length);
294261
+ const sectionOwners = sectionPlacement.byEntryIndex;
294262
+ const carriers = sectionPlacement.carriers.map(buildTocSectionCarrierXml);
293818
294263
  if (entries.length === 0) {
293819
- return buildGeneratedTocParagraphOpen(1, seedParagraph, paragraphTemplates) + '<w:r><w:fldChar w:fldCharType="begin" /></w:r>' + buildInstructionRunXml(instruction) + '<w:r><w:fldChar w:fldCharType="separate" /></w:r>' + buildTextRunXml(useEmptyPlaceholder ? "No table of contents entries found." : "") + '<w:r><w:fldChar w:fldCharType="end" /></w:r>' + "</w:p>";
294264
+ return buildGeneratedTocParagraphOpen(1, seedParagraph, paragraphTemplates, undefined, currentField != null) + '<w:r><w:fldChar w:fldCharType="begin" /></w:r>' + buildInstructionRunXml(instruction) + '<w:r><w:fldChar w:fldCharType="separate" /></w:r>' + buildTextRunXml(useEmptyPlaceholder ? "No table of contents entries found." : "") + (carriers.length ? `</w:p>${carriers.join("").slice(0, -6)}` : "") + '<w:r><w:fldChar w:fldCharType="end" /></w:r>' + "</w:p>";
293820
294265
  }
293821
294266
  const documentParaIds = collectDocumentParaIds(context);
293822
294267
  const usedParaIds = new Set(reservedParaIds ?? []);
294268
+ for (const id of collectParaIdsInXml([...sectionOwners.values(), ...sectionPlacement.carriers].join("")))
294269
+ usedParaIds.add(id);
293823
294270
  const nextParaId = createUniqueParaIdAllocator(documentParaIds);
293824
- return entries.map((entry, index) => `${dedupeParagraphOpenParaId(index === 0 ? buildGeneratedTocParagraphOpen(entry.level, seedParagraph, paragraphTemplates, entry.text) : buildTocContinuationParagraphOpen(entry, paragraphTemplates), usedParaIds, nextParaId)}` + (index === 0 ? '<w:r><w:fldChar w:fldCharType="begin" /></w:r>' + buildInstructionRunXml(instruction) + '<w:r><w:fldChar w:fldCharType="separate" /></w:r>' : "") + buildTocEntryRunsXml(instruction, entry, entryRunProperties[index]) + (index === entries.length - 1 ? '<w:r><w:fldChar w:fldCharType="end" /></w:r>' : "") + "</w:p>").join("");
294271
+ return entries.map((entry, index) => `${dedupeParagraphOpenParaId(withPageTab(index === 0 ? buildGeneratedTocParagraphOpen(entry.level, seedParagraph, paragraphTemplates, entry.cachedParagraphText ?? entry.text, currentField != null, entryParagraphOpens[index]) : currentField ? preserveTocContinuationSectionOpen(entryParagraphOpens[index] ?? buildTocContinuationParagraphOpen(entry, paragraphTemplates), index, sectionOwners, usedParaIds) : entryParagraphOpens[index] ?? buildTocContinuationParagraphOpen(entry, paragraphTemplates), entry), usedParaIds, nextParaId)}` + (index === 0 ? '<w:r><w:fldChar w:fldCharType="begin" /></w:r>' + buildInstructionRunXml(instruction) + '<w:r><w:fldChar w:fldCharType="separate" /></w:r>' : "") + buildTocEntryRunsXml(instruction, entry, entryRunProperties[index]) + (index === entries.length - 1 ? (carriers.length ? `</w:p>${carriers.join("").slice(0, -6)}` : "") + '<w:r><w:fldChar w:fldCharType="end" /></w:r>' : "") + "</w:p>").join("");
293825
294272
  }
293826
294273
  function collectDocumentParaIds(context) {
293827
294274
  const existing = new Set;
@@ -293889,7 +294336,8 @@ function buildTocEntryRunsXml(instruction, entry, entryRunProperties) {
293889
294336
  function buildTocEntries(context, instruction, currentField, preservedTocPages, tocBookmarkNames, paragraphs = readBodyParagraphs(context, { includeListState: false })) {
293890
294337
  const pages = estimateDocumentPages(context);
293891
294338
  const numberingMarkers = buildBodyParagraphNumberReferenceMap(context, paragraphs);
293892
- const tocBookmarks = buildBodyTocBookmarkMap(context);
294339
+ const bodyBookmarks = readBookmarkEntries(context);
294340
+ const tocBookmarks = buildBodyTocBookmarkMap(bodyBookmarks);
293893
294341
  if (tocBookmarkNames)
293894
294342
  for (const [key2, name] of tocBookmarkNames)
293895
294343
  tocBookmarks.set(key2, name);
@@ -293911,6 +294359,7 @@ function buildTocEntries(context, instruction, currentField, preservedTocPages,
293911
294359
  const bookmarkKey = bookmarkName ? normalizeTocBookmarkKey(bookmarkName) : undefined;
293912
294360
  const preservedPage = (bookmarkKey ? preservedPagesByBookmark.get(bookmarkKey) : undefined) ?? readPreservedTocPageByText(preservedPages, text);
293913
294361
  return {
294362
+ sourceByteStart: paragraph2.byteStart,
293914
294363
  text,
293915
294364
  page: preservedPage ?? String(pages.displayPageByBlockId.get(paragraph2.blockId) ?? 1),
293916
294365
  level: derivedLevel,
@@ -293922,17 +294371,30 @@ function buildTocEntries(context, instruction, currentField, preservedTocPages,
293922
294371
  ...bookmarkName ? { bookmarkName } : {}
293923
294372
  };
293924
294373
  }).filter((entry) => entry != null).filter((entry) => entry.text.length > 0);
293925
- const tcIdentifier = parseQuotedSwitch(instruction, "f");
293926
- const tcLevels = parseNumericSwitchRange(instruction, "l");
293927
- const tcEntries = listCanonicalFieldEntries(context).filter((entry) => instructionKeyword(entry.descriptor.instructionText) === "TC").map((entry) => ({ entry, parsed: parseTocEntryInstruction(entry.descriptor.instructionText) })).filter(({ parsed }) => (tcIdentifier == null || parsed.tableIdentifier === tcIdentifier) && (tcLevels == null || parsed.level >= tcLevels.from && parsed.level <= tcLevels.to)).map(({ entry, parsed }) => {
293928
- const preservedPage = readPreservedTocPageByText(preservedPages, parsed.text);
294374
+ const tcSelection = parseTocTcSourceSelection(instruction);
294375
+ const bodyParagraphs = new Map(paragraphs.map((paragraph2) => [`${paragraph2.storyId}:${paragraph2.blockId}`, paragraph2]));
294376
+ const tcFields = listCanonicalFieldEntries(context).filter((entry) => instructionKeyword(entry.descriptor.instructionText) === "TC").filter((entry) => bodyParagraphs.has(`${entry.storyId}:${entry.blockId}`));
294377
+ const tcBookmarkNames = resolveTocTcBookmarkNames(bodyBookmarks, paragraphs, tcFields);
294378
+ const tcEntries = tcFields.map((entry) => ({ entry, parsed: parseTocEntryInstruction(entry.descriptor.instructionText) })).filter(({ parsed }) => matchesTocTcSourceSelection(tcSelection, parsed)).map(({ entry, parsed }) => {
294379
+ const text = parsed.text;
294380
+ const separatorIndex = text.indexOf("\t");
294381
+ const marker = separatorIndex > 0 ? text.slice(0, separatorIndex) : undefined;
294382
+ const title = separatorIndex > 0 ? text.slice(separatorIndex + 1) : undefined;
294383
+ const fieldKey = tocTcFieldSourceKey(entry);
294384
+ const bookmarkName = tocBookmarkNames?.get(fieldKey) ?? tcBookmarkNames.get(fieldKey);
294385
+ const bookmarkKey = bookmarkName ? normalizeTocBookmarkKey(bookmarkName) : undefined;
294386
+ const preservedPage = (bookmarkKey ? preservedPagesByBookmark.get(bookmarkKey) : undefined) ?? readPreservedTocPageByText(preservedPages, text);
293929
294387
  return {
293930
- text: parsed.text,
294388
+ sourceByteStart: entry.descriptor.byteStart,
294389
+ text,
293931
294390
  page: preservedPage ?? String(pages.displayPageByBlockId.get(entry.blockId) ?? 1),
293932
- level: parsed.level
294391
+ level: parsed.level,
294392
+ isTcEntry: true,
294393
+ ...marker && title ? { marker, title, markerSeparator: "tab" } : {},
294394
+ ...bookmarkName ? { bookmarkName } : {}
293933
294395
  };
293934
- }).filter((entry) => entry.text.length > 0);
293935
- return [...headings, ...tcEntries];
294396
+ });
294397
+ return [...headings, ...tcEntries].sort((left, right) => left.sourceByteStart - right.sourceByteStart).map(({ sourceByteStart: _sourceByteStart, ...entry }) => entry);
293936
294398
  }
293937
294399
  function parseTocCustomStyles(instruction) {
293938
294400
  const raw = parseQuotedSwitch(instruction, "t");
@@ -293952,18 +294414,19 @@ function parseTocCustomStyles(instruction) {
293952
294414
  function normalizeStyleId(value2) {
293953
294415
  return value2.replace(/\s+/g, "").trim().toLowerCase();
293954
294416
  }
293955
- function readDocumentTocParagraphTemplates(paragraphs) {
294417
+ function readDocumentTocParagraphTemplates(paragraphs, ownerBlockId) {
293956
294418
  const templates = emptyTocParagraphTemplates();
293957
294419
  for (const paragraph2 of paragraphs) {
293958
294420
  const level = readTocParagraphLevel(paragraph2.rawXml);
293959
294421
  if (level == null)
293960
294422
  continue;
293961
- const open2 = buildTocParagraphTemplateOpen(paragraph2.rawXml);
294423
+ const open2 = buildTocParagraphTemplateOpen(paragraph2.blockId === ownerBlockId ? removeTocOwnerPropertiesFromTemplate(paragraph2.rawXml) : paragraph2.rawXml);
293962
294424
  if (!templates.byLevel.has(level))
293963
294425
  templates.byLevel.set(level, open2);
293964
294426
  const entryText = readTocParagraphTemplateText(paragraph2.rawXml);
293965
- if (entryText && !templates.byText.has(entryText))
293966
- templates.byText.set(entryText, open2);
294427
+ const key2 = `${level}:${entryText}`;
294428
+ if (entryText && !templates.byLevelAndText.has(key2))
294429
+ templates.byLevelAndText.set(key2, open2);
293967
294430
  }
293968
294431
  return templates;
293969
294432
  }
@@ -293971,7 +294434,8 @@ function readTocEntryRunPropertiesTemplates(context, currentField) {
293971
294434
  const templates = {
293972
294435
  byBookmark: new Map,
293973
294436
  byText: new Map,
293974
- byLevel: new Map
294437
+ byLevel: new Map,
294438
+ paragraphByRunTemplate: new Map
293975
294439
  };
293976
294440
  if (!currentField)
293977
294441
  return templates;
@@ -293986,12 +294450,18 @@ function readTocEntryRunPropertiesTemplates(context, currentField) {
293986
294450
  const { runProperties } = visibleEntry;
293987
294451
  if (runProperties.length === 0)
293988
294452
  continue;
294453
+ templates.paragraphByRunTemplate.set(runProperties, {
294454
+ level,
294455
+ open: buildTocParagraphTemplateOpen(paragraphXml)
294456
+ });
293989
294457
  const hyperlinkXml = findFirstElement(paragraphXml, "hyperlink")?.xml ?? "";
293990
294458
  const hyperlinkBookmark = readXmlAttributeByLocalName(hyperlinkXml, "anchor");
293991
294459
  const bookmark = hyperlinkBookmark ? decodeXmlEntities2(hyperlinkBookmark) : readTocPageReferenceBookmarkName(paragraphXml);
293992
294460
  const bookmarkKey = bookmark ? normalizeTocBookmarkKey(bookmark) : "";
293993
- if (bookmarkKey && !templates.byBookmark.has(bookmarkKey)) {
293994
- templates.byBookmark.set(bookmarkKey, runProperties);
294461
+ if (bookmarkKey) {
294462
+ const byBookmark = templates.byBookmark.get(bookmarkKey) ?? [];
294463
+ byBookmark.push(runProperties);
294464
+ templates.byBookmark.set(bookmarkKey, byBookmark);
293995
294465
  }
293996
294466
  const entryText = readTocParagraphTemplateText(visibleEntry);
293997
294467
  if (entryText) {
@@ -294255,24 +294725,54 @@ function hasEnabledWebHidden(xml) {
294255
294725
  }
294256
294726
  function resolveTocEntryRunProperties(entries, templates) {
294257
294727
  const usedTemplates = new Set;
294728
+ const bookmarkEntryCounts = new Map;
294729
+ for (const entry of entries) {
294730
+ if (!entry.bookmarkName)
294731
+ continue;
294732
+ const key2 = normalizeTocBookmarkKey(entry.bookmarkName);
294733
+ bookmarkEntryCounts.set(key2, (bookmarkEntryCounts.get(key2) ?? 0) + 1);
294734
+ }
294258
294735
  const byTextQueues = new Map([...templates.byText].map(([text, matches]) => [text, [...matches]]));
294259
- const takeByText = (text) => {
294736
+ const takeByText = (text, accept) => {
294260
294737
  const queue = byTextQueues.get(text);
294261
- while (queue?.length) {
294262
- const candidate2 = queue.shift();
294263
- if (candidate2 && !usedTemplates.has(candidate2))
294264
- return candidate2;
294265
- }
294266
- return;
294738
+ const index = queue?.findIndex((candidate2) => !usedTemplates.has(candidate2) && (!accept || accept(candidate2))) ?? -1;
294739
+ return index >= 0 ? queue?.splice(index, 1)[0] : undefined;
294267
294740
  };
294268
294741
  const resolved = entries.map((entry) => {
294269
294742
  const bookmarkKey = entry.bookmarkName ? normalizeTocBookmarkKey(entry.bookmarkName) : "";
294270
- const byBookmark = bookmarkKey ? templates.byBookmark.get(bookmarkKey) : undefined;
294271
- const byText = byBookmark ? undefined : takeByText(normalizeTocEntryText(entry.text));
294272
- const match = byBookmark ?? byText;
294273
- if (match)
294274
- usedTemplates.add(match);
294275
- return match;
294743
+ const bookmarkTemplates = bookmarkKey ? templates.byBookmark.get(bookmarkKey) : undefined;
294744
+ const byBookmark = bookmarkEntryCounts.get(bookmarkKey) === 1 && bookmarkTemplates?.length === 1 ? bookmarkTemplates[0] : undefined;
294745
+ if (byBookmark)
294746
+ usedTemplates.add(byBookmark);
294747
+ return byBookmark;
294748
+ });
294749
+ entries.forEach((entry, index) => {
294750
+ if (resolved[index] || !entry.isTcEntry)
294751
+ return;
294752
+ const levelTemplates = templates.byLevel.get(normalizeTocLevel(entry.level));
294753
+ const byText = takeByText(normalizeTocEntryText(entry.text), (template) => levelTemplates?.includes(template) === true && !template.some((run) => run.separator === "tab"));
294754
+ if (!byText)
294755
+ return;
294756
+ resolved[index] = byText;
294757
+ usedTemplates.add(byText);
294758
+ });
294759
+ entries.forEach((entry, index) => {
294760
+ if (resolved[index] || !entry.isTcEntry)
294761
+ return;
294762
+ const cachedSeparatorTemplate = templates.byLevel.get(normalizeTocLevel(entry.level))?.find((template) => !usedTemplates.has(template) && applyCachedTcEntrySeparator(entry, template) !== entry);
294763
+ if (!cachedSeparatorTemplate)
294764
+ return;
294765
+ resolved[index] = cachedSeparatorTemplate;
294766
+ usedTemplates.add(cachedSeparatorTemplate);
294767
+ });
294768
+ entries.forEach((entry, index) => {
294769
+ if (resolved[index])
294770
+ return;
294771
+ const byText = takeByText(normalizeTocEntryText(entry.text));
294772
+ if (!byText)
294773
+ return;
294774
+ resolved[index] = byText;
294775
+ usedTemplates.add(byText);
294276
294776
  });
294277
294777
  for (const level of new Set(entries.map((entry) => normalizeTocLevel(entry.level)))) {
294278
294778
  const entryIndexes = entries.map((entry, index) => normalizeTocLevel(entry.level) === level ? index : -1).filter((index) => index >= 0);
@@ -294308,6 +294808,49 @@ function resolveTocEntryRunProperties(entries, templates) {
294308
294808
  }
294309
294809
  return resolved;
294310
294810
  }
294811
+ function resolveTocEntryParagraphOpens(entries, runTemplates, templates, ownerParagraphXml) {
294812
+ const ownerOpen = ownerParagraphXml ? buildTocParagraphTemplateOpen(ownerParagraphXml) : undefined;
294813
+ return entries.map((entry, index) => {
294814
+ const runs = runTemplates[index];
294815
+ const paired = runs && templates.paragraphByRunTemplate.get(runs);
294816
+ if (!paired || paired.level !== normalizeTocLevel(entry.level))
294817
+ return;
294818
+ return paired.open === ownerOpen ? removeTocOwnerPropertiesFromTemplate(paired.open) : paired.open;
294819
+ });
294820
+ }
294821
+ function applyCachedTcEntrySeparator(entry, template) {
294822
+ if (!entry.isTcEntry || !template || entry.text.includes("\t"))
294823
+ return entry;
294824
+ const separatorIndex = template.findIndex((run) => run.separator === "tab");
294825
+ if (separatorIndex <= 0 || template.slice(separatorIndex + 1).some((run) => run.separator === "tab"))
294826
+ return entry;
294827
+ const cachedLabel = template.map((run) => run.separator === "tab" ? "\t" : run.text).join("");
294828
+ const compactLabel = normalizeCompactTocEntryText(cachedLabel).replace(/\.$/, "");
294829
+ if (compactLabel !== normalizeCompactTocEntryText(entry.text).replace(/\.$/, ""))
294830
+ return entry;
294831
+ const marker = normalizeTocEntryText(template.slice(0, separatorIndex).map((run) => run.text).join(""));
294832
+ const compactMarker = normalizeCompactTocEntryText(marker);
294833
+ if (!compactMarker || !normalizeCompactTocEntryText(entry.text).startsWith(compactMarker))
294834
+ return entry;
294835
+ let markerEnd = 0;
294836
+ let remainingMarkerLength = compactMarker.length;
294837
+ while (markerEnd < entry.text.length && remainingMarkerLength > 0) {
294838
+ if (!/\s/.test(entry.text[markerEnd]))
294839
+ remainingMarkerLength -= 1;
294840
+ markerEnd += 1;
294841
+ }
294842
+ const title = entry.text.slice(markerEnd).trim();
294843
+ if (!title)
294844
+ return entry;
294845
+ return {
294846
+ ...entry,
294847
+ text: joinMarkerAndText(marker, title),
294848
+ marker,
294849
+ title,
294850
+ markerSeparator: "tab",
294851
+ cachedParagraphText: cachedLabel
294852
+ };
294853
+ }
294311
294854
  function readUnanimousTocTextTemplate(matchingTemplates) {
294312
294855
  const template = matchingTemplates?.[0];
294313
294856
  if (!template)
@@ -294340,16 +294883,61 @@ function readUniformTocLevelRunProperties(siblingTemplates) {
294340
294883
  return uniformRunProperties;
294341
294884
  }
294342
294885
  function buildTocContinuationParagraphOpen(entry, templates) {
294343
- return resolveTocParagraphOpen(entry.level, templates, entry.text);
294886
+ return resolveTocParagraphOpen(entry.level, templates, entry.cachedParagraphText ?? entry.text);
294887
+ }
294888
+ function createTocPageTabFallback(context, instruction, fieldByteStart) {
294889
+ if (/\\n\b/.test(instruction) || parseQuotedSwitch(instruction, "p") != null)
294890
+ return (paragraphOpen) => paragraphOpen;
294891
+ let model;
294892
+ let position;
294893
+ return (paragraphOpen, entry) => {
294894
+ if (entry.markerSeparator === "tab" || entry.text.includes("\t"))
294895
+ return paragraphOpen;
294896
+ const properties = findDirectChild(paragraphOpen + "</w:p>", "pPr");
294897
+ if (!properties || findDirectChild(properties.xml, "tabs") || findDirectChild(properties.xml, "AlternateContent"))
294898
+ return paragraphOpen;
294899
+ model ?? (model = compileWordStyleModel({
294900
+ stylesXml: readStyleDefinitionsPartBytes(context),
294901
+ settingsXml: readPartBytes2(context, "/word/settings.xml"),
294902
+ numberingXml: readPartBytes2(context, "/word/numbering.xml")
294903
+ }));
294904
+ const style = findDirectChild(properties.xml, "pStyle");
294905
+ const styleId = style ? readXmlAttributeByLocalName(style.xml, "val") : undefined;
294906
+ if (model.resolveParagraph({ inlineProps: { styleId } }).tabStops?.length)
294907
+ return paragraphOpen;
294908
+ const container = parseContainerXml(properties.xml.replace(/\/>$/, `></${properties.qname}>`), "pPr");
294909
+ if (!container)
294910
+ return paragraphOpen;
294911
+ if (position == null) {
294912
+ const sections = readLiveSectionSignals(context);
294913
+ const section = sections.find((candidate2) => fieldByteStart < candidate2.sectPr.rawXmlByteEnd) ?? sections.at(-1);
294914
+ const setup = section?.pageSetup;
294915
+ const width = (setup?.pageSize.widthTwips ?? 12240) - (setup?.margins.leftTwips ?? 1440) - (setup?.margins.rightTwips ?? 1440) - (setup?.margins.gutterTwips ?? 0);
294916
+ const count = Math.max(1, section?.columns?.count ?? 1);
294917
+ const columnWidth = section?.columns?.columns[0]?.widthTwips ?? (width - (count - 1) * (section?.columns?.spaceTwips ?? 720)) / count;
294918
+ position = Math.max(0, Math.floor(columnWidth) - 10);
294919
+ }
294920
+ const prefix = container.prefix;
294921
+ const tabs2 = `<${prefix}:tabs><${prefix}:tab ${prefix}:val="right" ${prefix}:leader="dot" ${prefix}:pos="${position}"/></${prefix}:tabs>`;
294922
+ const children2 = setParagraphPropertyChild(parseTopLevelChildrenPreservingTrivia(container.inner), "tabs", tabs2);
294923
+ return paragraphOpen.replace(properties.xml, () => container.open + serializeTopLevelChildren(children2) + container.close);
294924
+ };
294344
294925
  }
294345
- function buildGeneratedTocParagraphOpen(level, seedParagraph, templates, entryText) {
294346
- const template = resolveTocParagraphTemplate(level, templates, entryText);
294347
- if (template)
294926
+ function buildGeneratedTocParagraphOpen(level, seedParagraph, templates, entryText, retainOwner = false, pairedTemplate) {
294927
+ const template = pairedTemplate ?? resolveTocParagraphTemplate(level, templates, entryText);
294928
+ if (template && !(retainOwner && seedParagraph))
294348
294929
  return template;
294349
294930
  const normalizedLevel = normalizeTocLevel(level);
294350
294931
  if (!seedParagraph)
294351
294932
  return `<w:p><w:pPr><w:pStyle w:val="TOC${normalizedLevel}"/></w:pPr>`;
294352
- return `${readParagraphOpenTag(seedParagraph.rawXml)}<w:pPr><w:pStyle w:val="TOC${normalizedLevel}"/></w:pPr>`;
294933
+ const ownerOpenTag = readParagraphOpenTag(seedParagraph.rawXml);
294934
+ if (!retainOwner)
294935
+ return `${ownerOpenTag}<w:pPr><w:pStyle w:val="TOC${normalizedLevel}"/></w:pPr>`;
294936
+ const templateOpenEnd = template ? findXmlTagEnd4(template, 1) : -1;
294937
+ const properties = template ? inheritRunNamespaceDeclarations(template.slice(templateOpenEnd), template, templateOpenEnd, template.slice(0, templateOpenEnd)) : `<w:pPr><w:pStyle w:val="TOC${normalizedLevel}"/></w:pPr>`;
294938
+ const ownerPropertiesStart = skipXmlWhitespace(seedParagraph.rawXml, ownerOpenTag.length);
294939
+ const ownerProperties = matchLeadingElement(seedParagraph.rawXml.slice(ownerPropertiesStart), "pPr");
294940
+ return ownerOpenTag + preserveTocOwnerProperties(properties, ownerProperties);
294353
294941
  }
294354
294942
  function readParagraphOpenTag(paragraphXml) {
294355
294943
  const match = /^<w:p\b([^>]*?)(?:\/>|>)/s.exec(paragraphXml);
@@ -294360,6 +294948,9 @@ function normalizeTocLevel(level) {
294360
294948
  }
294361
294949
  function buildTocEntryTextRuns(entry, runProperties, includeHyperlinks) {
294362
294950
  const buildLabelRun = (text, template) => {
294951
+ if (entry.isTcEntry && text.includes("\t")) {
294952
+ return text.split("\t").map((part, index) => (index > 0 ? "<w:r><w:tab/></w:r>" : "") + (part ? buildLabelRun(part, template) : "")).join("");
294953
+ }
294363
294954
  const sanitized = template ? sanitizeTocLabelRunProperties(template.runProperties, includeHyperlinks) : "";
294364
294955
  if (!sanitized)
294365
294956
  return buildTextRunXml(text);
@@ -294388,7 +294979,7 @@ function buildTocEntryTextRuns(entry, runProperties, includeHyperlinks) {
294388
294979
  }
294389
294980
  const cachedFirstRunText = runProperties?.[0]?.text;
294390
294981
  const matchesCompleteMarkerBoundary = cachedFirstRunText === entry.marker || entry.markerSeparator === "space" && cachedFirstRunText?.startsWith(`${entry.marker} `);
294391
- if (markerSeparatorIndex < 0 && matchesCompleteMarkerBoundary) {
294982
+ if (markerSeparatorIndex < 0 && entry.markerSeparator !== "tab" && matchesCompleteMarkerBoundary) {
294392
294983
  return buildLabelRuns(entry.text, runProperties);
294393
294984
  }
294394
294985
  if (markerSeparatorIndex < 0 && entry.markerSeparator === "space" && runProperties?.[0]) {
@@ -294408,8 +294999,28 @@ function buildTocEntryTextRuns(entry, runProperties, includeHyperlinks) {
294408
294999
  }
294409
295000
  }
294410
295001
  }
294411
- const markerTemplates = markerSeparatorIndex >= 0 ? runProperties?.slice(0, markerSeparatorIndex) : runProperties?.slice(0, 1);
294412
- const titleTemplates = markerSeparatorIndex >= 0 ? runProperties?.slice(markerSeparatorIndex + 1) : runProperties && runProperties.length > 1 ? runProperties.slice(1) : runProperties;
295002
+ let markerTemplates = markerSeparatorIndex >= 0 ? runProperties?.slice(0, markerSeparatorIndex) : runProperties?.slice(0, 1);
295003
+ let titleTemplates = markerSeparatorIndex >= 0 ? runProperties?.slice(markerSeparatorIndex + 1) : runProperties && runProperties.length > 1 ? runProperties.slice(1) : runProperties;
295004
+ if (markerSeparatorIndex < 0 && entry.markerSeparator === "tab" && runProperties) {
295005
+ const cachedLabel = runProperties.map((template) => template.text).join("");
295006
+ const markerEnd = entry.marker.length;
295007
+ const titleStart = markerEnd + /^\s*/.exec(cachedLabel.slice(markerEnd))[0].length;
295008
+ if (cachedLabel.startsWith(entry.marker) && cachedLabel.slice(titleStart) === entry.title) {
295009
+ markerTemplates = [];
295010
+ titleTemplates = [];
295011
+ let offset = 0;
295012
+ for (const template of runProperties) {
295013
+ const end = offset + template.text.length;
295014
+ if (offset < markerEnd) {
295015
+ markerTemplates.push({ ...template, text: template.text.slice(0, markerEnd - offset) });
295016
+ }
295017
+ if (end > titleStart) {
295018
+ titleTemplates.push({ ...template, text: template.text.slice(Math.max(0, titleStart - offset)) });
295019
+ }
295020
+ offset = end;
295021
+ }
295022
+ }
295023
+ }
294413
295024
  const markerRuns = buildLabelRuns(entry.marker, markerTemplates);
294414
295025
  if (entry.markerSeparator === "tab") {
294415
295026
  return [...markerRuns, "<w:r><w:tab/></w:r>", ...buildLabelRuns(entry.title, titleTemplates)];
@@ -294426,9 +295037,42 @@ function sanitizeTocLabelRunProperties(runPropertiesXml, includeHyperlinks) {
294426
295037
  return runPropertiesXml;
294427
295038
  return runPropertiesXml.replace(/<(?:[\w.-]+:)?rStyle\b(?=[^>]*\b(?:[\w.-]+:)?val=(["'])Hyperlink\1)[^>]*(?:\/>|>\s*<\/(?:[\w.-]+:)?rStyle\s*>)/gi, "");
294428
295039
  }
294429
- function buildBodyTocBookmarkMap(context) {
295040
+ function tocTcFieldSourceKey(field) {
295041
+ return `tc:${field.storyId}:${field.stableFieldId}`;
295042
+ }
295043
+ function resolveTocTcBookmarkNames(bookmarks, paragraphs, fields) {
295044
+ if (fields.length === 0)
295045
+ return new Map;
295046
+ const sourceKeys = new Set(fields.map((field) => `${field.storyId}:${field.blockId}`));
295047
+ const sourceParagraphs = paragraphs.filter((paragraph2) => sourceKeys.has(`${paragraph2.storyId}:${paragraph2.blockId}`));
295048
+ const paragraphBookmarks = buildBodyTocBookmarkMap(bookmarks);
295049
+ const paragraphsByKey = new Map(sourceParagraphs.map((paragraph2) => [`${paragraph2.storyId}:${paragraph2.blockId}`, paragraph2]));
295050
+ const ranges = buildBodyTocBookmarkRangeMap(bookmarks, sourceParagraphs);
295051
+ const siblings = new Map;
295052
+ for (const field of fields) {
295053
+ const key2 = `${field.storyId}:${field.blockId}`;
295054
+ const group = siblings.get(key2) ?? [];
295055
+ group.push(field);
295056
+ siblings.set(key2, group);
295057
+ }
295058
+ const names = new Map;
295059
+ for (const field of fields) {
295060
+ const paragraphKey = `${field.storyId}:${field.blockId}`;
295061
+ const bookmarkRanges = ranges.get(paragraphKey);
295062
+ const paragraphBookmark = paragraphBookmarks.get(paragraphKey);
295063
+ const fallbackRange = bookmarkRanges?.find((bookmark) => bookmark.name === paragraphBookmark);
295064
+ const belongsToSibling = fallbackRange && siblings.get(paragraphKey)?.some((sibling) => sibling.stableFieldId !== field.stableFieldId && (fallbackRange.start >= sibling.descriptor.byteStart && fallbackRange.end <= sibling.descriptor.byteEnd || fallbackRange.start <= sibling.descriptor.byteStart && fallbackRange.end >= sibling.descriptor.byteEnd));
295065
+ const paragraph2 = paragraphsByKey.get(paragraphKey);
295066
+ const coversCrossParagraphStart = paragraph2 && fallbackRange && field.descriptor.byteEnd > paragraph2.byteEnd && fallbackRange.start <= field.descriptor.byteStart && fallbackRange.end > field.descriptor.byteStart;
295067
+ const name = bookmarkRanges?.find((bookmark) => bookmark.start >= field.descriptor.byteStart && bookmark.end <= field.descriptor.byteEnd)?.name ?? bookmarkRanges?.find((bookmark) => bookmark.start <= field.descriptor.byteStart && bookmark.end >= field.descriptor.byteEnd)?.name ?? (belongsToSibling && !coversCrossParagraphStart ? undefined : paragraphBookmark);
295068
+ if (name)
295069
+ names.set(tocTcFieldSourceKey(field), name);
295070
+ }
295071
+ return names;
295072
+ }
295073
+ function buildBodyTocBookmarkMap(entries) {
294430
295074
  const bookmarks = new Map;
294431
- for (const entry of readBookmarkEntries(context)) {
295075
+ for (const entry of entries) {
294432
295076
  if (!entry.name.startsWith("_Toc"))
294433
295077
  continue;
294434
295078
  const key2 = `${entry.storyId}:${entry.blockId}`;
@@ -294437,6 +295081,43 @@ function buildBodyTocBookmarkMap(context) {
294437
295081
  }
294438
295082
  return bookmarks;
294439
295083
  }
295084
+ function buildBodyTocBookmarkRangeMap(bookmarks, paragraphs) {
295085
+ if (paragraphs.length === 0)
295086
+ return new Map;
295087
+ const paragraphsByKey = new Map(paragraphs.map((paragraph2) => [`${paragraph2.storyId}:${paragraph2.blockId}`, paragraph2]));
295088
+ const scans = new Map;
295089
+ const ranges = new Map;
295090
+ for (const bookmark of bookmarks) {
295091
+ if (!bookmark.name.startsWith("_Toc"))
295092
+ continue;
295093
+ const key2 = `${bookmark.storyId}:${bookmark.blockId}`;
295094
+ const paragraph2 = paragraphsByKey.get(key2);
295095
+ if (!paragraph2)
295096
+ continue;
295097
+ if (!scans.has(key2))
295098
+ scans.set(key2, readBookmarkMarkerSpans(paragraph2.rawXml, paragraph2.namespaceBindings));
295099
+ const scan = scans.get(key2);
295100
+ if (!scan || scan.invalidBookmarkIds.has(bookmark.bookmarkId))
295101
+ continue;
295102
+ const endMarker = scan.markers.find((marker) => marker.kind === "end" && marker.bookmarkId === bookmark.bookmarkId);
295103
+ if (!endMarker)
295104
+ continue;
295105
+ const range = {
295106
+ name: bookmark.name,
295107
+ start: bookmark.markerByteStart,
295108
+ end: paragraph2.byteStart + encodeXml(paragraph2.rawXml.slice(0, endMarker.start)).length
295109
+ };
295110
+ if (range.end < range.start)
295111
+ continue;
295112
+ const paragraphRanges = ranges.get(key2) ?? [];
295113
+ paragraphRanges.push(range);
295114
+ ranges.set(key2, paragraphRanges);
295115
+ }
295116
+ for (const paragraphRanges of ranges.values()) {
295117
+ paragraphRanges.sort((left, right) => left.end - left.start - (right.end - right.start));
295118
+ }
295119
+ return ranges;
295120
+ }
294440
295121
  function buildTocPageReferenceRunsXml(bookmarkName, page, separator) {
294441
295122
  return buildTocPageSeparatorRunsXml(separator) + buildWebHiddenFieldCharRunXml("begin") + buildWebHiddenInstructionRunXml(` PAGEREF ${bookmarkName} \\h `) + buildWebHiddenEmptyRunXml() + buildWebHiddenFieldCharRunXml("separate") + buildWebHiddenTextRunXml(page) + buildWebHiddenFieldCharRunXml("end");
294442
295123
  }
@@ -294466,7 +295147,7 @@ function buildWebHiddenEmptyRunXml() {
294466
295147
  function emptyTocParagraphTemplates() {
294467
295148
  return {
294468
295149
  byLevel: new Map,
294469
- byText: new Map
295150
+ byLevelAndText: new Map
294470
295151
  };
294471
295152
  }
294472
295153
  function buildTocParagraphTemplatesFromParagraphXml(xml) {
@@ -294480,18 +295161,20 @@ function buildTocParagraphTemplatesFromParagraphXml(xml) {
294480
295161
  if (!templates.byLevel.has(level))
294481
295162
  templates.byLevel.set(level, open2);
294482
295163
  const entryText = readTocParagraphTemplateText(paragraphXml);
294483
- if (entryText && !templates.byText.has(entryText))
294484
- templates.byText.set(entryText, open2);
295164
+ const key2 = `${level}:${entryText}`;
295165
+ if (entryText && !templates.byLevelAndText.has(key2))
295166
+ templates.byLevelAndText.set(key2, open2);
294485
295167
  }
294486
295168
  return templates;
294487
295169
  }
294488
295170
  function buildTocParagraphTemplateOpen(paragraphXml) {
294489
295171
  const openTag = /^<w:p\b[^>]*>/s.exec(paragraphXml)?.[0] ?? "";
294490
- const pPrXml = openTag ? matchLeadingElement(paragraphXml.slice(openTag.length), "pPr") : "";
295172
+ const pPrXml = openTag ? matchLeadingElement(paragraphXml.slice(skipXmlWhitespace(paragraphXml, openTag.length)), "pPr") : "";
294491
295173
  return `${readParagraphOpenTag(paragraphXml)}${pPrXml}`;
294492
295174
  }
294493
295175
  function readTocParagraphLevel(paragraphXml) {
294494
- const paragraphStyle = findFirstElement(paragraphXml, "pStyle");
295176
+ const propertiesXml = matchLeadingElement(paragraphXml, "pPr") || findDirectChild(paragraphXml, "pPr")?.xml;
295177
+ const paragraphStyle = propertiesXml ? findDirectChild(propertiesXml, "pStyle") : undefined;
294495
295178
  const style = paragraphStyle ? /^TOC(\d+)$/.exec(readXmlAttributeByLocalName(paragraphStyle.xml, "val") ?? "")?.[1] : undefined;
294496
295179
  if (!style)
294497
295180
  return null;
@@ -294514,13 +295197,14 @@ function resolveTocParagraphOpen(level, templates, entryText) {
294514
295197
  return `<w:p><w:pPr><w:pStyle w:val="TOC${normalizedLevel}"/></w:pPr>`;
294515
295198
  }
294516
295199
  function resolveTocParagraphTemplate(level, templates, entryText) {
295200
+ const normalizedLevel = normalizeTocLevel(level);
294517
295201
  const normalizedText = entryText ? normalizeTocEntryText(entryText) : "";
294518
295202
  if (normalizedText.length > 0) {
294519
- const byText = templates.byText.get(normalizedText);
294520
- if (byText)
294521
- return byText;
295203
+ const byLevelAndText = templates.byLevelAndText.get(`${normalizedLevel}:${normalizedText}`);
295204
+ if (byLevelAndText)
295205
+ return byLevelAndText;
294522
295206
  }
294523
- return templates.byLevel.get(normalizeTocLevel(level));
295207
+ return templates.byLevel.get(normalizedLevel);
294524
295208
  }
294525
295209
  function readPreservedTocPagesByText(context, currentField, paragraphs = readBodyParagraphs(context, { includeListState: false })) {
294526
295210
  const preserved = new Map;
@@ -295210,7 +295894,7 @@ function joinMarkerAndText(marker, text) {
295210
295894
  return text.length > 0 ? `${marker} ${text}` : marker;
295211
295895
  }
295212
295896
  function parseTocEntryInstruction(instruction) {
295213
- const tableIdentifier = parseQuotedSwitch(instruction, "f") ?? parseQuotedSwitch(instruction, "t");
295897
+ const tableIdentifier = parseTocFieldIdentifier(instruction) ?? parseQuotedSwitch(instruction, "t");
295214
295898
  return {
295215
295899
  text: parseFirstQuotedValue(instruction) ?? "",
295216
295900
  level: Number(parseNumericSwitchValue(instruction, "l") ?? "1"),
@@ -295319,6 +296003,10 @@ var init_runtime2 = __esm(() => {
295319
296003
  init_registry3();
295320
296004
  init_stories();
295321
296005
  init_section_xml();
296006
+ init_src6();
296007
+ init_part();
296008
+ init_common();
296009
+ init_paragraph_property_order();
295322
296010
  init_scalar_evaluation();
295323
296011
  init_bookmark_insertion();
295324
296012
  init_xml();
@@ -340500,10 +341188,18 @@ class V2ContentControlsAdapter {
340500
341188
  if (controlPlacement(part.xml, control2) !== control2.info.kind) {
340501
341189
  throw operationError("CAPABILITY_UNAVAILABLE", "Row and cell controls are not supported adjacent insertion targets.");
340502
341190
  }
340503
- let fragment4 = buildAdjacentContent(input.content ?? "", control2.info.kind, createParaIdAllocator(this.context));
341191
+ const allocator = createParaIdAllocator(this.context);
341192
+ let createdBlockId = null;
341193
+ const captureParaId = () => {
341194
+ const id = allocator();
341195
+ if (createdBlockId == null)
341196
+ createdBlockId = id;
341197
+ return id;
341198
+ };
341199
+ let fragment4 = buildAdjacentContent(input.content ?? "", control2.info.kind, captureParaId);
340504
341200
  let commitOptions = {
340505
341201
  partUri: part.partUri,
340506
- storySurface: { family: "storyBlocks", contentControlRewrite: true, targetBlockIds: [] },
341202
+ storySurface: { family: "storyBlocks", contentControlRewrite: true, changeMode: "direct", targetBlockIds: [] },
340507
341203
  preserveRenderCommit: true
340508
341204
  };
340509
341205
  if (options?.changeMode === "tracked") {
@@ -340529,7 +341225,7 @@ class V2ContentControlsAdapter {
340529
341225
  return this.validateDryRun(input, options, control2.target);
340530
341226
  const index2 = placement3 === "before" ? control2.start : control2.end;
340531
341227
  const nextXml = `${part.xml.slice(0, index2)}${fragment4}${part.xml.slice(index2)}`;
340532
- return this.commitDocument(nextXml, `content-control-insert-${placement3}`, input, options, control2.target, commitOptions);
341228
+ return this.commitDocument(nextXml, `content-control-insert-${placement3}`, input, options, control2.target, { ...commitOptions, ...createdBlockId != null ? { createdBlockId } : {} });
340533
341229
  }
340534
341230
  mutatePr(input, options, transform2) {
340535
341231
  return this.mutateControl(input.target, input, options, (control2) => {
@@ -340920,6 +341616,7 @@ class V2ContentControlsAdapter {
340920
341616
  if (!documentProtectionAllowsXmlRewrite(this.context, partUri, before, nextXml)) {
340921
341617
  return { success: false, failure: { code: "PERMISSION_DENIED", message: DOCUMENT_PROTECTION_MESSAGE } };
340922
341618
  }
341619
+ let remappedCreatedBlockId = commitOptions.createdBlockId;
340923
341620
  if (commitOptions.storySurface?.contentControlRewrite && this.context.isCollaborativeSession()) {
340924
341621
  const existingIds = new Set(this.load().parts.flatMap((part) => Array.from(part.xml.matchAll(/\bw14:paraId="([^"]+)"/g), (match) => match[1])));
340925
341622
  const newIds = [...new Set(Array.from(nextXml.matchAll(/\bw14:paraId="([^"]+)"/g), (match) => match[1]))].filter((id) => !existingIds.has(id));
@@ -340929,6 +341626,9 @@ class V2ContentControlsAdapter {
340929
341626
  return { success: false, failure: { code: "PRECONDITION_FAILED", message: "Could not reserve content-control paragraph identities." } };
340930
341627
  const remap = new Map(newIds.map((id, index2) => [id, allocated[index2]]));
340931
341628
  nextXml = nextXml.replace(/\bw14:paraId="([^"]+)"/g, (attribute, id) => remap.has(id) ? `w14:paraId="${remap.get(id)}"` : attribute);
341629
+ if (remappedCreatedBlockId != null) {
341630
+ remappedCreatedBlockId = remap.get(remappedCreatedBlockId) ?? remappedCreatedBlockId;
341631
+ }
340932
341632
  }
340933
341633
  }
340934
341634
  const committed = commitWholePartUpdates(this.context, prefix, { [partUri]: encodeXml(nextXml) }, {
@@ -340953,7 +341653,8 @@ class V2ContentControlsAdapter {
340953
341653
  contentControl: target,
340954
341654
  ...commitOptions.updatedRef ? { updatedRef: commitOptions.updatedRef } : {},
340955
341655
  affectedStories: [...commitOptions.affectedStories ?? [target.story ?? { kind: "story", storyType: "body" }]],
340956
- ...trackedChangeRefs && trackedChangeRefs.length > 0 ? { trackedChangeRefs } : {}
341656
+ ...trackedChangeRefs && trackedChangeRefs.length > 0 ? { trackedChangeRefs } : {},
341657
+ ...remappedCreatedBlockId != null ? { createdBlockId: remappedCreatedBlockId } : {}
340957
341658
  };
340958
341659
  if (commitOptions.preserveRenderCommit) {
340959
341660
  const renderCommit = getSDRenderCommitEnvelope(committed);
@@ -343099,10 +343800,12 @@ function regenerateTrackedToc(context, entry, instruction, dryRun) {
343099
343800
  }));
343100
343801
  if (missing2.some((bookmark) => !bookmark.paragraph))
343101
343802
  return unavailable4("A TOC heading target is unavailable.");
343102
- const names = new Map(missing2.map((bookmark) => [
343103
- `${bookmark.paragraph.storyId}:${bookmark.blockId}`,
343104
- bookmark.name
343105
- ]));
343803
+ const names = new Map;
343804
+ for (const bookmark of missing2) {
343805
+ names.set(bookmark.fieldSource?.key ?? `${bookmark.paragraph.storyId}:${bookmark.blockId}`, bookmark.name);
343806
+ for (const key2 of bookmark.fieldSourceKeys ?? [])
343807
+ names.set(key2, bookmark.name);
343808
+ }
343106
343809
  const sdt = prepareTocSdtReplacement(context, entry, instruction, names);
343107
343810
  const rendered = !sdt.ok && sdt.message === "Unable to locate the containing TOC content control." ? prepareBareTocReplacement(context, entry, instruction, names) : sdt;
343108
343811
  if (!rendered.ok)
@@ -343141,16 +343844,18 @@ function regenerateTrackedToc(context, entry, instruction, dryRun) {
343141
343844
  ];
343142
343845
  let count = content3.wordIds.length;
343143
343846
  let bookmarkId = nextBookmarkNumericId(context);
343847
+ const bookmarkMarkers = [];
343144
343848
  for (const bookmark of missing2) {
343145
343849
  const paragraph4 = bookmark.paragraph;
343146
- const markers = [
343147
- `<w:bookmarkStart w:id="${bookmarkId}" w:name="${xmlEscapeAttr(bookmark.name)}"/>`,
343148
- `<w:bookmarkEnd w:id="${bookmarkId++}"/>`
343149
- ].map((xml2) => {
343850
+ const markerBindings = readBookmarkInsertionNamespaceBindings(paragraph4, bookmark);
343851
+ if (!markerBindings)
343852
+ return null;
343853
+ const fragments = buildParagraphBookmarkMarkers(paragraph4, bookmark, bookmarkId++);
343854
+ const markers = [fragments.startXml, fragments.endXml].map((xml) => {
343150
343855
  const marker = prepareTrackedInlineXmlReplacement({
343151
343856
  beforeXml: "",
343152
- afterXml: xml2,
343153
- namespaceBindings: new Map(Object.entries(paragraph4.namespaceBindings ?? {})),
343857
+ afterXml: xml,
343858
+ namespaceBindings: markerBindings,
343154
343859
  stamp: {
343155
343860
  ...stamp,
343156
343861
  revisionId: revisionIds?.[count] ?? count,
@@ -343163,10 +343868,12 @@ function regenerateTrackedToc(context, entry, instruction, dryRun) {
343163
343868
  });
343164
343869
  if (!markers[0] || !markers[1])
343165
343870
  return null;
343166
- const start = injectParagraphPrefix(paragraph4.rawXml, markers[0].xml);
343167
- const xml = start && injectParagraphSuffix(start, markers[1].xml);
343168
- if (!xml)
343169
- return null;
343871
+ bookmarkMarkers.push({ ...bookmark, startXml: markers[0].xml, endXml: markers[1].xml });
343872
+ }
343873
+ const grouped = prepareBookmarkParagraphGroups(paragraphs, bookmarkMarkers);
343874
+ if (!grouped)
343875
+ return null;
343876
+ for (const { paragraph: paragraph4, xml } of grouped) {
343170
343877
  edits.push({
343171
343878
  partUri: paragraph4.partUri,
343172
343879
  storyId: paragraph4.storyId,
@@ -343202,6 +343909,8 @@ function regenerateTrackedToc(context, entry, instruction, dryRun) {
343202
343909
  return unavailable4("This TOC rebuild requires unsupported existing field, paragraph, or heading boundaries.");
343203
343910
  if (dryRun)
343204
343911
  return { ok: true };
343912
+ if (context.isCollaborativeSession())
343913
+ return { ok: false, code: "INVALID_CONTEXT", message: "toc-regenerate-tracked: unsupported-context" };
343205
343914
  const ids = reserveTrackedReferenceRevisionIds(context, preview.count, false);
343206
343915
  if (!ids)
343207
343916
  return unavailable4("The TOC rebuild could not reserve its complete revision identity batch.");
@@ -344461,9 +345170,11 @@ class V2TocAdapter {
344461
345170
  }
344462
345171
  if (options?.dryRun)
344463
345172
  return success3(input.target.nodeId);
345173
+ if (this.context.isCollaborativeSession())
345174
+ return failure6("INVALID_CONTEXT", "toc-configure: unsupported-context");
344464
345175
  let refreshed = entry;
344465
345176
  if (!usesV1EmptyTocSourceSet(nextInstruction)) {
344466
- const seeded = seedMissingTocBookmarks(this.context, nextInstruction);
345177
+ const seeded = seedMissingTocBookmarks(this.context, nextInstruction, entry.field);
344467
345178
  if (!seeded.ok)
344468
345179
  return failure6(seeded.code, seeded.message);
344469
345180
  const seededEntry = findTocBlock(this.context, input.target.nodeId);
@@ -344495,9 +345206,11 @@ class V2TocAdapter {
344495
345206
  }
344496
345207
  if (options?.dryRun)
344497
345208
  return success3(input.target.nodeId);
345209
+ if (this.context.isCollaborativeSession())
345210
+ return failure6("INVALID_CONTEXT", "toc-update: unsupported-context");
344498
345211
  let refreshed = entry;
344499
345212
  if (!usesV1EmptyTocSourceSet(entry.field.descriptor.instructionText)) {
344500
- const seeded = seedMissingTocBookmarks(this.context, entry.field.descriptor.instructionText);
345213
+ const seeded = seedMissingTocBookmarks(this.context, entry.field.descriptor.instructionText, entry.field);
344501
345214
  if (!seeded.ok)
344502
345215
  return failure6(seeded.code, seeded.message);
344503
345216
  const seededEntry = findTocBlock(this.context, input.target.nodeId);
@@ -344679,6 +345392,9 @@ function listTocBlocks(context) {
344679
345392
  function findTocBlock(context, nodeId) {
344680
345393
  return listTocBlocks(context).find((entry) => entry.field.blockId === nodeId) ?? null;
344681
345394
  }
345395
+ function guardTocBookmarkInsertion(context, instruction, operation) {
345396
+ return guardTocContentMutation(context, null, instruction, operation);
345397
+ }
344682
345398
  function guardTocContentMutation(context, field, instruction, operation) {
344683
345399
  const unavailable4 = () => ({ code: "CAPABILITY_UNAVAILABLE", message: `${operation}: the TOC source is unavailable.` });
344684
345400
  const decoder7 = new TextDecoder;
@@ -344698,15 +345414,28 @@ function guardTocContentMutation(context, field, instruction, operation) {
344698
345414
  });
344699
345415
  return true;
344700
345416
  };
344701
- if (!add(field.partUri, field.descriptor.byteStart, field.descriptor.byteEnd))
345417
+ if (field && !add(field.partUri, field.descriptor.byteStart, field.descriptor.byteEnd))
344702
345418
  return unavailable4();
344703
345419
  const missing2 = planMissingTocBookmarks(context, instruction);
344704
345420
  if (missing2.length) {
344705
345421
  const paragraphs = new Map(readBodyParagraphs(context, { includeListState: false }).map((paragraph4) => [paragraph4.blockId, paragraph4]));
345422
+ const aliasedFields = missing2.some((bookmark) => bookmark.fieldSourceKeys?.length) ? new Map(listCanonicalFieldEntries(context).map((source) => [tocTcFieldSourceKey(source), source])) : null;
344706
345423
  for (const bookmark of missing2) {
344707
345424
  const paragraph4 = paragraphs.get(bookmark.blockId);
344708
- if (!paragraph4 || !add(paragraph4.partUri, paragraph4.byteStart, paragraph4.byteStart + 1))
345425
+ if (!paragraph4)
344709
345426
  return unavailable4();
345427
+ const start = bookmark.fieldSource?.byteStart ?? paragraph4.byteStart;
345428
+ const end = bookmark.fieldSource?.byteEnd ?? paragraph4.byteStart;
345429
+ if (!add(paragraph4.partUri, start, start + 1) || bookmark.fieldSource && !add(paragraph4.partUri, end - 1, end))
345430
+ return unavailable4();
345431
+ for (const key2 of bookmark.fieldSourceKeys ?? []) {
345432
+ const source = aliasedFields?.get(key2);
345433
+ if (!source?.descriptor.complete)
345434
+ continue;
345435
+ const fieldSource = { key: key2, byteStart: source.descriptor.byteStart, byteEnd: source.descriptor.byteEnd };
345436
+ if (canPlaceBookmarkAtFieldSource(paragraph4, fieldSource) && (!add(source.partUri, fieldSource.byteStart, fieldSource.byteStart + 1) || !add(source.partUri, fieldSource.byteEnd - 1, fieldSource.byteEnd)))
345437
+ return unavailable4();
345438
+ }
344710
345439
  }
344711
345440
  }
344712
345441
  for (const part of parts.values()) {
@@ -344714,6 +345443,20 @@ function guardTocContentMutation(context, field, instruction, operation) {
344714
345443
  if (locked)
344715
345444
  return locked;
344716
345445
  }
345446
+ if (missing2.length) {
345447
+ const paragraphs = readBodyParagraphs(context, { includeListState: false });
345448
+ const byId = new Map(paragraphs.map((paragraph4) => [paragraph4.blockId, paragraph4]));
345449
+ let id = nextBookmarkNumericId(context);
345450
+ const markers = missing2.map((bookmark) => ({
345451
+ ...bookmark,
345452
+ ...buildParagraphBookmarkMarkers(byId.get(bookmark.blockId), bookmark, id++)
345453
+ }));
345454
+ if (!prepareBookmarkParagraphGroups(paragraphs, markers))
345455
+ return {
345456
+ code: "CAPABILITY_UNAVAILABLE",
345457
+ message: `${operation}: TOC bookmark targets have unsupported paragraph or field boundaries.`
345458
+ };
345459
+ }
344717
345460
  return null;
344718
345461
  }
344719
345462
  function paragraphOverlapsSpan(entry, span) {
@@ -344797,10 +345540,11 @@ function projectTocInlineDomain(entry) {
344797
345540
  };
344798
345541
  }
344799
345542
  function projectTocSourceConfig(instruction) {
345543
+ const tcSelection = parseTocTcSourceSelection(instruction);
344800
345544
  return {
344801
345545
  ...parseNumericSwitchRange(instruction, "o") ? { outlineLevels: parseNumericSwitchRange(instruction, "o") } : {},
344802
- ...parseQuotedSwitch(instruction, "f") ? { tcFieldIdentifier: parseQuotedSwitch(instruction, "f") } : {},
344803
- ...parseNumericSwitchRange(instruction, "l") ? { tcFieldLevels: parseNumericSwitchRange(instruction, "l") } : {},
345546
+ ...tcSelection.identifier ? { tcFieldIdentifier: tcSelection.identifier } : {},
345547
+ ...tcSelection.levels ? { tcFieldLevels: tcSelection.levels } : {},
344804
345548
  ...instruction.includes("\\u") ? { useAppliedOutlineLevel: true } : {}
344805
345549
  };
344806
345550
  }
@@ -344828,23 +345572,22 @@ function countGeneratedTocEntries(context, instruction, sourceConfig) {
344828
345572
  const outline = sourceConfig.outlineLevels ?? { from: 1, to: 3 };
344829
345573
  const customStyles = parseTocCustomStyles2(parseQuotedSwitch(instruction, "t") ?? "");
344830
345574
  const includeOutlineEntries = customStyles.length === 0 || sourceConfig.outlineLevels != null;
344831
- const headings = readBodyParagraphs(context, { includeListState: false }).filter((paragraph4) => {
345575
+ const paragraphs = readBodyParagraphs(context, { includeListState: false });
345576
+ const bodyParagraphs = new Set(paragraphs.map((paragraph4) => `${paragraph4.storyId}:${paragraph4.blockId}`));
345577
+ const headings = paragraphs.filter((paragraph4) => {
344832
345578
  const matchesCustomStyle = paragraph4.styleId != null && customStyles.some((entry) => normalizeStyleId2(entry.styleName) === normalizeStyleId2(paragraph4.styleId ?? ""));
344833
345579
  const matchesOutline = includeOutlineEntries && paragraph4.headingLevel >= outline.from && paragraph4.headingLevel <= outline.to;
344834
345580
  return matchesCustomStyle || matchesOutline;
344835
345581
  }).length;
344836
- const tcEntries = listTocInlineEntries(context).filter((entry) => {
345582
+ const tcSelection = parseTocTcSourceSelection(instruction);
345583
+ const tcEntries = listTocInlineEntries(context).filter((entry) => bodyParagraphs.has(`${entry.field.storyId}:${entry.field.blockId}`)).filter((entry) => {
344837
345584
  const parsed = parseTocEntryInstruction(entry.field.descriptor.instructionText);
344838
- if (sourceConfig.tcFieldIdentifier && parsed.tableIdentifier !== sourceConfig.tcFieldIdentifier)
344839
- return false;
344840
- if (sourceConfig.tcFieldLevels && (parsed.level < sourceConfig.tcFieldLevels.from || parsed.level > sourceConfig.tcFieldLevels.to))
344841
- return false;
344842
- return true;
345585
+ return matchesTocTcSourceSelection(tcSelection, parsed);
344843
345586
  }).length;
344844
345587
  return headings + tcEntries;
344845
345588
  }
344846
345589
  function usesV1EmptyTocSourceSet(instruction) {
344847
- return parseQuotedSwitch(instruction, "t") != null && parseNumericSwitchRange(instruction, "o") == null && !/\\u\b/i.test(instruction) && parseQuotedSwitch(instruction, "f") == null && parseNumericSwitchRange(instruction, "l") == null;
345590
+ return parseQuotedSwitch(instruction, "t") != null && parseNumericSwitchRange(instruction, "o") == null && !/\\u\b/i.test(instruction) && !parseTocTcSourceSelection(instruction).enabled;
344848
345591
  }
344849
345592
  function countMaterializedTocResultParagraphs(context, field) {
344850
345593
  if (field.descriptor.resultText.length === 0)
@@ -344867,6 +345610,7 @@ function isTocResultParagraph(rawXml) {
344867
345610
  return /<[\w.-]+:pStyle\b[^>]*\b(?:[\w.-]+:)?val="TOC[1-9]"/.test(rawXml);
344868
345611
  }
344869
345612
  function applyTocPatch(instruction, patch) {
345613
+ const tcSelection = parseTocTcSourceSelection(instruction);
344870
345614
  const nextParts = ["TOC"];
344871
345615
  const outlineLevels = patch.outlineLevels ?? parseNumericSwitchRange(instruction, "o");
344872
345616
  if (outlineLevels)
@@ -344883,12 +345627,17 @@ function applyTocPatch(instruction, patch) {
344883
345627
  nextParts.push(`\\p "${separator}"`);
344884
345628
  if ((patch.useAppliedOutlineLevel ?? instruction.includes("\\u")) === true)
344885
345629
  nextParts.push("\\u");
344886
- const tcIdentifier = patch.tcFieldIdentifier ?? parseQuotedSwitch(instruction, "f");
345630
+ const tcIdentifier = patch.tcFieldIdentifier ?? tcSelection.identifier;
344887
345631
  if (tcIdentifier != null)
344888
345632
  nextParts.push(`\\f "${tcIdentifier}"`);
344889
- const tcLevels = patch.tcFieldLevels ?? parseNumericSwitchRange(instruction, "l");
345633
+ else if (tcSelection.hasFieldSwitch)
345634
+ nextParts.push("\\f");
345635
+ const tcLevels = patch.tcFieldLevels ?? tcSelection.levels;
344890
345636
  if (tcLevels)
344891
345637
  nextParts.push(`\\l "${tcLevels.from}-${tcLevels.to}"`);
345638
+ else if (tcSelection.hasLevelSwitch) {
345639
+ nextParts.push(tcSelection.levelArgument == null ? "\\l" : `\\l "${tcSelection.levelArgument}"`);
345640
+ }
344892
345641
  return [...nextParts, ...readPreservedTocSwitchFragments(instruction)].join(" ");
344893
345642
  }
344894
345643
  function serializeTocEntryInstruction(text4, level, tableIdentifier, omitPageNumber) {
@@ -344986,9 +345735,19 @@ function parseTocCustomStyles2(value2) {
344986
345735
  function normalizeStyleId2(value2) {
344987
345736
  return value2.replace(/\s+/g, "").trim().toLowerCase();
344988
345737
  }
344989
- function seedMissingTocBookmarks(context, instruction) {
345738
+ function seedMissingTocBookmarks(context, instruction, field) {
344990
345739
  const insertions = planMissingTocBookmarks(context, instruction);
344991
345740
  if (insertions.length > 0) {
345741
+ const paragraphs = new Map(readBodyParagraphs(context, { includeListState: false }).map((paragraph4) => [paragraph4.blockId, paragraph4]));
345742
+ const names = new Map;
345743
+ for (const bookmark of insertions) {
345744
+ names.set(bookmark.fieldSource?.key ?? `${paragraphs.get(bookmark.blockId).storyId}:${bookmark.blockId}`, bookmark.name);
345745
+ for (const key2 of bookmark.fieldSourceKeys ?? [])
345746
+ names.set(key2, bookmark.name);
345747
+ }
345748
+ const prepared = prepareTocReplacement(context, field, instruction, names);
345749
+ if (!prepared.ok)
345750
+ return prepared;
344992
345751
  const committed = insertBookmarksIntoParagraphs(context, insertions, "toc-bookmark-seed");
344993
345752
  if (!committed.ok)
344994
345753
  return committed;
@@ -344998,44 +345757,91 @@ function seedMissingTocBookmarks(context, instruction) {
344998
345757
  function planMissingTocBookmarks(context, instruction) {
344999
345758
  if (usesV1EmptyTocSourceSet(instruction))
345000
345759
  return [];
345001
- const existing = new Map;
345002
- const existingNames = new Set;
345003
- for (const bookmark of readBookmarkEntries(context)) {
345004
- existingNames.add(bookmark.name);
345005
- if (!bookmark.name.startsWith("_Toc"))
345006
- continue;
345007
- const key2 = `${bookmark.storyId}:${bookmark.blockId}`;
345008
- if (!existing.has(key2))
345009
- existing.set(key2, bookmark.name);
345010
- }
345760
+ const bookmarks = readBookmarkEntries(context);
345761
+ const existingNames = new Set(bookmarks.map((bookmark) => bookmark.name));
345762
+ const existingParagraphs = new Set(bookmarks.filter((bookmark) => bookmark.name.startsWith("_Toc")).map((bookmark) => `${bookmark.storyId}:${bookmark.blockId}`));
345763
+ const paragraphs = readBodyParagraphs(context, { includeListState: false });
345764
+ const bodyKeys = new Set(paragraphs.map((paragraph4) => `${paragraph4.storyId}:${paragraph4.blockId}`));
345765
+ const canonicalFields = listCanonicalFieldEntries(context);
345766
+ const tcFields = canonicalFields.filter((field) => instructionKeyword(field.descriptor.instructionText) === "TC" && bodyKeys.has(`${field.storyId}:${field.blockId}`));
345767
+ const incompleteFields = canonicalFields.filter((field) => !field.descriptor.complete);
345768
+ const tcBookmarkNames = resolveTocTcBookmarkNames(bookmarks, paragraphs, tcFields);
345011
345769
  let nextOrdinal = nextTocBookmarkOrdinal(existingNames);
345012
345770
  const insertions = [];
345013
- for (const paragraph4 of listIncludedTocParagraphs(context, instruction)) {
345014
- const key2 = `${paragraph4.storyId}:${paragraph4.blockId}`;
345015
- if (existing.has(key2))
345016
- continue;
345017
- let name = buildTocBookmarkName(nextOrdinal);
345018
- while (existingNames.has(name)) {
345019
- nextOrdinal += 1;
345020
- name = buildTocBookmarkName(nextOrdinal);
345021
- }
345022
- insertions.push({ blockId: paragraph4.blockId, name });
345023
- existing.set(key2, name);
345771
+ const genericByParagraph = new Map;
345772
+ const paragraphsByKey = new Map(paragraphs.map((paragraph4) => [`${paragraph4.storyId}:${paragraph4.blockId}`, paragraph4]));
345773
+ const allocateName = () => {
345774
+ let name = buildTocBookmarkName(nextOrdinal++);
345775
+ while (existingNames.has(name))
345776
+ name = buildTocBookmarkName(nextOrdinal++);
345024
345777
  existingNames.add(name);
345025
- nextOrdinal += 1;
345026
- }
345027
- return insertions;
345028
- }
345029
- function listIncludedTocParagraphs(context, instruction) {
345778
+ return name;
345779
+ };
345030
345780
  const customStyles = parseTocCustomStyles2(parseQuotedSwitch(instruction, "t") ?? "");
345031
345781
  const explicitOutlineRange = parseNumericSwitchRange(instruction, "o");
345032
345782
  const outlineRange = explicitOutlineRange ?? { from: 1, to: 3 };
345033
345783
  const includeOutlineEntries = customStyles.length === 0 || explicitOutlineRange != null;
345034
- return readBodyParagraphs(context, { includeListState: false }).filter((paragraph4) => {
345784
+ for (const paragraph4 of paragraphs) {
345035
345785
  const matchesCustomStyle = paragraph4.styleId != null && customStyles.some((entry) => normalizeStyleId2(entry.styleName) === normalizeStyleId2(paragraph4.styleId ?? ""));
345036
345786
  const matchesOutline = includeOutlineEntries && paragraph4.headingLevel >= outlineRange.from && paragraph4.headingLevel <= outlineRange.to;
345037
- return matchesCustomStyle || matchesOutline;
345038
- });
345787
+ if ((matchesCustomStyle || matchesOutline) && !existingParagraphs.has(`${paragraph4.storyId}:${paragraph4.blockId}`)) {
345788
+ const insertion = { blockId: paragraph4.blockId, name: allocateName() };
345789
+ insertions.push(insertion);
345790
+ genericByParagraph.set(`${paragraph4.storyId}:${paragraph4.blockId}`, insertion);
345791
+ }
345792
+ }
345793
+ const selection = parseTocTcSourceSelection(instruction);
345794
+ const missingFields = tcFields.filter((field) => matchesTocTcSourceSelection(selection, parseTocEntryInstruction(field.descriptor.instructionText)) && !tcBookmarkNames.has(tocTcFieldSourceKey(field))).map((field) => {
345795
+ const key2 = tocTcFieldSourceKey(field);
345796
+ const fieldSource = { key: key2, byteStart: field.descriptor.byteStart, byteEnd: field.descriptor.byteEnd };
345797
+ const paragraphKey = `${field.storyId}:${field.blockId}`;
345798
+ const paragraph4 = paragraphsByKey.get(paragraphKey);
345799
+ const bytes = readPartBytes2(context, field.partUri);
345800
+ const validCanonicalField = Boolean(field.descriptor.complete && Number.isInteger(fieldSource.byteStart) && Number.isInteger(fieldSource.byteEnd) && fieldSource.byteStart >= paragraph4.byteStart && fieldSource.byteEnd > fieldSource.byteStart && bytes && fieldSource.byteEnd <= bytes.length);
345801
+ return { field, key: key2, fieldSource, paragraphKey, paragraph: paragraph4, validCanonicalField };
345802
+ });
345803
+ const fieldsByParagraph = new Map;
345804
+ for (const source of missingFields) {
345805
+ const group = fieldsByParagraph.get(source.paragraphKey) ?? [];
345806
+ group.push(source);
345807
+ fieldsByParagraph.set(source.paragraphKey, group);
345808
+ }
345809
+ const collidingKeys = new Set;
345810
+ for (const group of fieldsByParagraph.values()) {
345811
+ group.sort((left, right) => left.fieldSource.byteStart - right.fieldSource.byteStart);
345812
+ let component = [];
345813
+ let componentEnd = -1;
345814
+ const finishComponent = () => {
345815
+ if (component.length > 1 && component.every((source) => source.validCanonicalField) && !incompleteFields.some((field) => field.storyId === component[0].field.storyId && field.blockId === component[0].field.blockId && field.descriptor.byteStart >= component[0].fieldSource.byteStart && field.descriptor.byteStart < componentEnd)) {
345816
+ for (const source of component)
345817
+ collidingKeys.add(source.key);
345818
+ }
345819
+ };
345820
+ for (const source of group) {
345821
+ if (source.fieldSource.byteStart >= componentEnd) {
345822
+ finishComponent();
345823
+ component = [];
345824
+ componentEnd = -1;
345825
+ }
345826
+ component.push(source);
345827
+ componentEnd = Math.max(componentEnd, source.fieldSource.byteEnd);
345828
+ }
345829
+ finishComponent();
345830
+ }
345831
+ for (const { field, key: key2, fieldSource, paragraphKey, paragraph: paragraph4, validCanonicalField } of missingFields) {
345832
+ if (validCanonicalField && (collidingKeys.has(key2) || !canPlaceBookmarkAtFieldSource(paragraph4, fieldSource))) {
345833
+ let generic = genericByParagraph.get(paragraphKey);
345834
+ if (!generic) {
345835
+ generic = { blockId: field.blockId, name: allocateName() };
345836
+ genericByParagraph.set(paragraphKey, generic);
345837
+ insertions.push(generic);
345838
+ }
345839
+ (generic.fieldSourceKeys ?? (generic.fieldSourceKeys = [])).push(key2);
345840
+ } else {
345841
+ insertions.push({ blockId: field.blockId, name: allocateName(), fieldSource });
345842
+ }
345843
+ }
345844
+ return insertions;
345039
345845
  }
345040
345846
  function nextTocBookmarkOrdinal(existingNames) {
345041
345847
  let largest = 0;
@@ -345134,14 +345940,17 @@ function insertTrackedToc(context, input) {
345134
345940
  }));
345135
345941
  if (missing2.some((bookmark) => !bookmark.paragraph))
345136
345942
  return unavailable4("A TOC heading target is unavailable.");
345137
- const names = new Map(missing2.map((bookmark) => [
345138
- `${bookmark.paragraph.storyId}:${bookmark.blockId}`,
345139
- bookmark.name
345140
- ]));
345943
+ const names = new Map;
345944
+ for (const bookmark of missing2) {
345945
+ names.set(bookmark.fieldSource?.key ?? `${bookmark.paragraph.storyId}:${bookmark.blockId}`, bookmark.name);
345946
+ for (const key2 of bookmark.fieldSourceKeys ?? [])
345947
+ names.set(key2, bookmark.name);
345948
+ }
345141
345949
  let tocXml = buildTocFieldXml(context, input.instruction, {
345142
345950
  bare: true,
345143
345951
  tocBookmarkNames: names,
345144
- reservedParaIds: occupied
345952
+ reservedParaIds: occupied,
345953
+ insertionByteStart: insertByte
345145
345954
  });
345146
345955
  tocXml = tocXml.replace(/<w:p\b[^>]*>/g, (open2) => /\sxmlns:w14\s*=/.test(open2) ? open2 : open2.replace("<w:p", '<w:p xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml"'));
345147
345956
  const tocRanges = collectXmlElementRanges(tocXml, {
@@ -345153,17 +345962,8 @@ function insertTrackedToc(context, input) {
345153
345962
  const tocParagraphs = tocRanges.ranges.filter((range) => range.tag.namespaceUri === bindings.get("w") && range.tag.localName === "p");
345154
345963
  if (!tocParagraphs.length)
345155
345964
  return unavailable4("The generated TOC has no paragraphs.");
345156
- const coordinated = context.isCollaborativeSession() && !input.dryRun ? context.allocateCollaborativeStoryParaIds({
345157
- count: tocParagraphs.length,
345158
- inUse: [...occupied]
345159
- }) : null;
345160
- if (context.isCollaborativeSession() && !input.dryRun && (coordinated?.length !== tocParagraphs.length || new Set(coordinated.map((id) => id.toUpperCase())).size !== coordinated.length || coordinated.some((id) => !/^[0-9a-f]{8}$/i.test(id) || occupied.has(id.toUpperCase())))) {
345161
- return unavailable4("TOC insertion could not reserve its complete paragraph identity batch.");
345162
- }
345163
345965
  let nextParagraphId = 184549376;
345164
- const paragraphIds = tocParagraphs.map((_paragraph, index2) => {
345165
- if (coordinated)
345166
- return coordinated[index2];
345966
+ const paragraphIds = tocParagraphs.map(() => {
345167
345967
  let id;
345168
345968
  do {
345169
345969
  id = (++nextParagraphId).toString(16).toUpperCase().padStart(8, "0");
@@ -345188,6 +345988,12 @@ function insertTrackedToc(context, input) {
345188
345988
  const preview = prepareTrackedTocInsertion({ xml: tocXml, namespaceBindings: bindings, stamp });
345189
345989
  if (!preview)
345190
345990
  return unavailable4("The generated TOC content cannot be represented by supported run revisions.");
345991
+ if (context.isCollaborativeSession() && !input.dryRun)
345992
+ return {
345993
+ ok: false,
345994
+ code: "INVALID_CONTEXT",
345995
+ message: "create-table-of-contents-tracked: unsupported-context"
345996
+ };
345191
345997
  const ids = reserveTrackedReferenceRevisionIds(context, preview.wordIds.length + missing2.length * 2, input.dryRun);
345192
345998
  if (!ids)
345193
345999
  return unavailable4("TOC insertion could not reserve its complete revision identity batch.");
@@ -345204,24 +346010,29 @@ function insertTrackedToc(context, input) {
345204
346010
  const storyIds = new Set([input.storyId]);
345205
346011
  let idIndex = preview.wordIds.length;
345206
346012
  let bookmarkId = nextBookmarkNumericId(context);
346013
+ const bookmarkMarkers = [];
345207
346014
  for (const bookmark of missing2) {
345208
346015
  const paragraph4 = bookmark.paragraph;
345209
- const startXml = `<w:bookmarkStart w:id="${bookmarkId}" w:name="${xmlEscapeAttr(bookmark.name)}"/>`;
345210
- const endXml = `<w:bookmarkEnd w:id="${bookmarkId++}"/>`;
346016
+ const markerBindings = readBookmarkInsertionNamespaceBindings(paragraph4, bookmark);
346017
+ if (!markerBindings)
346018
+ return unavailable4("TOC bookmark namespace context is unavailable.");
346019
+ const { startXml, endXml } = buildParagraphBookmarkMarkers(paragraph4, bookmark, bookmarkId++);
345211
346020
  const markers = [startXml, endXml].map((xml) => prepareTrackedInlineXmlReplacement({
345212
346021
  beforeXml: "",
345213
346022
  afterXml: xml,
345214
- namespaceBindings: new Map(Object.entries(paragraph4.namespaceBindings ?? {})),
346023
+ namespaceBindings: markerBindings,
345215
346024
  stamp: { ...stamp, revisionId: ids[idIndex], revisionIds: [ids[idIndex++]] }
345216
346025
  }));
345217
346026
  if (!markers[0] || !markers[1])
345218
346027
  return unavailable4("TOC bookmark markers cannot be revision marked.");
345219
- const withStart = injectParagraphPrefix(paragraph4.rawXml, markers[0].xml);
345220
- const withEnd = withStart && injectParagraphSuffix(withStart, markers[1].xml);
345221
- if (!withEnd)
345222
- return unavailable4("TOC bookmark markers could not be placed.");
346028
+ bookmarkMarkers.push({ ...bookmark, startXml: markers[0].xml, endXml: markers[1].xml });
346029
+ }
346030
+ const grouped = prepareBookmarkParagraphGroups(paragraphs, bookmarkMarkers);
346031
+ if (!grouped)
346032
+ return unavailable4("TOC bookmark markers could not be placed.");
346033
+ for (const { paragraph: paragraph4, xml } of grouped) {
345223
346034
  const perPart2 = edits.get(paragraph4.partUri) ?? [];
345224
- perPart2.push({ start: paragraph4.byteStart, end: paragraph4.byteEnd, bytes: encodeXml(withEnd) });
346035
+ perPart2.push({ start: paragraph4.byteStart, end: paragraph4.byteEnd, bytes: encodeXml(xml) });
345225
346036
  edits.set(paragraph4.partUri, perPart2);
345226
346037
  storyIds.add(paragraph4.storyId);
345227
346038
  }
@@ -346189,10 +347000,14 @@ class V2CreateAdapter {
346189
347000
  return { success: true, section, ...trackedChangeRefs.length ? { trackedChangeRefs } : {} };
346190
347001
  }
346191
347002
  tableOfContents(input, options) {
347003
+ const guard = beginCanonicalMutation(this.context, options, "create.tableOfContents");
347004
+ if (guard)
347005
+ return createFailure(guard.code, guard.message);
347006
+ const instruction = buildEffectiveTocInstruction(input.instruction, input.config);
347007
+ const locked = guardTocBookmarkInsertion(this.context, instruction, "create.tableOfContents");
347008
+ if (locked)
347009
+ return createFailure(locked.code, locked.message);
346192
347010
  if (options?.changeMode === "tracked") {
346193
- const guard = beginCanonicalMutation(this.context, options, "create.tableOfContents");
346194
- if (guard)
346195
- return createFailure(guard.code, guard.message);
346196
347011
  const paragraphInput = { at: input.at, text: "" };
346197
347012
  const story = resolveStoryTarget(this.context, effectiveStoryLocator(paragraphInput));
346198
347013
  if ("failure" in story)
@@ -346212,7 +347027,7 @@ class V2CreateAdapter {
346212
347027
  ...site,
346213
347028
  storyId: anchor.storyId,
346214
347029
  documentBoundary: input.at?.kind === "documentStart" || input.at?.kind === "documentEnd" ? input.at.kind : undefined,
346215
- instruction: buildEffectiveTocInstruction(input.instruction, input.config),
347030
+ instruction,
346216
347031
  dryRun: options.dryRun
346217
347032
  });
346218
347033
  if (!inserted.ok)
@@ -346225,6 +347040,8 @@ class V2CreateAdapter {
346225
347040
  toc: { kind: "block", nodeType: "tableOfContents", nodeId: "(dry-run)" }
346226
347041
  };
346227
347042
  }
347043
+ if (this.context.isCollaborativeSession())
347044
+ return createFailure("INVALID_CONTEXT", "create-table-of-contents: unsupported-context");
346228
347045
  const created = this.paragraph({ at: input.at, text: "" }, options);
346229
347046
  if (!created.success) {
346230
347047
  return {
@@ -346233,7 +347050,6 @@ class V2CreateAdapter {
346233
347050
  };
346234
347051
  }
346235
347052
  const nodeId = created.paragraph.nodeId;
346236
- const instruction = buildEffectiveTocInstruction(input.instruction, input.config);
346237
347053
  const committed = prependTocFieldToGeneratedParagraph(this.context, nodeId, instruction, "create-table-of-contents", undefined, input.at?.kind === "documentStart" || input.at?.kind === "documentEnd" ? input.at.kind : undefined);
346238
347054
  if (!committed.ok)
346239
347055
  return createFailure(committed.code, committed.message);
@@ -346964,107 +347780,6 @@ var init_adapter14 = __esm(() => {
346964
347780
  VALUED_TOC_SWITCHES = new Set(["\\o", "\\n", "\\p", "\\f", "\\l"]);
346965
347781
  });
346966
347782
 
346967
- // ../../../v2/document-api-v2-adapter/dist/formatting/paragraph-property-order.js
346968
- function setParagraphPropertyChild(children2, localName2, xml) {
346969
- const parsed = parseSingleElement(xml);
346970
- const existingIndex = children2.findIndex((child) => child.localName === localName2);
346971
- if (existingIndex >= 0) {
346972
- const next = [...children2];
346973
- next[existingIndex] = parsed;
346974
- return next;
346975
- }
346976
- const targetRank = PARAGRAPH_PROPERTY_CHILD_RANK.get(localName2);
346977
- if (targetRank == null)
346978
- throw new Error(`Unknown paragraph property child: ${localName2}`);
346979
- let insertionIndex = 0;
346980
- for (const [index2, child] of children2.entries()) {
346981
- const childRank = paragraphPropertyRankRange(child);
346982
- if (!childRank)
346983
- continue;
346984
- if (childRank.minimum > targetRank) {
346985
- return [...children2.slice(0, index2), parsed, ...children2.slice(index2)];
346986
- }
346987
- if (childRank.maximum >= targetRank) {
346988
- throw new ParagraphPropertyMutationUnavailableError(`Cannot safely insert w:${localName2} within mc:AlternateContent paragraph properties`);
346989
- }
346990
- insertionIndex = index2 + 1;
346991
- }
346992
- return [...children2.slice(0, insertionIndex), parsed, ...children2.slice(insertionIndex)];
346993
- }
346994
- function paragraphPropertyRankRange(child) {
346995
- const directRank = PARAGRAPH_PROPERTY_CHILD_RANK.get(child.localName);
346996
- if (directRank != null)
346997
- return { minimum: directRank, maximum: directRank };
346998
- if (child.localName !== "AlternateContent")
346999
- return null;
347000
- const alternateContent = parseContainerXml(child.xml, "AlternateContent");
347001
- if (!alternateContent)
347002
- return null;
347003
- const ranks = parseTopLevelChildren(alternateContent.inner).flatMap((branch) => {
347004
- if (branch.localName !== "Choice" && branch.localName !== "Fallback")
347005
- return [];
347006
- const branchContainer = parseContainerXml(branch.xml, branch.localName);
347007
- if (!branchContainer)
347008
- return [];
347009
- return parseTopLevelChildren(branchContainer.inner).flatMap((candidate2) => {
347010
- const range = paragraphPropertyRankRange(candidate2);
347011
- return range ? [range.minimum, range.maximum] : [];
347012
- });
347013
- });
347014
- if (ranks.length === 0)
347015
- return null;
347016
- return { minimum: Math.min(...ranks), maximum: Math.max(...ranks) };
347017
- }
347018
- var PARAGRAPH_PROPERTY_CHILD_ORDER, PARAGRAPH_PROPERTY_CHILD_RANK, ParagraphPropertyMutationUnavailableError;
347019
- var init_paragraph_property_order = __esm(() => {
347020
- init_common();
347021
- PARAGRAPH_PROPERTY_CHILD_ORDER = [
347022
- "pStyle",
347023
- "keepNext",
347024
- "keepLines",
347025
- "pageBreakBefore",
347026
- "framePr",
347027
- "widowControl",
347028
- "numPr",
347029
- "suppressLineNumbers",
347030
- "pBdr",
347031
- "shd",
347032
- "tabs",
347033
- "suppressAutoHyphens",
347034
- "kinsoku",
347035
- "wordWrap",
347036
- "overflowPunct",
347037
- "topLinePunct",
347038
- "autoSpaceDE",
347039
- "autoSpaceDN",
347040
- "bidi",
347041
- "adjustRightInd",
347042
- "snapToGrid",
347043
- "spacing",
347044
- "ind",
347045
- "contextualSpacing",
347046
- "mirrorIndents",
347047
- "suppressOverlap",
347048
- "jc",
347049
- "textDirection",
347050
- "textAlignment",
347051
- "textboxTightWrap",
347052
- "outlineLvl",
347053
- "divId",
347054
- "cnfStyle",
347055
- "rPr",
347056
- "sectPr",
347057
- "pPrChange"
347058
- ];
347059
- PARAGRAPH_PROPERTY_CHILD_RANK = new Map(PARAGRAPH_PROPERTY_CHILD_ORDER.map((name, index2) => [name, index2]));
347060
- ParagraphPropertyMutationUnavailableError = class ParagraphPropertyMutationUnavailableError extends Error {
347061
- constructor(message) {
347062
- super(message);
347063
- this.name = "ParagraphPropertyMutationUnavailableError";
347064
- }
347065
- };
347066
- });
347067
-
347068
347783
  // ../../../v2/document-api-v2-adapter/dist/formatting/paragraph.js
347069
347784
  function classifyParagraphNodeType(input) {
347070
347785
  if (input.headingLevel > 0)