@stll/folio-core 0.58.5 → 0.60.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/README.md +10 -1
  2. package/dist/ai-edits/apply.d.ts +11 -12
  3. package/dist/ai-edits/apply.js +179 -168
  4. package/dist/ai-edits/headless.d.ts +15 -13
  5. package/dist/ai-edits/headless.js +40 -13
  6. package/dist/ai-edits/index.d.ts +3 -3
  7. package/dist/ai-edits/newListNumbering.d.ts +3 -9
  8. package/dist/ai-edits/newListNumbering.js +36 -41
  9. package/dist/ai-edits/referenceClassification.d.ts +22 -0
  10. package/dist/ai-edits/referenceClassification.js +21 -0
  11. package/dist/ai-edits/snapshot.js +39 -40
  12. package/dist/ai-edits/types.d.ts +24 -32
  13. package/dist/compare/column-alignment.d.ts +4 -4
  14. package/dist/compare/compare.d.ts +3 -7
  15. package/dist/compare/compare.js +25 -27
  16. package/dist/compare/content-alignment.d.ts +9 -9
  17. package/dist/compare/content-types.d.ts +23 -10
  18. package/dist/compare/content-types.js +14 -0
  19. package/dist/compare/content.d.ts +16 -17
  20. package/dist/compare/content.js +30 -7
  21. package/dist/compare/formatting.d.ts +3 -3
  22. package/dist/compare/import-style-closure.d.ts +22 -0
  23. package/dist/compare/import-style-closure.js +33 -0
  24. package/dist/compare/inserted-resource-snapshot.d.ts +15 -0
  25. package/dist/compare/inserted-resource-snapshot.js +63 -0
  26. package/dist/compare/plan.js +20 -13
  27. package/dist/compare/scenario.js +12 -2
  28. package/dist/compare/style-resources.d.ts +8 -2
  29. package/dist/compare/style-resources.js +63 -14
  30. package/dist/compare/verification.d.ts +15 -3
  31. package/dist/compare/verification.js +47 -8
  32. package/dist/compat/eigenpal.d.ts +5 -5
  33. package/dist/compat/eigenpal.js +2 -2
  34. package/dist/controller/canonicalListRendering.js +13 -22
  35. package/dist/controller/canonicalPublicOperations.js +1 -1
  36. package/dist/controller/canonicalSession.js +3 -2
  37. package/dist/controller/canonicalStructure.js +55 -28
  38. package/dist/controller/fontReadiness.js +1 -1
  39. package/dist/controller/layoutPipeline.js +7 -1
  40. package/dist/controller/layoutSession.d.ts +2 -0
  41. package/dist/display-list/build/fontTable.js +7 -5
  42. package/dist/display-list/build/furniture.d.ts +1 -0
  43. package/dist/display-list/build/furniture.js +1 -0
  44. package/dist/display-list/build/watermarkPrimitives.d.ts +2 -1
  45. package/dist/display-list/build/watermarkPrimitives.js +9 -3
  46. package/dist/display-list/editor/pageRenderer.js +1 -0
  47. package/dist/document-operations.d.ts +4 -9
  48. package/dist/document-operations.js +45 -41
  49. package/dist/docx/attributeRemainder.d.ts +1 -1
  50. package/dist/docx/bookmarkIdNormalization.d.ts +10 -0
  51. package/dist/docx/bookmarkIdNormalization.js +100 -0
  52. package/dist/docx/bookmarkParser.js +4 -2
  53. package/dist/docx/importedIdCollisions.d.ts +136 -0
  54. package/dist/docx/importedIdCollisions.js +215 -0
  55. package/dist/docx/index.d.ts +1 -1
  56. package/dist/docx/listMarkerComputation.js +9 -14
  57. package/dist/docx/listTemplate.d.ts +22 -0
  58. package/dist/docx/listTemplate.js +40 -0
  59. package/dist/docx/numberingParser.js +4 -4
  60. package/dist/docx/numberingReferenceNormalization.js +3 -3
  61. package/dist/docx/paragraphParser.js +3 -4
  62. package/dist/docx/paragraphPropertySource.js +1 -2
  63. package/dist/docx/parseContext.d.ts +2 -1
  64. package/dist/docx/parseContext.js +1 -0
  65. package/dist/docx/parseWarningMessage.js +1 -0
  66. package/dist/docx/parser.js +5 -1
  67. package/dist/docx/relsParser.js +1 -1
  68. package/dist/docx/rezip.js +4 -3
  69. package/dist/docx/selectedXmlIdentityScan.d.ts +10 -0
  70. package/dist/docx/selectedXmlIdentityScan.js +36 -0
  71. package/dist/docx/selectiveSave.js +5 -4
  72. package/dist/docx/selectiveXmlPatch.js +44 -52
  73. package/dist/docx/serializer/commentSerializer.d.ts +3 -1
  74. package/dist/docx/serializer/commentSerializer.js +11 -2
  75. package/dist/docx/serializer/runSerializer.js +2 -2
  76. package/dist/docx/serializer/trackedChangeAttributes.d.ts +1 -3
  77. package/dist/docx/serializer/trackedChangeAttributes.js +1 -11
  78. package/dist/docx/server/materializeYjsDocx.js +2 -2
  79. package/dist/docx/server/migrateYjsAttrSchema.js +5 -5
  80. package/dist/fonts/embeddedFontFingerprint.d.ts +5 -0
  81. package/dist/fonts/embeddedFontFingerprint.js +18 -0
  82. package/dist/fonts/embeddedFonts.d.ts +1 -1
  83. package/dist/fonts/embeddedFonts.js +1 -1
  84. package/dist/fonts/headlessMeasure.js +0 -0
  85. package/dist/generated/text_shaper.js +8 -4
  86. package/dist/generated/text_shaper_bg.wasm +0 -0
  87. package/dist/headless-layout.js +1 -0
  88. package/dist/index.d.ts +5 -5
  89. package/dist/index.js +2 -2
  90. package/dist/internal/paragraphFormattingSerialization.d.ts +1 -8
  91. package/dist/internal/paragraphFormattingSerialization.js +6 -20
  92. package/dist/layout-bridge/convert/flowConversionShared.d.ts +3 -1
  93. package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -1
  94. package/dist/layout-bridge/convert/footnoteLayout.js +3 -0
  95. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
  96. package/dist/layout-bridge/convert/headerFooterLayout.js +2 -0
  97. package/dist/layout-bridge/convert/listMarkers.d.ts +1 -2
  98. package/dist/layout-bridge/convert/listMarkers.js +3 -11
  99. package/dist/layout-bridge/convert/paragraphAttrs.d.ts +1 -1
  100. package/dist/layout-bridge/convert/paragraphAttrs.js +8 -4
  101. package/dist/layout-bridge/convert/paragraphConversion.js +8 -1
  102. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +2 -1
  103. package/dist/layout-bridge/convert/toFlowBlocks.js +27 -2
  104. package/dist/layout-engine/measure/cache.js +39 -7
  105. package/dist/layout-engine/measure/lineTypography.js +1 -0
  106. package/dist/layout-engine/measure/listMarkerWidth.d.ts +1 -0
  107. package/dist/layout-engine/measure/listMarkerWidth.js +1 -0
  108. package/dist/layout-engine/measure/measureContainer.js +3 -4
  109. package/dist/layout-engine/measure/measureHelpers.d.ts +6 -9
  110. package/dist/layout-engine/measure/measureHelpers.js +21 -18
  111. package/dist/layout-engine/measure/measureParagraph.js +2 -0
  112. package/dist/layout-engine/measure/measureTypes.d.ts +2 -0
  113. package/dist/layout-engine/types.d.ts +4 -1
  114. package/dist/layout-painter/renderPage.d.ts +1 -0
  115. package/dist/layout-painter/renderPage.js +11 -3
  116. package/dist/layout-painter/renderParagraph.js +13 -3
  117. package/dist/layout-painter/renderWatermark.d.ts +1 -0
  118. package/dist/layout-painter/renderWatermark.js +7 -3
  119. package/dist/managers/editorShortcuts.d.ts +2 -1
  120. package/dist/managers/editorShortcuts.js +2 -1
  121. package/dist/markdown/renderParagraph.js +29 -3
  122. package/dist/prosemirror/canonicalSelectionRange.d.ts +4 -1
  123. package/dist/prosemirror/canonicalSelectionRange.js +9 -3
  124. package/dist/prosemirror/commands/comments.js +5 -32
  125. package/dist/prosemirror/commands/paragraphBookmarkJoin.d.ts +7 -1
  126. package/dist/prosemirror/commands/paragraphBookmarkJoin.js +35 -1
  127. package/dist/prosemirror/commands/propertyChangeScope.js +6 -0
  128. package/dist/prosemirror/commands/resolveParagraphProperties.js +10 -5
  129. package/dist/prosemirror/conversion/fromProseDoc.js +23 -9
  130. package/dist/prosemirror/conversion/toProseDoc.js +31 -7
  131. package/dist/prosemirror/extensions/core/ParagraphExtension.js +29 -14
  132. package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.d.ts +8 -2
  133. package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +39 -3
  134. package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.d.ts +8 -2
  135. package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +4 -3
  136. package/dist/prosemirror/extensions/features/ImageDragExtension.js +4 -3
  137. package/dist/prosemirror/extensions/features/JoinedRunStyleExtension.js +4 -3
  138. package/dist/prosemirror/extensions/features/ListExtension.js +51 -21
  139. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +9 -3
  140. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +6 -5
  141. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +8 -2
  142. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +11 -3
  143. package/dist/prosemirror/extensions/marks/RunIdentityExtension.js +4 -3
  144. package/dist/prosemirror/extensions/marks/markUtils.js +1 -1
  145. package/dist/prosemirror/listInstanceReferences.js +21 -15
  146. package/dist/prosemirror/listLabels.d.ts +4 -3
  147. package/dist/prosemirror/listLabels.js +18 -51
  148. package/dist/prosemirror/listMarker.d.ts +2 -19
  149. package/dist/prosemirror/listMarker.js +28 -57
  150. package/dist/prosemirror/listNumbering.js +16 -6
  151. package/dist/prosemirror/listRendering.d.ts +4 -3
  152. package/dist/prosemirror/listRendering.js +22 -3
  153. package/dist/prosemirror/listRenderingAttrs.d.ts +2 -1
  154. package/dist/prosemirror/listRenderingAttrs.js +6 -11
  155. package/dist/prosemirror/numberedRefFields.js +9 -5
  156. package/dist/prosemirror/numberingAttr.d.ts +19 -1
  157. package/dist/prosemirror/numberingAttr.js +16 -2
  158. package/dist/prosemirror/paragraphIndentation.js +5 -2
  159. package/dist/prosemirror/paragraphMarkJoin.js +17 -3
  160. package/dist/prosemirror/paragraphPropertyCarry.js +5 -6
  161. package/dist/prosemirror/pluginKeyOwner.d.ts +13 -0
  162. package/dist/prosemirror/pluginKeyOwner.js +35 -0
  163. package/dist/prosemirror/plugins/aiCitationDecorations.d.ts +11 -4
  164. package/dist/prosemirror/plugins/aiCitationDecorations.js +16 -3
  165. package/dist/prosemirror/plugins/aiSuggestionDecorations.d.ts +11 -4
  166. package/dist/prosemirror/plugins/aiSuggestionDecorations.js +18 -3
  167. package/dist/prosemirror/plugins/anonymizationDecorations.d.ts +11 -11
  168. package/dist/prosemirror/plugins/anonymizationDecorations.js +23 -13
  169. package/dist/prosemirror/plugins/autocompleteSuggestion.d.ts +8 -2
  170. package/dist/prosemirror/plugins/autocompleteSuggestion.js +27 -5
  171. package/dist/prosemirror/plugins/contentControlWidgets.d.ts +8 -2
  172. package/dist/prosemirror/plugins/contentControlWidgets.js +4 -3
  173. package/dist/prosemirror/plugins/createDocScanPlugin.d.ts +6 -5
  174. package/dist/prosemirror/plugins/createDocScanPlugin.js +1 -1
  175. package/dist/prosemirror/plugins/documentNumbering.js +5 -3
  176. package/dist/prosemirror/plugins/documentStyleState.d.ts +8 -2
  177. package/dist/prosemirror/plugins/documentStyleState.js +2 -2
  178. package/dist/prosemirror/plugins/documentStyles.js +1 -1
  179. package/dist/prosemirror/plugins/selectionTracker.d.ts +8 -2
  180. package/dist/prosemirror/plugins/selectionTracker.js +4 -3
  181. package/dist/prosemirror/plugins/suggestionMode.d.ts +8 -2
  182. package/dist/prosemirror/plugins/suggestionMode.js +4 -3
  183. package/dist/prosemirror/plugins/templateDirectives.d.ts +8 -2
  184. package/dist/prosemirror/plugins/templateDirectives.js +19 -4
  185. package/dist/prosemirror/plugins/templatePreviewValues.d.ts +8 -2
  186. package/dist/prosemirror/plugins/templatePreviewValues.js +27 -5
  187. package/dist/prosemirror/plugins/templateSlashMenu.d.ts +8 -2
  188. package/dist/prosemirror/plugins/templateSlashMenu.js +23 -5
  189. package/dist/prosemirror/plugins/transactionInvariants.js +29 -5
  190. package/dist/prosemirror/schema/nodes.d.ts +2 -1
  191. package/dist/prosemirror/selectionState.js +5 -1
  192. package/dist/prosemirror/storyListNumbering.js +11 -12
  193. package/dist/prosemirror/styles/paragraphStyleCascade.js +2 -6
  194. package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +11 -4
  195. package/dist/prosemirror/styles/resolvedStyleAttrs.js +28 -18
  196. package/dist/prosemirror/yjsDocumentMetadata.d.ts +9 -3
  197. package/dist/prosemirror/yjsDocumentMetadata.js +42 -10
  198. package/dist/redline.d.ts +17 -1
  199. package/dist/redline.js +118 -57
  200. package/dist/server.d.ts +3 -3
  201. package/dist/server.js +2 -2
  202. package/dist/utils/fontLoader.d.ts +2 -2
  203. package/dist/utils/fontLoader.js +2 -7
  204. package/dist/utils/fontResolver.d.ts +7 -3
  205. package/dist/utils/fontResolver.js +6 -8
  206. package/dist/version-comparison.d.ts +1 -2
  207. package/dist/version-comparison.js +1 -2
  208. package/package.json +26 -9
@@ -1,13 +1,13 @@
1
1
  import { applyFolioAIEditOperations, previewFolioAIEditOperationsWithResult } from "./ai-edits/apply.js";
2
2
  import { describeModelError, findIntroducedModelErrors } from "./ai-edits/result-validation.js";
3
3
  import { LIST_KINDS } from "./docx/listNumberingInstances.js";
4
- import { isNumberingReference } from "./docx/numberingReference.js";
5
4
  import { completeNumberingForDoc } from "./prosemirror/listInstanceReferences.js";
6
5
  import { outlineLevelFromAttrValue } from "./prosemirror/outlineLevelAttr.js";
7
6
  import { getStatedDocumentNumbering } from "./prosemirror/plugins/documentNumbering.js";
8
7
  import { LINE_SPACING_RULE_VALUES, PARAGRAPH_ALIGNMENT_VALUES } from "./types/documentEnumValues.js";
9
8
  import { TaggedError } from "better-result";
10
9
  import { sanitizeXmlCharacters } from "@stll/docx-core";
10
+ import { isNumberingReference, paragraphNumberingReference } from "@stll/docx-core/model";
11
11
  //#region src/document-operations.ts
12
12
  const FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION = 1;
13
13
  /** Direct paragraph-alignment values accepted by the operation contract. */
@@ -210,16 +210,6 @@ const readNonNegativeInteger = (value, key, path) => {
210
210
  if (typeof candidate === "number" && Number.isSafeInteger(candidate) && candidate >= 0) return candidate;
211
211
  return invalidBatch(`${path}.${key}`, "expected a non-negative safe integer");
212
212
  };
213
- /**
214
- * A non-negative integer that may also be cleared. `undefined` is "say
215
- * nothing"; `null` is "there is none", which is a different instruction and
216
- * the one absence alone cannot give.
217
- */
218
- const readClearableNonNegativeInteger = (value, key, path) => {
219
- const candidate = value[key];
220
- if (candidate === void 0) return;
221
- return candidate === null ? null : readNonNegativeInteger(value, key, path);
222
- };
223
213
  const readClearableParagraphAlignment = ({ value, key, path }) => {
224
214
  const candidate = value[key];
225
215
  if (candidate === void 0 || candidate === null) return candidate;
@@ -302,43 +292,64 @@ const readClearableParagraphIndentation = ({ value, key, path }) => {
302
292
  const MAX_NEW_LIST_LEVEL = 8;
303
293
  const LIST_KIND_SET = new Set(LIST_KINDS);
304
294
  const isListKind = (value) => LIST_KIND_SET.has(value);
305
- /** `{ start: "new", kind, level? }`: a list the operation starts. */
295
+ /** `{ kind: "newList", format, level? }`: a list the operation starts. */
306
296
  const readNewListReference = (candidate, numberingPath) => {
307
297
  assertAllowedKeys(candidate, numberingPath, [
308
- "start",
309
298
  "kind",
299
+ "format",
310
300
  "level"
311
301
  ]);
312
- const kind = candidate["kind"];
313
- if (typeof kind !== "string" || !isListKind(kind)) return invalidBatch(`${numberingPath}.kind`, `expected one of ${LIST_KINDS.join(", ")}`);
302
+ const format = candidate["format"];
303
+ if (typeof format !== "string" || !isListKind(format)) return invalidBatch(`${numberingPath}.format`, `expected one of ${LIST_KINDS.join(", ")}`);
314
304
  if (candidate["level"] === void 0) return {
315
- start: "new",
316
- kind
305
+ kind: "newList",
306
+ format
317
307
  };
318
308
  const level = readNonNegativeInteger(candidate, "level", numberingPath);
319
309
  if (level > MAX_NEW_LIST_LEVEL) return invalidBatch(`${numberingPath}.level`, `expected at most ${MAX_NEW_LIST_LEVEL}`);
320
310
  return {
321
- start: "new",
322
- kind,
311
+ kind: "newList",
312
+ format,
323
313
  level
324
314
  };
325
315
  };
326
316
  const readClearableNumbering = ({ value, key, path }) => {
327
317
  const candidate = value[key];
328
- if (candidate === void 0 || candidate === null) return candidate;
318
+ if (candidate === void 0) return void 0;
329
319
  const numberingPath = `${path}.${key}`;
330
- if (!isPlainObject(candidate)) return invalidBatch(numberingPath, "expected an object or null when provided");
331
- if (candidate["start"] !== void 0) {
332
- if (candidate["start"] !== "new") return invalidBatch(`${numberingPath}.start`, "expected \"new\"");
333
- return readNewListReference(candidate, numberingPath);
320
+ if (!isPlainObject(candidate)) return invalidBatch(numberingPath, "expected a numbering object");
321
+ const kind = candidate["kind"];
322
+ if (kind === "none" || kind === "inherit") {
323
+ assertAllowedKeys(candidate, numberingPath, ["kind"]);
324
+ return { kind };
334
325
  }
335
- assertAllowedKeys(candidate, numberingPath, ["numId", "level"]);
336
- const numId = readNonNegativeInteger(candidate, "numId", numberingPath);
337
- if (!isNumberingReference(numId)) return invalidBatch(`${numberingPath}.numId`, "expected a positive integer");
338
- return {
339
- numId,
340
- level: readNonNegativeInteger(candidate, "level", numberingPath)
341
- };
326
+ if (kind === "levelOnly") {
327
+ assertAllowedKeys(candidate, numberingPath, ["kind", "ilvl"]);
328
+ const ilvl = readNonNegativeInteger(candidate, "ilvl", numberingPath);
329
+ if (ilvl > MAX_NEW_LIST_LEVEL) return invalidBatch(`${numberingPath}.ilvl`, `expected at most ${MAX_NEW_LIST_LEVEL}`);
330
+ return {
331
+ kind,
332
+ ilvl
333
+ };
334
+ }
335
+ if (kind === "reference") {
336
+ assertAllowedKeys(candidate, numberingPath, [
337
+ "kind",
338
+ "numId",
339
+ "ilvl"
340
+ ]);
341
+ const numId = readNonNegativeInteger(candidate, "numId", numberingPath);
342
+ if (!isNumberingReference(numId)) return invalidBatch(`${numberingPath}.numId`, "expected a positive integer");
343
+ if (candidate["ilvl"] === void 0) return paragraphNumberingReference({ numId });
344
+ const ilvl = readNonNegativeInteger(candidate, "ilvl", numberingPath);
345
+ if (ilvl > MAX_NEW_LIST_LEVEL) return invalidBatch(`${numberingPath}.ilvl`, `expected at most ${MAX_NEW_LIST_LEVEL}`);
346
+ return paragraphNumberingReference({
347
+ numId,
348
+ ilvl
349
+ });
350
+ }
351
+ if (kind === "newList") return readNewListReference(candidate, numberingPath);
352
+ return invalidBatch(`${numberingPath}.kind`, "expected \"none\", \"inherit\", \"levelOnly\", \"reference\", or \"newList\"");
342
353
  };
343
354
  /**
344
355
  * A rectangular grid of cell texts. Rectangular because a table whose rows
@@ -376,7 +387,6 @@ const readParagraphProperties = ({ value, key, path }) => {
376
387
  assertAllowedKeys(candidate, propertiesPath, [
377
388
  "styleId",
378
389
  "outlineLevel",
379
- "listLevel",
380
390
  "numbering",
381
391
  "alignment",
382
392
  "spacing",
@@ -384,7 +394,6 @@ const readParagraphProperties = ({ value, key, path }) => {
384
394
  ]);
385
395
  const styleId = candidate["styleId"] === null ? null : readOptionalString(candidate, "styleId", propertiesPath);
386
396
  const outlineLevel = readClearableOutlineLevel(candidate, propertiesPath);
387
- const listLevel = readClearableNonNegativeInteger(candidate, "listLevel", propertiesPath);
388
397
  const numbering = readClearableNumbering({
389
398
  value: candidate,
390
399
  key: "numbering",
@@ -405,11 +414,10 @@ const readParagraphProperties = ({ value, key, path }) => {
405
414
  key: "indentation",
406
415
  path: propertiesPath
407
416
  });
408
- if (styleId === void 0 && outlineLevel === void 0 && listLevel === void 0 && numbering === void 0 && alignment === void 0 && spacing === void 0 && indentation === void 0) return invalidBatch(propertiesPath, "expected at least one property to set");
417
+ if (styleId === void 0 && outlineLevel === void 0 && numbering === void 0 && alignment === void 0 && spacing === void 0 && indentation === void 0) return invalidBatch(propertiesPath, "expected at least one property to set");
409
418
  return {
410
419
  ...styleId !== void 0 && { styleId },
411
420
  ...outlineLevel !== void 0 && { outlineLevel },
412
- ...listLevel !== void 0 && { listLevel },
413
421
  ...numbering !== void 0 && { numbering },
414
422
  ...alignment !== void 0 && { alignment },
415
423
  ...spacing !== void 0 && { spacing },
@@ -555,7 +563,6 @@ const OPERATION_KEY_DECISIONS = {
555
563
  indentation: true,
556
564
  lineBreakMode: true,
557
565
  formattingScope: true,
558
- listLevel: true,
559
566
  numbering: true,
560
567
  moveId: true,
561
568
  pageBreakBefore: true,
@@ -573,7 +580,6 @@ const OPERATION_KEY_DECISIONS = {
573
580
  indentation: true,
574
581
  lineBreakMode: true,
575
582
  formattingScope: true,
576
- listLevel: true,
577
583
  numbering: true,
578
584
  moveId: true,
579
585
  pageBreakBefore: true,
@@ -833,7 +839,6 @@ const parseDocumentOperation = (value, index) => {
833
839
  const styleId = value["styleId"] === null ? null : readOptionalString(value, "styleId", path);
834
840
  const outlineLevel = readClearableOutlineLevel(value, path);
835
841
  const moveId = readOptionalString(value, "moveId", path);
836
- const listLevel = readClearableNonNegativeInteger(value, "listLevel", path);
837
842
  const numbering = readClearableNumbering({
838
843
  value,
839
844
  key: "numbering",
@@ -874,7 +879,6 @@ const parseDocumentOperation = (value, index) => {
874
879
  ...indentation !== void 0 && { indentation },
875
880
  ...lineBreakMode !== void 0 && { lineBreakMode },
876
881
  ...formattingScope !== void 0 && { formattingScope },
877
- ...listLevel !== void 0 && { listLevel },
878
882
  ...numbering !== void 0 && { numbering },
879
883
  ...moveId !== void 0 && { moveId },
880
884
  ...pageBreakBefore !== void 0 && { pageBreakBefore },
@@ -1250,7 +1254,7 @@ const inOperationOrder = (operations, skipped) => {
1250
1254
  const indexById = new Map(operations.map(({ id }, index) => [id, index]));
1251
1255
  return [...skipped].sort((left, right) => (indexById.get(left.id) ?? -1) - (indexById.get(right.id) ?? -1));
1252
1256
  };
1253
- const applyFolioDocumentOperations = ({ view, snapshot, batch, story = "main", author, createCommentId, createUndoHandle, revisionStamp, wordDiff, tableTemplates, replacementBackground, undefinedStyles }) => {
1257
+ const applyFolioDocumentOperations = ({ view, snapshot, batch, story = "main", author, createCommentId, createUndoHandle, revisionStamp, wordDiff, tableTemplates, replacementBackground, undefinedReferences }) => {
1254
1258
  const parsedBatch = parseFolioDocumentOperationBatch(batch);
1255
1259
  const isAtomic = parsedBatch.atomic === true;
1256
1260
  const beforeDoc = view.state.doc;
@@ -1265,7 +1269,7 @@ const applyFolioDocumentOperations = ({ view, snapshot, batch, story = "main", a
1265
1269
  ...wordDiff !== void 0 && { wordDiff },
1266
1270
  ...tableTemplates !== void 0 && { tableTemplates },
1267
1271
  ...replacementBackground !== void 0 && { replacementBackground },
1268
- ...undefinedStyles !== void 0 && { undefinedStyles }
1272
+ undefinedReferences
1269
1273
  };
1270
1274
  if (preview) return {
1271
1275
  ...previewFolioAIEditOperationsWithResult({
@@ -1,5 +1,5 @@
1
- import { XmlElement } from "./xmlParser.js";
2
1
  import { ModelledAttributes } from "./propertyElementAttributes.js";
2
+ import { XmlElement } from "./xmlParser.js";
3
3
  import { PreservedAttribute } from "@stll/docx-core/model";
4
4
  //#region src/docx/attributeRemainder.d.ts
5
5
  declare const InvalidPreservedAttributeError_base: import("better-result").TaggedErrorClass<"InvalidPreservedAttributeError">;
@@ -0,0 +1,10 @@
1
+ //#region src/docx/bookmarkIdNormalization.d.ts
2
+ /**
3
+ * Give repeated bookmark ranges independent identities before editor pairing.
4
+ * The first range keeps its id. Ends close starts in encounter order, including
5
+ * overlapping ambiguous ranges. Only colliding ids are repaired: those require
6
+ * unique XML ids for a valid save. Every other source byte stays verbatim.
7
+ */
8
+ declare const normalizeBookmarkIdsInXmlParts: (parts: ReadonlyMap<string, string>) => ReadonlyMap<string, string>;
9
+ //#endregion
10
+ export { normalizeBookmarkIdsInXmlParts };
@@ -0,0 +1,100 @@
1
+ import { scanSelectedStreamingXmlElements } from "./selectedXmlIdentityScan.js";
2
+ import { WORDPROCESSINGML_NAMESPACE_URIS, findAttributeByNamespaceUri, getLocalName, getNamespaceUri } from "./xmlParser.js";
3
+ import { panic } from "better-result";
4
+ //#region src/docx/bookmarkIdNormalization.ts
5
+ const bookmarkIdentity = (element) => {
6
+ if (!WORDPROCESSINGML_NAMESPACE_URIS.has(getNamespaceUri(element) ?? "")) return null;
7
+ const name = getLocalName(element.name);
8
+ if (name !== "bookmarkStart" && name !== "bookmarkEnd") return null;
9
+ const attribute = findAttributeByNamespaceUri(element, WORDPROCESSINGML_NAMESPACE_URIS, "id");
10
+ if (!attribute) return null;
11
+ const id = Number(attribute.value);
12
+ if (!Number.isSafeInteger(id) || id < 0) return null;
13
+ return {
14
+ name,
15
+ attribute: attribute.name,
16
+ id
17
+ };
18
+ };
19
+ /**
20
+ * Give repeated bookmark ranges independent identities before editor pairing.
21
+ * The first range keeps its id. Ends close starts in encounter order, including
22
+ * overlapping ambiguous ranges. Only colliding ids are repaired: those require
23
+ * unique XML ids for a valid save. Every other source byte stays verbatim.
24
+ */
25
+ const normalizeBookmarkIdsInXmlParts = (parts) => {
26
+ const candidates = [...parts].filter(([, xml]) => /bookmark(?:Start|End)/u.test(xml));
27
+ const reserved = /* @__PURE__ */ new Set();
28
+ const repeated = /* @__PURE__ */ new Set();
29
+ const markersByPart = /* @__PURE__ */ new Map();
30
+ for (const [path, xml] of candidates) {
31
+ const starts = /* @__PURE__ */ new Set();
32
+ const markers = [];
33
+ if (scanSelectedStreamingXmlElements(xml, ({ element, attributeValueSpans }) => {
34
+ const marker = bookmarkIdentity(element);
35
+ if (!marker) return;
36
+ const span = attributeValueSpans.get(marker.attribute);
37
+ if (!span) panic("Missing bookmark identity source span");
38
+ markers.push({
39
+ marker,
40
+ ...span
41
+ });
42
+ reserved.add(marker.id);
43
+ if (marker.name === "bookmarkStart") {
44
+ if (starts.has(marker.id)) repeated.add(path);
45
+ starts.add(marker.id);
46
+ }
47
+ }).status === "unsupported") {
48
+ repeated.delete(path);
49
+ continue;
50
+ }
51
+ markersByPart.set(path, markers);
52
+ }
53
+ if (repeated.size === 0) return parts;
54
+ let next = 0;
55
+ const allocate = () => {
56
+ while (reserved.has(next)) next += 1;
57
+ const id = next++;
58
+ reserved.add(id);
59
+ return id;
60
+ };
61
+ const normalized = new Map(parts);
62
+ for (const [path, xml] of candidates) {
63
+ if (!repeated.has(path)) continue;
64
+ const seen = /* @__PURE__ */ new Set();
65
+ const open = /* @__PURE__ */ new Map();
66
+ const chunks = [];
67
+ let cursor = 0;
68
+ for (const { marker, start, end } of markersByPart.get(path) ?? []) {
69
+ let id = marker.id;
70
+ if (marker.name === "bookmarkStart") {
71
+ if (seen.has(id)) id = allocate();
72
+ seen.add(marker.id);
73
+ let queue = open.get(marker.id);
74
+ if (!queue) {
75
+ queue = {
76
+ ids: [],
77
+ cursor: 0
78
+ };
79
+ open.set(marker.id, queue);
80
+ }
81
+ queue.ids.push(id);
82
+ } else {
83
+ const queue = open.get(marker.id);
84
+ const paired = queue?.ids.at(queue.cursor);
85
+ if (paired !== void 0 && queue) {
86
+ id = paired;
87
+ queue.cursor += 1;
88
+ }
89
+ }
90
+ if (id === marker.id) continue;
91
+ chunks.push(xml.slice(cursor, start), String(id));
92
+ cursor = end;
93
+ }
94
+ chunks.push(xml.slice(cursor));
95
+ normalized.set(path, chunks.join(""));
96
+ }
97
+ return normalized;
98
+ };
99
+ //#endregion
100
+ export { normalizeBookmarkIdsInXmlParts };
@@ -31,8 +31,10 @@ function createBookmarkMap() {
31
31
  * @param bookmark - The bookmark start to add
32
32
  */
33
33
  function addBookmark(map, bookmark) {
34
- map.byId.set(bookmark.id, bookmark);
35
- if (bookmark.name) map.byName.set(bookmark.name, bookmark);
34
+ if (!map.byId.has(bookmark.id)) map.byId.set(bookmark.id, bookmark);
35
+ if (bookmark.name) {
36
+ if (!map.byName.has(bookmark.name)) map.byName.set(bookmark.name, bookmark);
37
+ }
36
38
  map.bookmarks.push(bookmark);
37
39
  }
38
40
  /**
@@ -0,0 +1,136 @@
1
+ import { ParseContext } from "./parseContext.js";
2
+ //#region src/docx/importedIdCollisions.d.ts
3
+ /** Definition sites only: paired markers and references never claim an identity. */
4
+ declare const IMPORTED_ID_COLLISION_REGISTRY: {
5
+ readonly bookmark: {
6
+ readonly kind: "bookmark";
7
+ readonly scope: "part";
8
+ readonly sites: readonly [{
9
+ readonly namespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
10
+ readonly elements: Set<string>;
11
+ }];
12
+ readonly attribute: "id";
13
+ readonly attributeNamespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
14
+ readonly encoding: "decimal";
15
+ };
16
+ readonly comment: {
17
+ readonly kind: "comment";
18
+ readonly scope: "part";
19
+ readonly sites: readonly [{
20
+ readonly namespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
21
+ readonly elements: Set<string>;
22
+ }];
23
+ readonly attribute: "id";
24
+ readonly attributeNamespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
25
+ readonly encoding: "decimal";
26
+ };
27
+ readonly footnote: {
28
+ readonly kind: "footnote";
29
+ readonly scope: "part";
30
+ readonly sites: readonly [{
31
+ readonly namespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
32
+ readonly elements: Set<string>;
33
+ }];
34
+ readonly attribute: "id";
35
+ readonly attributeNamespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
36
+ readonly encoding: "decimal";
37
+ };
38
+ readonly endnote: {
39
+ readonly kind: "endnote";
40
+ readonly scope: "part";
41
+ readonly sites: readonly [{
42
+ readonly namespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
43
+ readonly elements: Set<string>;
44
+ }];
45
+ readonly attribute: "id";
46
+ readonly attributeNamespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
47
+ readonly encoding: "decimal";
48
+ };
49
+ readonly revision: {
50
+ readonly kind: "revision";
51
+ readonly scope: "package";
52
+ readonly sites: readonly [{
53
+ readonly namespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
54
+ readonly elements: Set<string>;
55
+ }];
56
+ readonly attribute: "id";
57
+ readonly attributeNamespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
58
+ readonly encoding: "decimal";
59
+ };
60
+ readonly paraId: {
61
+ readonly kind: "paraId";
62
+ readonly scope: "part";
63
+ readonly sites: readonly [{
64
+ readonly namespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
65
+ readonly elements: Set<string>;
66
+ }, {
67
+ readonly namespace: "http://schemas.microsoft.com/office/word/2012/wordml";
68
+ readonly elements: Set<string>;
69
+ }, {
70
+ readonly namespace: string;
71
+ readonly elements: Set<string>;
72
+ }];
73
+ readonly attribute: "paraId";
74
+ readonly attributeNamespace: "http://schemas.microsoft.com/office/word/2010/wordml";
75
+ readonly encoding: "hex";
76
+ };
77
+ readonly textId: {
78
+ readonly kind: "textId";
79
+ readonly scope: "part";
80
+ readonly sites: readonly [{
81
+ readonly namespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
82
+ readonly elements: Set<string>;
83
+ }];
84
+ readonly attribute: "textId";
85
+ readonly attributeNamespace: "http://schemas.microsoft.com/office/word/2010/wordml";
86
+ readonly encoding: "hex";
87
+ };
88
+ readonly numId: {
89
+ readonly kind: "numId";
90
+ readonly scope: "part";
91
+ readonly sites: readonly [{
92
+ readonly namespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
93
+ readonly elements: Set<string>;
94
+ }];
95
+ readonly attribute: "numId";
96
+ readonly attributeNamespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
97
+ readonly encoding: "decimal";
98
+ };
99
+ readonly abstractNumId: {
100
+ readonly kind: "abstractNumId";
101
+ readonly scope: "part";
102
+ readonly sites: readonly [{
103
+ readonly namespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
104
+ readonly elements: Set<string>;
105
+ }];
106
+ readonly attribute: "abstractNumId";
107
+ readonly attributeNamespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
108
+ readonly encoding: "decimal";
109
+ };
110
+ readonly drawing: {
111
+ readonly kind: "drawing";
112
+ readonly scope: "package";
113
+ readonly sites: readonly [{
114
+ readonly namespace: "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing";
115
+ readonly elements: Set<string>;
116
+ }];
117
+ readonly attribute: "id";
118
+ readonly attributeNamespace: null;
119
+ readonly encoding: "decimal";
120
+ };
121
+ readonly relationship: {
122
+ readonly kind: "relationship";
123
+ readonly scope: "part";
124
+ readonly sites: readonly [{
125
+ readonly namespace: "http://schemas.openxmlformats.org/package/2006/relationships";
126
+ readonly elements: Set<string>;
127
+ }];
128
+ readonly attribute: "Id";
129
+ readonly attributeNamespace: null;
130
+ readonly encoding: "string";
131
+ };
132
+ };
133
+ /** Reports repeated source definitions without changing the package or choosing a winner. */
134
+ declare const diagnoseImportedIdCollisions: (parts: ReadonlyMap<string, string>, context: ParseContext) => void;
135
+ //#endregion
136
+ export { IMPORTED_ID_COLLISION_REGISTRY, diagnoseImportedIdCollisions };
@@ -0,0 +1,215 @@
1
+ import { paraIdAttribute, textIdAttribute } from "./paraIdAttribute.js";
2
+ import { REVISION_ELEMENT_NAMES } from "./revisionIdNormalization.js";
3
+ import { scanSelectedStreamingXmlElements } from "./selectedXmlIdentityScan.js";
4
+ import { OOXML_NAMESPACES } from "./serializer/partNamespaces.js";
5
+ import { toTransitionalNamespaceUri } from "./transitionalSpelling.js";
6
+ import { resolveNamespaceUri } from "./xmlNamespaceContext.js";
7
+ import { NAMESPACES, getLocalName, getNamespaceUri } from "./xmlParser.js";
8
+ import { panic } from "better-result";
9
+ import { IMPORTED_ID_COLLISION_KINDS, PARSE_WARNING_CODES } from "@stll/docx-core/model";
10
+ //#region src/docx/importedIdCollisions.ts
11
+ const WORD_2010_NAMESPACE = "http://schemas.microsoft.com/office/word/2010/wordml";
12
+ const PACKAGE_RELATIONSHIP_NAMESPACE = "http://schemas.openxmlformats.org/package/2006/relationships";
13
+ const paragraphIdentityForKind = (kind, element) => {
14
+ switch (kind) {
15
+ case IMPORTED_ID_COLLISION_KINDS.paraId: return paraIdAttribute(element);
16
+ case IMPORTED_ID_COLLISION_KINDS.textId: return textIdAttribute(element);
17
+ default: return;
18
+ }
19
+ };
20
+ /** Definition sites only: paired markers and references never claim an identity. */
21
+ const IMPORTED_ID_COLLISION_REGISTRY = {
22
+ bookmark: {
23
+ kind: IMPORTED_ID_COLLISION_KINDS.bookmark,
24
+ scope: "part",
25
+ sites: [{
26
+ namespace: NAMESPACES.w,
27
+ elements: /* @__PURE__ */ new Set(["bookmarkStart"])
28
+ }],
29
+ attribute: "id",
30
+ attributeNamespace: NAMESPACES.w,
31
+ encoding: "decimal"
32
+ },
33
+ comment: {
34
+ kind: IMPORTED_ID_COLLISION_KINDS.comment,
35
+ scope: "part",
36
+ sites: [{
37
+ namespace: NAMESPACES.w,
38
+ elements: /* @__PURE__ */ new Set(["comment"])
39
+ }],
40
+ attribute: "id",
41
+ attributeNamespace: NAMESPACES.w,
42
+ encoding: "decimal"
43
+ },
44
+ footnote: {
45
+ kind: IMPORTED_ID_COLLISION_KINDS.footnote,
46
+ scope: "part",
47
+ sites: [{
48
+ namespace: NAMESPACES.w,
49
+ elements: /* @__PURE__ */ new Set(["footnote"])
50
+ }],
51
+ attribute: "id",
52
+ attributeNamespace: NAMESPACES.w,
53
+ encoding: "decimal"
54
+ },
55
+ endnote: {
56
+ kind: IMPORTED_ID_COLLISION_KINDS.endnote,
57
+ scope: "part",
58
+ sites: [{
59
+ namespace: NAMESPACES.w,
60
+ elements: /* @__PURE__ */ new Set(["endnote"])
61
+ }],
62
+ attribute: "id",
63
+ attributeNamespace: NAMESPACES.w,
64
+ encoding: "decimal"
65
+ },
66
+ revision: {
67
+ kind: IMPORTED_ID_COLLISION_KINDS.revision,
68
+ scope: "package",
69
+ sites: [{
70
+ namespace: NAMESPACES.w,
71
+ elements: REVISION_ELEMENT_NAMES
72
+ }],
73
+ attribute: "id",
74
+ attributeNamespace: NAMESPACES.w,
75
+ encoding: "decimal"
76
+ },
77
+ paraId: {
78
+ kind: IMPORTED_ID_COLLISION_KINDS.paraId,
79
+ scope: "part",
80
+ sites: [
81
+ {
82
+ namespace: NAMESPACES.w,
83
+ elements: /* @__PURE__ */ new Set(["p"])
84
+ },
85
+ {
86
+ namespace: NAMESPACES.w15,
87
+ elements: /* @__PURE__ */ new Set(["commentEx"])
88
+ },
89
+ {
90
+ namespace: OOXML_NAMESPACES.w16cex.uri,
91
+ elements: /* @__PURE__ */ new Set(["comment"])
92
+ }
93
+ ],
94
+ attribute: "paraId",
95
+ attributeNamespace: WORD_2010_NAMESPACE,
96
+ encoding: "hex"
97
+ },
98
+ textId: {
99
+ kind: IMPORTED_ID_COLLISION_KINDS.textId,
100
+ scope: "part",
101
+ sites: [{
102
+ namespace: NAMESPACES.w,
103
+ elements: /* @__PURE__ */ new Set(["p"])
104
+ }],
105
+ attribute: "textId",
106
+ attributeNamespace: WORD_2010_NAMESPACE,
107
+ encoding: "hex"
108
+ },
109
+ numId: {
110
+ kind: IMPORTED_ID_COLLISION_KINDS.numId,
111
+ scope: "part",
112
+ sites: [{
113
+ namespace: NAMESPACES.w,
114
+ elements: /* @__PURE__ */ new Set(["num"])
115
+ }],
116
+ attribute: "numId",
117
+ attributeNamespace: NAMESPACES.w,
118
+ encoding: "decimal"
119
+ },
120
+ abstractNumId: {
121
+ kind: IMPORTED_ID_COLLISION_KINDS.abstractNumId,
122
+ scope: "part",
123
+ sites: [{
124
+ namespace: NAMESPACES.w,
125
+ elements: /* @__PURE__ */ new Set(["abstractNum"])
126
+ }],
127
+ attribute: "abstractNumId",
128
+ attributeNamespace: NAMESPACES.w,
129
+ encoding: "decimal"
130
+ },
131
+ drawing: {
132
+ kind: IMPORTED_ID_COLLISION_KINDS.drawing,
133
+ scope: "package",
134
+ sites: [{
135
+ namespace: NAMESPACES.wp,
136
+ elements: /* @__PURE__ */ new Set(["docPr"])
137
+ }],
138
+ attribute: "id",
139
+ attributeNamespace: null,
140
+ encoding: "decimal"
141
+ },
142
+ relationship: {
143
+ kind: IMPORTED_ID_COLLISION_KINDS.relationship,
144
+ scope: "part",
145
+ sites: [{
146
+ namespace: PACKAGE_RELATIONSHIP_NAMESPACE,
147
+ elements: /* @__PURE__ */ new Set(["Relationship"])
148
+ }],
149
+ attribute: "Id",
150
+ attributeNamespace: null,
151
+ encoding: "string"
152
+ }
153
+ };
154
+ const normalizedIdentity = (value, encoding) => {
155
+ if (encoding === "string") return value;
156
+ if (encoding === "hex") return /^[0-9a-f]{8}$/iu.test(value) ? value.toUpperCase() : void 0;
157
+ const spelling = value.trim();
158
+ if (!/^[+-]?\d+$/u.test(spelling)) return void 0;
159
+ const digits = spelling.replace(/^[+-]?0*/u, "");
160
+ return digits === "" ? "0" : `${spelling.startsWith("-") ? "-" : ""}${digits}`;
161
+ };
162
+ /** Reports repeated source definitions without changing the package or choosing a winner. */
163
+ const diagnoseImportedIdCollisions = (parts, context) => {
164
+ const rules = Object.values(IMPORTED_ID_COLLISION_REGISTRY);
165
+ const packageSeen = /* @__PURE__ */ new Map();
166
+ for (const [part, xml] of parts) {
167
+ const partSeen = /* @__PURE__ */ new Map();
168
+ const scoped = context.scoped({ part });
169
+ scanSelectedStreamingXmlElements(xml, ({ element, attributeValueSpans }) => {
170
+ if (element.name === void 0) return;
171
+ const namespace = toTransitionalNamespaceUri(getNamespaceUri(element) ?? "");
172
+ const localName = getLocalName(element.name);
173
+ for (const rule of rules) {
174
+ const kind = rule.kind;
175
+ if (!rule.sites.some((site) => namespace === site.namespace && site.elements.has(localName))) continue;
176
+ const paragraphIdentity = paragraphIdentityForKind(kind, element);
177
+ const seen = rule.scope === "package" ? packageSeen : partSeen;
178
+ for (const [name, rawValue] of Object.entries(element.attributes ?? {})) {
179
+ if (getLocalName(name) !== rule.attribute || rawValue === void 0) continue;
180
+ const colon = name.indexOf(":");
181
+ const attributeNamespace = colon < 0 ? null : toTransitionalNamespaceUri(resolveNamespaceUri(element.namespaceScope, name.slice(0, colon)) ?? "");
182
+ if (rule.encoding === "hex") {
183
+ if (String(rawValue) !== paragraphIdentity) continue;
184
+ } else if (attributeNamespace !== rule.attributeNamespace) continue;
185
+ const value = String(rawValue);
186
+ const identity = normalizedIdentity(value, rule.encoding);
187
+ if (identity === void 0) continue;
188
+ const key = `${kind}:${identity}`;
189
+ const span = attributeValueSpans.get(name);
190
+ if (span === void 0) panic("Missing imported identity source span");
191
+ const offset = span.start;
192
+ const first = seen.get(key);
193
+ if (first === void 0) {
194
+ seen.set(key, {
195
+ part,
196
+ offset
197
+ });
198
+ break;
199
+ }
200
+ scoped.warn({
201
+ code: PARSE_WARNING_CODES.duplicateImportedId,
202
+ identityKind: kind,
203
+ element: element.name,
204
+ at: `offset ${offset}`,
205
+ value,
206
+ detail: `${kind} identity repeats the definition at offset ${first.offset} in ${first.part}.`
207
+ });
208
+ break;
209
+ }
210
+ }
211
+ });
212
+ }
213
+ };
214
+ //#endregion
215
+ export { IMPORTED_ID_COLLISION_REGISTRY, diagnoseImportedIdCollisions };