@stll/folio-core 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/dist/ai-edits/apply.js +602 -50
  2. package/dist/ai-edits/block-identity.d.ts +4 -0
  3. package/dist/ai-edits/block-identity.js +9 -0
  4. package/dist/ai-edits/blockRange.d.ts +28 -1
  5. package/dist/ai-edits/blockRange.js +67 -1
  6. package/dist/ai-edits/headless.d.ts +4 -4
  7. package/dist/ai-edits/headless.js +9 -9
  8. package/dist/ai-edits/index.d.ts +2 -2
  9. package/dist/ai-edits/index.js +2 -2
  10. package/dist/ai-edits/read.d.ts +7 -7
  11. package/dist/ai-edits/read.js +110 -3
  12. package/dist/ai-edits/table-cell-mutations.d.ts +48 -0
  13. package/dist/ai-edits/table-cell-mutations.js +237 -0
  14. package/dist/ai-edits/table-mutation-plan.d.ts +38 -0
  15. package/dist/ai-edits/table-mutation-plan.js +90 -0
  16. package/dist/ai-edits/table-row-column-mutations.d.ts +100 -0
  17. package/dist/ai-edits/table-row-column-mutations.js +300 -0
  18. package/dist/ai-edits/table-targets.d.ts +32 -0
  19. package/dist/ai-edits/table-targets.js +70 -0
  20. package/dist/ai-edits/types.d.ts +34 -0
  21. package/dist/compat/eigenpal.js +1 -1
  22. package/dist/content-controls/mutateContentControls.js +1 -1
  23. package/dist/controller/activeEditorStory.d.ts +36 -0
  24. package/dist/controller/activeEditorStory.js +30 -0
  25. package/dist/controller/contentControlWidgetController.d.ts +55 -0
  26. package/dist/controller/contentControlWidgetController.js +141 -0
  27. package/dist/controller/fontReadiness.js +2 -0
  28. package/dist/controller/headerFooterEditorManager.js +1 -1
  29. package/dist/controller/hiddenEditorApi.js +2 -2
  30. package/dist/controller/hiddenEditorManager.d.ts +12 -1
  31. package/dist/controller/hiddenEditorManager.js +32 -11
  32. package/dist/controller/layoutPipeline.d.ts +2 -0
  33. package/dist/controller/layoutPipeline.js +16 -1
  34. package/dist/controller/noteEditorManager.d.ts +36 -0
  35. package/dist/controller/noteEditorManager.js +210 -0
  36. package/dist/document-operations.d.ts +35 -3
  37. package/dist/document-operations.js +161 -3
  38. package/dist/docx/blockContentParser.js +2 -2
  39. package/dist/docx/commentParser.js +6 -1
  40. package/dist/docx/conformance.js +8 -1
  41. package/dist/docx/documentGrid.d.ts +8 -0
  42. package/dist/docx/documentGrid.js +8 -0
  43. package/dist/docx/drawingUtils.js +1 -1
  44. package/dist/docx/ensureParaIds.js +1 -1
  45. package/dist/docx/fieldParser.js +1 -1
  46. package/dist/docx/notePropertiesParser.js +1 -1
  47. package/dist/docx/numberingParser.js +1 -1
  48. package/dist/docx/paragraphParser.js +63 -58
  49. package/dist/docx/paragraphTextBoxEnrichment.d.ts +2 -1
  50. package/dist/docx/paragraphTextBoxEnrichment.js +67 -13
  51. package/dist/docx/paragraphTraversal.js +1 -1
  52. package/dist/docx/parser.js +3 -3
  53. package/dist/docx/rezip.js +1 -1
  54. package/dist/docx/runParser.js +4 -2
  55. package/dist/docx/sdtProperties.js +1 -1
  56. package/dist/docx/sectionParser.js +1 -1
  57. package/dist/docx/selectiveSave.js +1 -1
  58. package/dist/docx/serializer/commentSerializer.js +1 -2
  59. package/dist/docx/serializer/documentSerializer.js +2 -2
  60. package/dist/docx/serializer/headerFooterSerializer.js +2 -2
  61. package/dist/docx/serializer/noteSerializer.js +2 -2
  62. package/dist/docx/serializer/paragraphSerializer.js +7 -1
  63. package/dist/docx/serializer/runSerializer.js +4 -2
  64. package/dist/docx/serializer/stylesSerializer.js +1 -1
  65. package/dist/docx/serializer/tableSerializer.d.ts +5 -4
  66. package/dist/docx/serializer/tableSerializer.js +17 -13
  67. package/dist/docx/server/applyDocxXmlPatchProposal.d.ts +87 -0
  68. package/dist/docx/server/applyDocxXmlPatchProposal.js +204 -0
  69. package/dist/docx/server/boundedArchive.d.ts +14 -3
  70. package/dist/docx/server/boundedArchive.js +56 -11
  71. package/dist/docx/server/evaluateDocxXmlPatchProposal.d.ts +85 -0
  72. package/dist/docx/server/evaluateDocxXmlPatchProposal.js +361 -0
  73. package/dist/docx/server/inspectDocxPackage.d.ts +70 -0
  74. package/dist/docx/server/inspectDocxPackage.js +217 -0
  75. package/dist/docx/server/validateDocxConformance.d.ts +41 -0
  76. package/dist/docx/server/validateDocxConformance.js +336 -0
  77. package/dist/docx/settingsParser.js +11 -1
  78. package/dist/docx/shapeParser.js +1 -1
  79. package/dist/docx/styleParser.js +4 -2
  80. package/dist/docx/tableParser.js +18 -7
  81. package/dist/docx/textBoxParser.d.ts +3 -3
  82. package/dist/docx/textBoxParser.js +16 -12
  83. package/dist/docx/xmlSafety.d.ts +5 -0
  84. package/dist/docx/xmlSafety.js +9 -0
  85. package/dist/fields/resolveFieldValues.js +1 -3
  86. package/dist/i18n/messages/catalogs.gen.d.ts +17 -0
  87. package/dist/i18n/messages/catalogs.gen.js +17 -0
  88. package/dist/i18n/messages/messages.gen.d.ts +1 -0
  89. package/dist/index.js +1 -1
  90. package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
  91. package/dist/layout-bridge/convert/footnoteLayout.js +47 -40
  92. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
  93. package/dist/layout-bridge/convert/headerFooterLayout.js +3 -0
  94. package/dist/layout-bridge/convert/templatePreviewFlow.js +3 -3
  95. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +4 -2
  96. package/dist/layout-bridge/convert/toFlowBlocks.js +136 -20
  97. package/dist/layout-bridge/dom/noteStoryDom.d.ts +6 -0
  98. package/dist/layout-bridge/dom/noteStoryDom.js +17 -0
  99. package/dist/layout-bridge/engine/clickToPosition.js +2 -2
  100. package/dist/layout-engine/index.d.ts +2 -2
  101. package/dist/layout-engine/index.js +43 -28
  102. package/dist/layout-engine/justificationCompatibility.d.ts +6 -0
  103. package/dist/layout-engine/justificationCompatibility.js +8 -0
  104. package/dist/layout-engine/keep-together.js +11 -1
  105. package/dist/layout-engine/measure/cache.js +21 -5
  106. package/dist/layout-engine/measure/lineBreakProvider.js +53 -34
  107. package/dist/layout-engine/measure/measureBlocks.js +6 -3
  108. package/dist/layout-engine/measure/measureContainer.js +1 -1
  109. package/dist/layout-engine/measure/measureHelpers.d.ts +1 -1
  110. package/dist/layout-engine/measure/measureHelpers.js +3 -3
  111. package/dist/layout-engine/measure/measureParagraph.js +69 -25
  112. package/dist/layout-engine/measure/measureProvider.js +4 -3
  113. package/dist/layout-engine/measure/tableCellFlow.js +5 -2
  114. package/dist/layout-engine/measure/textBoxParagraphLayout.d.ts +9 -7
  115. package/dist/layout-engine/measure/textBoxParagraphLayout.js +22 -6
  116. package/dist/layout-engine/measure/textMeasurementPolicy.d.ts +3 -1
  117. package/dist/layout-engine/measure/textMeasurementPolicy.js +7 -1
  118. package/dist/layout-engine/paginator.js +5 -1
  119. package/dist/layout-engine/paragraphSpacing.d.ts +28 -4
  120. package/dist/layout-engine/paragraphSpacing.js +107 -13
  121. package/dist/layout-engine/renderedBreakReconciliation.js +1 -1
  122. package/dist/layout-engine/types.d.ts +26 -13
  123. package/dist/layout-painter/registry/modules/textBox.js +5 -1
  124. package/dist/layout-painter/renderPage.d.ts +5 -2
  125. package/dist/layout-painter/renderPage.js +56 -12
  126. package/dist/layout-painter/renderParagraph.js +22 -6
  127. package/dist/layout-painter/renderTable.d.ts +5 -1
  128. package/dist/layout-painter/renderTable.js +5 -2
  129. package/dist/layout-painter/renderTextBox.d.ts +2 -1
  130. package/dist/layout-painter/renderTextBox.js +25 -14
  131. package/dist/managers/DocumentLoaderManager.js +1 -1
  132. package/dist/model.js +1 -1
  133. package/dist/prosemirror/attrs/index.d.ts +4 -2
  134. package/dist/prosemirror/attrs/index.js +154 -18
  135. package/dist/prosemirror/commands/comments.d.ts +3 -3
  136. package/dist/prosemirror/commands/comments.js +248 -12
  137. package/dist/prosemirror/commands/contentControls.js +1 -1
  138. package/dist/prosemirror/commands/index.js +1 -1
  139. package/dist/prosemirror/commands/pageBreak.js +1 -1
  140. package/dist/prosemirror/commands/propertyChangeScope.d.ts +2 -2
  141. package/dist/prosemirror/commands/propertyChangeScope.js +3 -2
  142. package/dist/prosemirror/commands/tableCellMergeResolution.d.ts +9 -0
  143. package/dist/prosemirror/commands/tableCellMergeResolution.js +181 -0
  144. package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -1
  145. package/dist/prosemirror/conversion/fromProseDoc.js +286 -61
  146. package/dist/prosemirror/conversion/sdtAttrs.d.ts +9 -0
  147. package/dist/prosemirror/conversion/sdtAttrs.js +49 -0
  148. package/dist/prosemirror/conversion/toProseDoc.d.ts +2 -1
  149. package/dist/prosemirror/conversion/toProseDoc.js +347 -98
  150. package/dist/prosemirror/extensions/ExtensionManager.js +1 -1
  151. package/dist/prosemirror/extensions/StarterKit.js +6 -1
  152. package/dist/prosemirror/extensions/core/ParagraphExtension.js +4 -1
  153. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +1 -0
  154. package/dist/prosemirror/extensions/features/ListExtension.js +1 -1
  155. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +10 -1
  156. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +93 -2
  157. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +2 -1
  158. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +6 -2
  159. package/dist/prosemirror/extensions/marks/CharacterSpacingExtension.js +1 -1
  160. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.d.ts +9 -1
  161. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +24 -1
  162. package/dist/prosemirror/extensions/nodes/FieldExtension.js +1 -1
  163. package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.d.ts +7 -0
  164. package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.js +22 -0
  165. package/dist/prosemirror/extensions/nodes/TableExtension.js +9 -3
  166. package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.d.ts +13 -0
  167. package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.js +41 -0
  168. package/dist/prosemirror/extensions/nodes/TextBoxExtension.d.ts +5 -2
  169. package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +4 -1
  170. package/dist/prosemirror/plugins/contentControlWidgets.d.ts +34 -8
  171. package/dist/prosemirror/plugins/contentControlWidgets.js +125 -91
  172. package/dist/prosemirror/plugins/selectionTracker.js +1 -0
  173. package/dist/prosemirror/plugins/suggestionMode.js +1 -1
  174. package/dist/prosemirror/schema/index.d.ts +2 -2
  175. package/dist/prosemirror/schema/marks.d.ts +5 -1
  176. package/dist/prosemirror/schema/nodes.d.ts +64 -7
  177. package/dist/prosemirror/selectionState.js +1 -0
  178. package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
  179. package/dist/prosemirror/tableCellMergeRevision.d.ts +9 -0
  180. package/dist/prosemirror/tableCellMergeRevision.js +22 -0
  181. package/dist/prosemirror/textBoxAnchorAttrs.d.ts +9 -0
  182. package/dist/prosemirror/textBoxAnchorAttrs.js +33 -0
  183. package/dist/prosemirror/utils/extractTrackedChanges.d.ts +1 -1
  184. package/dist/prosemirror/utils/extractTrackedChanges.js +62 -14
  185. package/dist/prosemirror/validation.js +9 -1
  186. package/dist/server.d.ts +6 -2
  187. package/dist/server.js +5 -1
  188. package/dist/utils/fontFamilyMerge.js +9 -11
  189. package/dist/utils/fontLoader.js +3 -2
  190. package/dist/utils/fontResolver.js +22 -4
  191. package/dist/utils/fontWeights.d.ts +1 -1
  192. package/dist/utils/fontWeights.js +1 -1
  193. package/dist/utils/paragraphFormattingMerge.js +1 -0
  194. package/package.json +1 -1
@@ -3,7 +3,7 @@ import { FolioAIEditView } from "./ai-edits/apply.js";
3
3
 
4
4
  //#region src/document-operations.d.ts
5
5
  declare const FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION: 1;
6
- declare const FOLIO_DOCUMENT_OPERATION_TYPES: readonly ["replaceInBlock", "replaceRange", "commentOnRange", "formatRange", "insertAfterBlock", "insertBeforeBlock", "replaceBlock", "deleteBlock", "commentOnBlock", "insertSignatureTable"];
6
+ declare const FOLIO_DOCUMENT_OPERATION_TYPES: readonly ["replaceInBlock", "replaceRange", "commentOnRange", "formatRange", "insertAfterBlock", "insertBeforeBlock", "replaceBlock", "deleteBlock", "commentOnBlock", "insertSignatureTable", "insertTableRow", "deleteTableRow", "insertTableColumn", "deleteTableColumn", "mergeTableCells", "splitTableCell"];
7
7
  declare const FOLIO_DOCUMENT_OPERATION_MODES: readonly ["direct", "tracked-changes"];
8
8
  declare const FOLIO_DOCUMENT_OPERATION_STORIES: readonly ["main", "header", "footer", "footnote", "endnote"];
9
9
  declare const FOLIO_DOCUMENT_OPERATION_PRECONDITIONS: readonly ["blockTextHash"];
@@ -16,13 +16,19 @@ declare const FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE: Readonly<{
16
16
  readonly replaceInBlock: readonly ["direct", "tracked-changes"];
17
17
  readonly replaceRange: readonly ["direct", "tracked-changes"];
18
18
  readonly commentOnRange: readonly ["direct", "tracked-changes"];
19
- readonly formatRange: readonly ["direct"];
19
+ readonly formatRange: readonly ["direct", "tracked-changes"];
20
20
  readonly insertAfterBlock: readonly ["direct", "tracked-changes"];
21
21
  readonly insertBeforeBlock: readonly ["direct", "tracked-changes"];
22
22
  readonly replaceBlock: readonly ["direct", "tracked-changes"];
23
23
  readonly deleteBlock: readonly ["direct", "tracked-changes"];
24
24
  readonly commentOnBlock: readonly ["direct", "tracked-changes"];
25
25
  readonly insertSignatureTable: readonly ["direct"];
26
+ readonly insertTableRow: readonly ["direct", "tracked-changes"];
27
+ readonly deleteTableRow: readonly ["direct", "tracked-changes"];
28
+ readonly insertTableColumn: readonly ["direct", "tracked-changes"];
29
+ readonly deleteTableColumn: readonly ["direct", "tracked-changes"];
30
+ readonly mergeTableCells: readonly ["direct", "tracked-changes"];
31
+ readonly splitTableCell: readonly ["direct", "tracked-changes"];
26
32
  }>;
27
33
  type FolioDocumentOperationCapabilities = {
28
34
  readonly version: typeof FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION;
@@ -96,10 +102,36 @@ type FolioDocumentOperationAffectedTarget = {
96
102
  story: FolioDocumentOperationStory;
97
103
  anchorBlockId: string;
98
104
  position: "before" | "after";
99
- content: "block" | "signatureTable";
105
+ content: "block" | "signatureTable" | "tableRow" | "tableColumn";
100
106
  } | {
101
107
  type: "comment";
102
108
  commentId: number;
109
+ } | {
110
+ type: "tableRow";
111
+ story: FolioDocumentOperationStory;
112
+ anchorBlockId: string;
113
+ effect: "deleted";
114
+ } | {
115
+ type: "tableColumn";
116
+ story: FolioDocumentOperationStory;
117
+ anchorBlockId: string;
118
+ effect: "deleted";
119
+ } | ({
120
+ type: "tableCells";
121
+ story: FolioDocumentOperationStory;
122
+ anchorBlockId: string;
123
+ effect: "merged";
124
+ } & ({
125
+ endAnchorBlockId: string;
126
+ rowCount?: never;
127
+ } | {
128
+ rowCount: number;
129
+ endAnchorBlockId?: never;
130
+ })) | {
131
+ type: "tableCell";
132
+ story: FolioDocumentOperationStory;
133
+ anchorBlockId: string;
134
+ effect: "split";
103
135
  };
104
136
  /** Input-ordered effect receipt for one successfully applied operation. */
105
137
  type FolioDocumentOperationReceipt = {
@@ -12,7 +12,13 @@ const FOLIO_DOCUMENT_OPERATION_TYPES = Object.freeze([
12
12
  "replaceBlock",
13
13
  "deleteBlock",
14
14
  "commentOnBlock",
15
- "insertSignatureTable"
15
+ "insertSignatureTable",
16
+ "insertTableRow",
17
+ "deleteTableRow",
18
+ "insertTableColumn",
19
+ "deleteTableColumn",
20
+ "mergeTableCells",
21
+ "splitTableCell"
16
22
  ]);
17
23
  const FOLIO_DOCUMENT_OPERATION_MODES = Object.freeze(["direct", "tracked-changes"]);
18
24
  const FOLIO_DOCUMENT_OPERATION_STORIES = Object.freeze([
@@ -30,13 +36,19 @@ const FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE = Object.freeze({
30
36
  replaceInBlock: DIRECT_AND_TRACKED_MODES,
31
37
  replaceRange: DIRECT_AND_TRACKED_MODES,
32
38
  commentOnRange: DIRECT_AND_TRACKED_MODES,
33
- formatRange: DIRECT_ONLY_MODES,
39
+ formatRange: DIRECT_AND_TRACKED_MODES,
34
40
  insertAfterBlock: DIRECT_AND_TRACKED_MODES,
35
41
  insertBeforeBlock: DIRECT_AND_TRACKED_MODES,
36
42
  replaceBlock: DIRECT_AND_TRACKED_MODES,
37
43
  deleteBlock: DIRECT_AND_TRACKED_MODES,
38
44
  commentOnBlock: DIRECT_AND_TRACKED_MODES,
39
- insertSignatureTable: DIRECT_ONLY_MODES
45
+ insertSignatureTable: DIRECT_ONLY_MODES,
46
+ insertTableRow: DIRECT_AND_TRACKED_MODES,
47
+ deleteTableRow: DIRECT_AND_TRACKED_MODES,
48
+ insertTableColumn: DIRECT_AND_TRACKED_MODES,
49
+ deleteTableColumn: DIRECT_AND_TRACKED_MODES,
50
+ mergeTableCells: DIRECT_AND_TRACKED_MODES,
51
+ splitTableCell: DIRECT_AND_TRACKED_MODES
40
52
  });
41
53
  const DOCUMENT_OPERATION_CAPABILITIES = Object.freeze({
42
54
  version: 1,
@@ -94,6 +106,15 @@ const readOptionalBoolean = (value, key, path) => {
94
106
  if (typeof candidate === "boolean") return candidate;
95
107
  return invalidBatch(`${path}.${key}`, "expected a boolean when provided");
96
108
  };
109
+ const readOptionalStringArray = (value, key, path) => {
110
+ const candidate = value[key];
111
+ if (candidate === void 0) return;
112
+ if (!Array.isArray(candidate)) return invalidBatch(`${path}.${key}`, "expected an array when provided");
113
+ return candidate.map((item, index) => {
114
+ if (typeof item === "string") return item;
115
+ return invalidBatch(`${path}.${key}[${index}]`, "expected a string");
116
+ });
117
+ };
97
118
  const readNonNegativeInteger = (value, key, path) => {
98
119
  const candidate = value[key];
99
120
  if (typeof candidate === "number" && Number.isInteger(candidate) && candidate >= 0) return candidate;
@@ -382,6 +403,98 @@ const parseDocumentOperation = (value, index) => {
382
403
  ...comment !== void 0 && { comment }
383
404
  };
384
405
  }
406
+ if (type === "insertTableRow") {
407
+ assertAllowedKeys(value, path, [
408
+ ...COMMON_OPERATION_KEYS,
409
+ "position",
410
+ "cellTexts"
411
+ ]);
412
+ const position = value["position"];
413
+ if (position !== void 0 && position !== "after" && position !== "before") return invalidBatch(`${path}.position`, "expected \"after\" or \"before\" when provided");
414
+ const cellTexts = readOptionalStringArray(value, "cellTexts", path);
415
+ return {
416
+ ...operationMeta,
417
+ id,
418
+ type,
419
+ blockId,
420
+ ...position !== void 0 && { position },
421
+ ...cellTexts !== void 0 && { cellTexts }
422
+ };
423
+ }
424
+ if (type === "deleteTableRow") {
425
+ assertAllowedKeys(value, path, COMMON_OPERATION_KEYS);
426
+ return {
427
+ ...operationMeta,
428
+ id,
429
+ type,
430
+ blockId
431
+ };
432
+ }
433
+ if (type === "insertTableColumn") {
434
+ assertAllowedKeys(value, path, [
435
+ ...COMMON_OPERATION_KEYS,
436
+ "position",
437
+ "cellTexts"
438
+ ]);
439
+ const position = value["position"];
440
+ if (position !== void 0 && position !== "after" && position !== "before") return invalidBatch(`${path}.position`, "expected \"after\" or \"before\" when provided");
441
+ const cellTexts = readOptionalStringArray(value, "cellTexts", path);
442
+ return {
443
+ ...operationMeta,
444
+ id,
445
+ type,
446
+ blockId,
447
+ ...position !== void 0 && { position },
448
+ ...cellTexts !== void 0 && { cellTexts }
449
+ };
450
+ }
451
+ if (type === "deleteTableColumn") {
452
+ assertAllowedKeys(value, path, COMMON_OPERATION_KEYS);
453
+ return {
454
+ ...operationMeta,
455
+ id,
456
+ type,
457
+ blockId
458
+ };
459
+ }
460
+ if (type === "mergeTableCells") {
461
+ assertAllowedKeys(value, path, [
462
+ ...COMMON_OPERATION_KEYS,
463
+ "endBlockId",
464
+ "rowCount"
465
+ ]);
466
+ const endBlockId = readOptionalString(value, "endBlockId", path);
467
+ const rawRowCount = value["rowCount"];
468
+ if (endBlockId === void 0 === (rawRowCount === void 0)) return invalidBatch(path, "expected exactly one of endBlockId or rowCount");
469
+ if (endBlockId !== void 0) {
470
+ if (endBlockId.length === 0) return invalidBatch(`${path}.endBlockId`, "expected a non-empty string");
471
+ return {
472
+ ...operationMeta,
473
+ id,
474
+ type,
475
+ blockId,
476
+ endBlockId
477
+ };
478
+ }
479
+ const rowCount = readNonNegativeInteger(value, "rowCount", path);
480
+ if (rowCount < 2) return invalidBatch(`${path}.rowCount`, "expected an integer greater than or equal to 2");
481
+ return {
482
+ ...operationMeta,
483
+ id,
484
+ type,
485
+ blockId,
486
+ rowCount
487
+ };
488
+ }
489
+ if (type === "splitTableCell") {
490
+ assertAllowedKeys(value, path, COMMON_OPERATION_KEYS);
491
+ return {
492
+ ...operationMeta,
493
+ id,
494
+ type,
495
+ blockId
496
+ };
497
+ }
385
498
  return invalidBatch(`${path}.type`, `unsupported operation type "${type}"`);
386
499
  };
387
500
  const parseFolioDocumentOperationBatch = (value) => {
@@ -498,6 +611,51 @@ const getPrimaryAffectedTarget = (operation, story) => {
498
611
  position: operation.position ?? "after",
499
612
  content: "signatureTable"
500
613
  };
614
+ case "insertTableRow": return {
615
+ type: "insertion",
616
+ story,
617
+ anchorBlockId: operation.blockId,
618
+ position: operation.position ?? "after",
619
+ content: "tableRow"
620
+ };
621
+ case "deleteTableRow": return {
622
+ type: "tableRow",
623
+ story,
624
+ anchorBlockId: operation.blockId,
625
+ effect: "deleted"
626
+ };
627
+ case "insertTableColumn": return {
628
+ type: "insertion",
629
+ story,
630
+ anchorBlockId: operation.blockId,
631
+ position: operation.position ?? "after",
632
+ content: "tableColumn"
633
+ };
634
+ case "deleteTableColumn": return {
635
+ type: "tableColumn",
636
+ story,
637
+ anchorBlockId: operation.blockId,
638
+ effect: "deleted"
639
+ };
640
+ case "mergeTableCells": return operation.rowCount !== void 0 ? {
641
+ type: "tableCells",
642
+ story,
643
+ anchorBlockId: operation.blockId,
644
+ rowCount: operation.rowCount,
645
+ effect: "merged"
646
+ } : {
647
+ type: "tableCells",
648
+ story,
649
+ anchorBlockId: operation.blockId,
650
+ endAnchorBlockId: operation.endBlockId,
651
+ effect: "merged"
652
+ };
653
+ case "splitTableCell": return {
654
+ type: "tableCell",
655
+ story,
656
+ anchorBlockId: operation.blockId,
657
+ effect: "split"
658
+ };
501
659
  }
502
660
  };
503
661
  /** Build deterministic affected-target receipts from operations and their applied entries. */
@@ -1,10 +1,10 @@
1
1
  import { elementToXml, findChild, getChildElements, getLocalName, mergeXmlnsDeclarations } from "./xmlParser.js";
2
+ import { padDecimal } from "./numberingParser.js";
2
3
  import { parseBookmarkEnd, parseBookmarkStart } from "./bookmarkParser.js";
3
4
  import { parseSdtProperties } from "./sdtProperties.js";
4
5
  import { parseParagraph } from "./paragraphParser.js";
5
6
  import { appendBookmarkMarkerToLastParagraphInBlocks, prependBookmarkMarkersToFirstParagraphInBlocks } from "./bookmarkPlacement.js";
6
7
  import { convertBulletToUnicode } from "./bulletMarkers.js";
7
- import { padDecimal } from "./numberingParser.js";
8
8
  import { enrichParagraphTextBoxes } from "./paragraphTextBoxEnrichment.js";
9
9
  import { parseTable } from "./tableParser.js";
10
10
  //#region src/docx/blockContentParser.ts
@@ -154,7 +154,7 @@ const parseBlockContentWithState = (parent, styles, theme, numbering, rels, medi
154
154
  if (localName === "p") {
155
155
  const paragraph = parseParagraph(child, styles, theme, numbering, rels, media, state.options);
156
156
  prependPendingBookmarkMarkers(paragraph, pendingBookmarkMarkers);
157
- enrichParagraphTextBoxes(paragraph, child, styles, theme, numbering, rels, media);
157
+ enrichParagraphTextBoxes(paragraph, child, styles, theme, numbering, rels, media, parseTable);
158
158
  computeListMarker(paragraph, {
159
159
  numbering,
160
160
  listCounters: state.listCounters,
@@ -75,7 +75,8 @@ function parseComments(commentsXml, styles, theme, rels, media, commentsExtensib
75
75
  for (const child of children) {
76
76
  if ((child.name?.replace(/^.*:/u, "") ?? "") !== "comment") continue;
77
77
  const id = Number.parseInt(getAttribute(child, "w", "id") ?? "0", 10);
78
- const author = getAttribute(child, "w", "author")?.trim() || "Unknown";
78
+ const rawAuthor = getAttribute(child, "w", "author");
79
+ const author = parseCommentAuthor(rawAuthor);
79
80
  const rawInitials = getAttribute(child, "w", "initials");
80
81
  const initials = rawInitials !== null ? String(rawInitials) : void 0;
81
82
  const rawDate = getAttribute(child, "w", "date");
@@ -123,5 +124,9 @@ function parseComments(commentsXml, styles, theme, rels, media, commentsExtensib
123
124
  }
124
125
  return comments;
125
126
  }
127
+ const parseCommentAuthor = (author) => {
128
+ if (author === "") return "";
129
+ return author?.trim() || "Unknown";
130
+ };
126
131
  //#endregion
127
132
  export { parseComments, parseCommentsExtended };
@@ -3,9 +3,16 @@ import { DOCX_CONFORMANCE_CLASSES } from "@stll/docx-core/model";
3
3
  //#region src/docx/conformance.ts
4
4
  const STRICT_MAIN_NAMESPACE = "http://purl.oclc.org/ooxml/wordprocessingml/main";
5
5
  const TRANSITIONAL_MAIN_NAMESPACE = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
6
+ const ROOT_START_TAG_SCAN_LIMIT = 64 * 1024;
7
+ const ROOT_START_TAG_PATTERN = /^(?:\uFEFF|\s|<\?[\s\S]*?\?>|<!--[\s\S]*?-->)*(?<tag><[^\s/>]+(?:[^>"']|"[^"]*"|'[^']*')*>)/u;
6
8
  const detectDocxConformanceClass = (documentXml) => {
7
9
  if (documentXml === null) return DOCX_CONFORMANCE_CLASSES.UNKNOWN;
8
- const root = parseXmlDocument(documentXml);
10
+ const scanTarget = documentXml.length <= ROOT_START_TAG_SCAN_LIMIT ? documentXml : documentXml.slice(0, ROOT_START_TAG_SCAN_LIMIT);
11
+ const rootStartTag = ROOT_START_TAG_PATTERN.exec(scanTarget)?.groups?.["tag"];
12
+ const root = (rootStartTag === void 0 ? null : parseXmlDocument(rootStartTag.endsWith("/>") ? rootStartTag : `${rootStartTag.slice(0, -1)}/>`)) ?? parseXmlDocument(documentXml);
13
+ return detectDocxConformanceClassFromRoot(root);
14
+ };
15
+ const detectDocxConformanceClassFromRoot = (root) => {
9
16
  if (root === null || getLocalName(root.name ?? "") !== "document") return DOCX_CONFORMANCE_CLASSES.UNKNOWN;
10
17
  const prefix = getNamespacePrefix(root.name ?? "");
11
18
  const namespaceAttribute = prefix === null ? "xmlns" : `xmlns:${prefix}`;
@@ -0,0 +1,8 @@
1
+ //#region src/docx/documentGrid.d.ts
2
+ type DocumentGrid = {
3
+ type?: "default" | "lines" | "linesAndChars" | "snapToChars";
4
+ linePitch?: number;
5
+ };
6
+ declare function resolveDocumentGridLinePitch(grid: DocumentGrid | undefined): number | undefined;
7
+ //#endregion
8
+ export { resolveDocumentGridLinePitch };
@@ -0,0 +1,8 @@
1
+ //#region src/docx/documentGrid.ts
2
+ function resolveDocumentGridLinePitch(grid) {
3
+ if (grid?.type === void 0 || grid.type === "default") return;
4
+ if (grid.linePitch === void 0 || grid.linePitch <= 0) return;
5
+ return grid.linePitch;
6
+ }
7
+ //#endregion
8
+ export { resolveDocumentGridLinePitch };
@@ -1,5 +1,5 @@
1
- import { findByFullName, getAttribute, getChildElements, getTextContent, parseNumericAttribute } from "./xmlParser.js";
2
1
  import { ImageHorizontalAlignmentSchema, ImageHorizontalRelativeToSchema, ImageVerticalAlignmentSchema, ImageVerticalRelativeToSchema, ImageWrapTextSchema, ShapeOutlineStyleSchema, narrowEnum } from "./parserEnums.js";
2
+ import { findByFullName, getAttribute, getChildElements, getTextContent, parseNumericAttribute } from "./xmlParser.js";
3
3
  //#region src/docx/drawingUtils.ts
4
4
  /**
5
5
  * Map OOXML scheme names to standard theme color slots.
@@ -1,5 +1,5 @@
1
- import { isXmlNameBoundary } from "./selectiveXmlPatch.js";
2
1
  import { deterministicHexId } from "../utils/hexId.js";
2
+ import { isXmlNameBoundary } from "./selectiveXmlPatch.js";
3
3
  import { TaggedError } from "better-result";
4
4
  import JSZip from "jszip";
5
5
  //#region src/docx/ensureParaIds.ts
@@ -1,5 +1,5 @@
1
- import { findChildren, getAttribute } from "./xmlParser.js";
2
1
  import { FieldTypeSchema, narrowEnum } from "./parserEnums.js";
2
+ import { findChildren, getAttribute } from "./xmlParser.js";
3
3
  import { parseRun } from "./runParser.js";
4
4
  //#region src/docx/fieldParser.ts
5
5
  /**
@@ -1,5 +1,5 @@
1
- import { findChild, getAttribute, parseNumericAttribute } from "./xmlParser.js";
2
1
  import { NumberFormatSchema, narrowEnum } from "./parserEnums.js";
2
+ import { findChild, getAttribute, parseNumericAttribute } from "./xmlParser.js";
3
3
  //#region src/docx/notePropertiesParser.ts
4
4
  function parseNumberFormat(numFmtAttr) {
5
5
  return narrowEnum(numFmtAttr, NumberFormatSchema);
@@ -1,5 +1,5 @@
1
- import { findChild, findChildren, getAttribute, parseBooleanElement, parseNumericAttribute, parseXmlDocument } from "./xmlParser.js";
2
1
  import { LevelSuffixSchema, ThemeColorSlotSchema, narrowEnum } from "./parserEnums.js";
2
+ import { findChild, findChildren, getAttribute, parseBooleanElement, parseNumericAttribute, parseXmlDocument } from "./xmlParser.js";
3
3
  //#region src/docx/numberingParser.ts
4
4
  const NUMBER_FORMAT_MAP = {
5
5
  decimal: "decimal",
@@ -1,8 +1,8 @@
1
- import { elementToXml, findChild, findChildren, getAttribute, getChildElements, mergeXmlnsDeclarations, parseBooleanElement, parseNumericAttribute } from "./xmlParser.js";
2
- import { parseBookmarkEnd as parseBookmarkEnd$1, parseBookmarkStart as parseBookmarkStart$1 } from "./bookmarkParser.js";
3
1
  import { BorderStyleSchema, FrameWrapSchema, FrameXAlignSchema, FrameYAlignSchema, LineSpacingRuleSchema, ParagraphAlignmentSchema, ShadingPatternSchema, TabLeaderSchema, TabStopAlignmentSchema, ThemeColorSlotSchema, narrowEnum } from "./parserEnums.js";
2
+ import { elementToXml, findChild, findChildren, getAttribute, getChildElements, mergeXmlnsDeclarations, parseBooleanElement, parseNumericAttribute } from "./xmlParser.js";
4
3
  import { parseRun, parseRunProperties } from "./runParser.js";
5
4
  import { parseFieldType } from "./fieldParser.js";
5
+ import { parseBookmarkEnd as parseBookmarkEnd$1, parseBookmarkStart as parseBookmarkStart$1 } from "./bookmarkParser.js";
6
6
  import { parseHyperlink as parseHyperlink$1 } from "./hyperlinkParser.js";
7
7
  import { consolidateParagraphContent } from "./runConsolidator.js";
8
8
  import { parseSdtProperties } from "./sdtProperties.js";
@@ -191,6 +191,9 @@ function collectFirstParagraphPropertyChildren(pPr) {
191
191
  case "shd":
192
192
  children.shd ??= child;
193
193
  break;
194
+ case "snapToGrid":
195
+ children.snapToGrid ??= child;
196
+ break;
194
197
  case "spacing":
195
198
  children.spacing ??= child;
196
199
  break;
@@ -243,6 +246,8 @@ function parseParagraphProperties(pPr, theme, styles) {
243
246
  }
244
247
  const bidi = propertyChildren.bidi;
245
248
  if (bidi) formatting.bidi = parseBooleanElement(bidi);
249
+ const snapToGrid = propertyChildren.snapToGrid;
250
+ if (snapToGrid) formatting.snapToGrid = parseBooleanElement(snapToGrid);
246
251
  const spacing = propertyChildren.spacing;
247
252
  if (spacing) {
248
253
  const before = parseNumericAttribute(spacing, "w", "before");
@@ -369,64 +374,64 @@ function getLocalName(name) {
369
374
  const colonIndex = name.indexOf(":");
370
375
  return colonIndex !== -1 ? name.slice(colonIndex + 1) : name;
371
376
  }
377
+ const RENDERED_BREAK_INLINE_WRAPPERS = /* @__PURE__ */ new Set([
378
+ "hyperlink",
379
+ "smartTag",
380
+ "sdt",
381
+ "sdtContent",
382
+ "fldSimple",
383
+ "customXml",
384
+ "ins",
385
+ "del",
386
+ "moveFrom",
387
+ "moveTo"
388
+ ]);
389
+ const RENDERED_BREAK_NON_CONTENT_MARKERS = /* @__PURE__ */ new Set([
390
+ "pPr",
391
+ "proofErr",
392
+ "bookmarkStart",
393
+ "bookmarkEnd",
394
+ "commentRangeStart",
395
+ "commentRangeEnd",
396
+ "commentReference",
397
+ "permStart",
398
+ "permEnd",
399
+ "rsidR"
400
+ ]);
401
+ const RENDERED_BREAK_VISIBLE_RUN_CONTENT = /* @__PURE__ */ new Set([
402
+ "t",
403
+ "tab",
404
+ "br",
405
+ "cr",
406
+ "sym",
407
+ "drawing",
408
+ "pict",
409
+ "object",
410
+ "softHyphen",
411
+ "noBreakHyphen",
412
+ "fldChar",
413
+ "instrText",
414
+ "pgNum",
415
+ "separator",
416
+ "continuationSeparator",
417
+ "footnoteRef",
418
+ "endnoteRef",
419
+ "footnoteReference",
420
+ "endnoteReference",
421
+ "ptab",
422
+ "monthShort",
423
+ "monthLong",
424
+ "yearShort",
425
+ "yearLong",
426
+ "dayShort",
427
+ "dayLong"
428
+ ]);
372
429
  function paragraphStartsWithRenderedPageBreak(node) {
373
- const inlineWrappers = /* @__PURE__ */ new Set([
374
- "hyperlink",
375
- "smartTag",
376
- "sdt",
377
- "sdtContent",
378
- "fldSimple",
379
- "customXml",
380
- "ins",
381
- "del",
382
- "moveFrom",
383
- "moveTo"
384
- ]);
385
- const nonContentMarkers = /* @__PURE__ */ new Set([
386
- "pPr",
387
- "proofErr",
388
- "bookmarkStart",
389
- "bookmarkEnd",
390
- "commentRangeStart",
391
- "commentRangeEnd",
392
- "commentReference",
393
- "permStart",
394
- "permEnd",
395
- "rsidR"
396
- ]);
397
- const visibleRunContent = /* @__PURE__ */ new Set([
398
- "t",
399
- "tab",
400
- "br",
401
- "cr",
402
- "sym",
403
- "drawing",
404
- "pict",
405
- "object",
406
- "softHyphen",
407
- "noBreakHyphen",
408
- "fldChar",
409
- "instrText",
410
- "pgNum",
411
- "separator",
412
- "continuationSeparator",
413
- "footnoteRef",
414
- "endnoteRef",
415
- "footnoteReference",
416
- "endnoteReference",
417
- "ptab",
418
- "monthShort",
419
- "monthLong",
420
- "yearShort",
421
- "yearLong",
422
- "dayShort",
423
- "dayLong"
424
- ]);
425
430
  let sawRenderedPageBreak = false;
426
431
  const visit = (element) => {
427
432
  for (const child of getChildElements(element)) {
428
433
  const childName = getLocalName(child.name);
429
- if (nonContentMarkers.has(childName)) continue;
434
+ if (RENDERED_BREAK_NON_CONTENT_MARKERS.has(childName)) continue;
430
435
  if (childName === "lastRenderedPageBreak") {
431
436
  sawRenderedPageBreak = true;
432
437
  continue;
@@ -440,11 +445,11 @@ function paragraphStartsWithRenderedPageBreak(node) {
440
445
  continue;
441
446
  }
442
447
  if (runChildName === "br" && getAttribute(runChild, "w", "type") === "page") return "forced";
443
- if (visibleRunContent.has(runChildName)) return "visible";
448
+ if (RENDERED_BREAK_VISIBLE_RUN_CONTENT.has(runChildName)) return "visible";
444
449
  }
445
450
  continue;
446
451
  }
447
- if (inlineWrappers.has(childName)) {
452
+ if (RENDERED_BREAK_INLINE_WRAPPERS.has(childName)) {
448
453
  const result = visit(child);
449
454
  if (result !== "continue") return result;
450
455
  continue;
@@ -535,7 +540,7 @@ function isTrackedChangeWrapperChild(content) {
535
540
  return content.type === "run" || content.type === "hyperlink";
536
541
  }
537
542
  function isInlineSdtContent(content) {
538
- return content.type === "run" || content.type === "hyperlink" || content.type === "simpleField" || content.type === "complexField" || content.type === "inlineSdt" || content.type === "insertion" || content.type === "deletion" || content.type === "mathEquation";
543
+ return content.type === "run" || content.type === "hyperlink" || content.type === "simpleField" || content.type === "complexField" || content.type === "inlineSdt" || content.type === "insertion" || content.type === "deletion" || content.type === "moveFrom" || content.type === "moveTo" || content.type === "mathEquation";
539
544
  }
540
545
  function pushTrackedChangeWrapper({ contents, type, info, content, preserveEmpty = false }) {
541
546
  if (content.length === 0 && !preserveEmpty) return;
@@ -2,8 +2,9 @@ import { document_d_exports } from "../types/document.js";
2
2
  import { NumberingMap } from "./numberingParser.js";
3
3
  import { StyleMap } from "./styleParser.js";
4
4
  import { XmlElement } from "./xmlParser.js";
5
+ import { TableParserFn } from "./textBoxParser.js";
5
6
 
6
7
  //#region src/docx/paragraphTextBoxEnrichment.d.ts
7
- declare const enrichParagraphTextBoxes: (paragraph: document_d_exports.Paragraph, paraXml: XmlElement, styles: StyleMap | null, theme: document_d_exports.Theme | null, numbering: NumberingMap | null, rels: document_d_exports.RelationshipMap | null, media: Map<string, document_d_exports.MediaFile> | null) => void;
8
+ declare const enrichParagraphTextBoxes: (paragraph: document_d_exports.Paragraph, paraXml: XmlElement, styles: StyleMap | null, theme: document_d_exports.Theme | null, numbering: NumberingMap | null, rels: document_d_exports.RelationshipMap | null, media: Map<string, document_d_exports.MediaFile> | null, parseTable: TableParserFn) => void;
8
9
  //#endregion
9
10
  export { enrichParagraphTextBoxes };