@portone/docx-editor 0.2.1 → 0.4.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 (253) hide show
  1. package/CHANGELOG.md +155 -0
  2. package/CONTRIBUTING.md +5 -1
  3. package/dist/DocxEditor.d.ts +6 -0
  4. package/dist/DocxEditor.js +13 -29
  5. package/dist/core.d.ts +23 -8
  6. package/dist/core.js +9 -4
  7. package/dist/docx/cloning.d.ts +38 -0
  8. package/dist/docx/cloning.js +74 -0
  9. package/dist/docx/commentOnlyChange.d.ts +12 -7
  10. package/dist/docx/commentOnlyChange.js +9 -156
  11. package/dist/docx/comments/constants.d.ts +0 -1
  12. package/dist/docx/comments/constants.js +0 -2
  13. package/dist/docx/comments/grammar.d.ts +10 -4
  14. package/dist/docx/comments/grammar.js +12 -2
  15. package/dist/docx/comments/{verifying.d.ts → parts.d.ts} +26 -18
  16. package/dist/docx/comments/parts.js +279 -0
  17. package/dist/docx/comments/people.d.ts +11 -2
  18. package/dist/docx/comments/people.js +16 -92
  19. package/dist/docx/comments/policy.d.ts +7 -0
  20. package/dist/docx/comments/policy.js +43 -0
  21. package/dist/docx/comments/reading.js +8 -10
  22. package/dist/docx/comments/writing.d.ts +19 -7
  23. package/dist/docx/comments/writing.js +59 -112
  24. package/dist/docx/documentSettings.d.ts +7 -0
  25. package/dist/docx/documentSettings.js +10 -2
  26. package/dist/docx/exportDocx.d.ts +40 -5
  27. package/dist/docx/exportDocx.js +88 -74
  28. package/dist/docx/exportRefs.d.ts +5 -2
  29. package/dist/docx/exportRefs.js +3 -1
  30. package/dist/docx/fidelity.d.ts +43 -0
  31. package/dist/docx/fidelity.js +64 -0
  32. package/dist/docx/formatting/attrs.d.ts +45 -0
  33. package/dist/docx/formatting/attrs.js +86 -0
  34. package/dist/docx/formatting/context.d.ts +39 -0
  35. package/dist/docx/formatting/context.js +60 -0
  36. package/dist/docx/formatting/direct.d.ts +6 -5
  37. package/dist/docx/formatting/direct.js +52 -78
  38. package/dist/docx/formatting/resolve.d.ts +51 -0
  39. package/dist/docx/formatting/resolve.js +160 -0
  40. package/dist/docx/formatting/runProperties.d.ts +93 -0
  41. package/dist/docx/formatting/runProperties.js +316 -0
  42. package/dist/docx/formatting/styles.d.ts +25 -2
  43. package/dist/docx/formatting/styles.js +87 -6
  44. package/dist/docx/formatting/tabStops.js +7 -22
  45. package/dist/docx/formatting.d.ts +4 -1
  46. package/dist/docx/formatting.js +4 -1
  47. package/dist/docx/headersFooters.js +6 -13
  48. package/dist/docx/hyperlink.d.ts +14 -4
  49. package/dist/docx/hyperlink.js +4 -1
  50. package/dist/docx/identities.d.ts +67 -0
  51. package/dist/docx/identities.js +174 -0
  52. package/dist/docx/importDocx.d.ts +12 -1
  53. package/dist/docx/importDocx.js +90 -88
  54. package/dist/docx/importParagraph.d.ts +1 -1
  55. package/dist/docx/importParagraph.js +4 -3
  56. package/dist/docx/importTable.d.ts +2 -2
  57. package/dist/docx/importTable.js +69 -56
  58. package/dist/docx/invariants.d.ts +33 -0
  59. package/dist/docx/invariants.js +269 -0
  60. package/dist/docx/media.d.ts +6 -4
  61. package/dist/docx/media.js +6 -37
  62. package/dist/docx/newLists.d.ts +50 -0
  63. package/dist/docx/newLists.js +59 -0
  64. package/dist/docx/notes.js +3 -7
  65. package/dist/docx/numberingPlanner.d.ts +11 -0
  66. package/dist/docx/numberingPlanner.js +50 -0
  67. package/dist/docx/packageParts.d.ts +42 -0
  68. package/dist/docx/packageParts.js +135 -0
  69. package/dist/docx/pageGeometry.d.ts +2 -0
  70. package/dist/docx/pageGeometry.js +18 -9
  71. package/dist/docx/paraProps.d.ts +10 -22
  72. package/dist/docx/paraProps.js +47 -76
  73. package/dist/docx/partPlan.d.ts +36 -0
  74. package/dist/docx/partPlan.js +59 -0
  75. package/dist/docx/protectionPolicy.d.ts +127 -0
  76. package/dist/docx/protectionPolicy.js +169 -0
  77. package/dist/docx/relationships.d.ts +1 -1
  78. package/dist/docx/relationships.js +8 -13
  79. package/dist/docx/runProps.d.ts +9 -22
  80. package/dist/docx/runProps.js +15 -168
  81. package/dist/docx/scan.js +20 -52
  82. package/dist/docx/sdt.js +9 -34
  83. package/dist/docx/sdtProps.d.ts +8 -1
  84. package/dist/docx/sdtProps.js +10 -0
  85. package/dist/docx/serializeBlock.d.ts +2 -0
  86. package/dist/docx/serializeBlock.js +8 -5
  87. package/dist/docx/serializeTable.js +32 -15
  88. package/dist/docx/session.d.ts +42 -14
  89. package/dist/docx/session.js +53 -17
  90. package/dist/docx/tableFormatting/conditions.d.ts +76 -0
  91. package/dist/docx/tableFormatting/conditions.js +196 -0
  92. package/dist/docx/tableFormatting/editing.d.ts +7 -3
  93. package/dist/docx/tableFormatting/editing.js +111 -143
  94. package/dist/docx/tableFormatting/reading.d.ts +63 -23
  95. package/dist/docx/tableFormatting/reading.js +132 -38
  96. package/dist/docx/tableFormatting.d.ts +1 -0
  97. package/dist/docx/tableFormatting.js +1 -0
  98. package/dist/docx/tableTemplate.js +30 -19
  99. package/dist/download.d.ts +8 -5
  100. package/dist/download.js +2 -0
  101. package/dist/editor/clipboard/inlineFormatting.js +19 -30
  102. package/dist/editor/commands/comments/editing.d.ts +6 -2
  103. package/dist/editor/commands/comments/editing.js +19 -31
  104. package/dist/editor/commands/exportQueries.d.ts +15 -0
  105. package/dist/editor/commands/exportQueries.js +14 -0
  106. package/dist/editor/commands/fidelityQueries.d.ts +12 -0
  107. package/dist/editor/commands/fidelityQueries.js +8 -0
  108. package/dist/editor/commands/formatting/editing.d.ts +2 -2
  109. package/dist/editor/commands/formatting/editing.js +26 -108
  110. package/dist/editor/commands/formatting/propertyCommands.d.ts +21 -0
  111. package/dist/editor/commands/formatting/propertyCommands.js +108 -0
  112. package/dist/editor/commands/formatting/shared.d.ts +3 -3
  113. package/dist/editor/commands/formatting/shared.js +5 -2
  114. package/dist/editor/commands/indentCommands.js +5 -4
  115. package/dist/editor/commands/index.d.ts +11 -0
  116. package/dist/editor/commands/index.js +5 -0
  117. package/dist/editor/commands/linkCommands.js +5 -6
  118. package/dist/editor/commands/listCommands.d.ts +6 -3
  119. package/dist/editor/commands/listCommands.js +73 -30
  120. package/dist/editor/commands/lockCommands.d.ts +7 -1
  121. package/dist/editor/commands/lockCommands.js +35 -46
  122. package/dist/editor/commands/paragraphCommands.js +33 -31
  123. package/dist/editor/commands/spacingCommands.js +1 -1
  124. package/dist/editor/createEditor.d.ts +17 -29
  125. package/dist/editor/createEditor.js +58 -58
  126. package/dist/editor/documentStyles.d.ts +11 -35
  127. package/dist/editor/documentStyles.js +9 -52
  128. package/dist/editor/editorDocument.d.ts +57 -0
  129. package/dist/editor/editorDocument.js +86 -0
  130. package/dist/editor/externalClipboard.d.ts +13 -2
  131. package/dist/editor/externalClipboard.js +76 -75
  132. package/dist/editor/insertTable.js +4 -3
  133. package/dist/editor/paragraphEdits.d.ts +27 -19
  134. package/dist/editor/paragraphEdits.js +18 -19
  135. package/dist/editor/paragraphPlacement.d.ts +11 -0
  136. package/dist/editor/paragraphPlacement.js +18 -0
  137. package/dist/editor/plugins/displayDerivation.d.ts +47 -0
  138. package/dist/editor/plugins/displayDerivation.js +78 -0
  139. package/dist/editor/plugins/imagePaste.js +11 -7
  140. package/dist/editor/plugins/keymap.js +18 -3
  141. package/dist/editor/plugins/numberingDecorations.d.ts +14 -14
  142. package/dist/editor/plugins/numberingDecorations.js +50 -19
  143. package/dist/editor/plugins/paragraphDisplay.d.ts +7 -0
  144. package/dist/editor/plugins/paragraphDisplay.js +57 -0
  145. package/dist/editor/plugins/tabLayout.js +1 -1
  146. package/dist/editor/plugins/tableDisplay.d.ts +6 -0
  147. package/dist/editor/plugins/tableDisplay.js +30 -0
  148. package/dist/index.d.ts +2 -0
  149. package/dist/model/format.d.ts +80 -8
  150. package/dist/model/format.js +100 -22
  151. package/dist/model/tabStops.d.ts +9 -0
  152. package/dist/model/tabStops.js +18 -0
  153. package/dist/numbering/listRegistry.d.ts +37 -0
  154. package/dist/numbering/listRegistry.js +112 -0
  155. package/dist/numbering/listTemplate.d.ts +26 -17
  156. package/dist/numbering/listTemplate.js +88 -25
  157. package/dist/numbering/markers.d.ts +15 -6
  158. package/dist/numbering/markers.js +26 -59
  159. package/dist/numbering/parseNumbering.d.ts +84 -6
  160. package/dist/numbering/parseNumbering.js +131 -44
  161. package/dist/numbering/spellers.d.ts +15 -0
  162. package/dist/numbering/spellers.js +96 -0
  163. package/dist/numbering/writeNumbering.d.ts +8 -7
  164. package/dist/numbering/writeNumbering.js +28 -39
  165. package/dist/ooxml/childOrder.d.ts +34 -0
  166. package/dist/ooxml/childOrder.js +496 -0
  167. package/dist/ooxml/conformance.d.ts +28 -0
  168. package/dist/ooxml/conformance.js +20 -0
  169. package/dist/ooxml/element.d.ts +24 -11
  170. package/dist/ooxml/element.js +31 -12
  171. package/dist/ooxml/errors.d.ts +6 -5
  172. package/dist/ooxml/image.d.ts +4 -0
  173. package/dist/ooxml/image.js +2 -5
  174. package/dist/ooxml/names.d.ts +9 -0
  175. package/dist/ooxml/names.js +8 -1
  176. package/dist/ooxml/partSplice.d.ts +67 -0
  177. package/dist/ooxml/partSplice.js +176 -0
  178. package/dist/ooxml/props.d.ts +112 -0
  179. package/dist/{docx/propsXml.js → ooxml/props.js} +72 -200
  180. package/dist/ooxml/simpleTypes.d.ts +103 -0
  181. package/dist/ooxml/simpleTypes.js +182 -0
  182. package/dist/ooxml/tabStops.js +8 -27
  183. package/dist/ooxml/tagScan.d.ts +34 -0
  184. package/dist/ooxml/tagScan.js +108 -0
  185. package/dist/ooxml/units.d.ts +25 -13
  186. package/dist/ooxml/units.js +65 -31
  187. package/dist/ooxml/xml.d.ts +35 -15
  188. package/dist/ooxml/xml.js +43 -11
  189. package/dist/page/PageGuides.d.ts +1 -1
  190. package/dist/page/PageGuides.js +0 -13
  191. package/dist/page/blockKinds.d.ts +61 -0
  192. package/dist/page/blockKinds.js +11 -0
  193. package/dist/page/kinds/index.d.ts +6 -0
  194. package/dist/page/kinds/index.js +10 -0
  195. package/dist/page/kinds/paragraphKind.d.ts +10 -0
  196. package/dist/page/kinds/paragraphKind.js +71 -0
  197. package/dist/page/kinds/tableKind.d.ts +10 -0
  198. package/dist/page/kinds/tableKind.js +178 -0
  199. package/dist/page/measureBlocks.d.ts +3 -14
  200. package/dist/page/measureBlocks.js +24 -45
  201. package/dist/page/pageDecorations.d.ts +27 -44
  202. package/dist/page/pageDecorations.js +70 -152
  203. package/dist/page/pageLayout.d.ts +2 -29
  204. package/dist/page/pageLayout.js +39 -16
  205. package/dist/page/usePageLayout.d.ts +2 -24
  206. package/dist/page/usePageLayout.js +5 -48
  207. package/dist/schema/attrRoles.d.ts +25 -18
  208. package/dist/schema/attrRoles.js +110 -68
  209. package/dist/schema/displayDerivation.d.ts +82 -0
  210. package/dist/schema/displayDerivation.js +130 -0
  211. package/dist/schema/docxSchema.d.ts +3 -0
  212. package/dist/schema/docxSchema.js +58 -17
  213. package/dist/schema/editGuard.d.ts +1 -1
  214. package/dist/schema/guards.d.ts +37 -14
  215. package/dist/schema/guards.js +29 -3
  216. package/dist/schema/index.d.ts +2 -0
  217. package/dist/schema/index.js +2 -0
  218. package/dist/schema/locks.d.ts +11 -44
  219. package/dist/schema/locks.js +0 -9
  220. package/dist/schema/preservedGuards.d.ts +26 -6
  221. package/dist/schema/preservedGuards.js +31 -1
  222. package/dist/schema/protection.d.ts +7 -1
  223. package/dist/schema/protection.js +2 -1
  224. package/dist/schema/sourceEquality.d.ts +1 -9
  225. package/dist/schema/sourceEquality.js +1 -27
  226. package/dist/styles/classNames.d.ts +13 -2
  227. package/dist/styles/classNames.js +13 -2
  228. package/dist/styles/inlineStyle.js +15 -6
  229. package/dist/styles.css +16 -18
  230. package/dist/table/cellFormatting.d.ts +8 -1
  231. package/dist/table/cellFormatting.js +11 -20
  232. package/dist/table/commands.js +20 -18
  233. package/dist/table/format.d.ts +3 -0
  234. package/dist/table/format.js +3 -9
  235. package/dist/table/gridBorders.d.ts +24 -30
  236. package/dist/table/gridBorders.js +35 -59
  237. package/dist/table/merge.d.ts +2 -6
  238. package/dist/table/merge.js +5 -5
  239. package/package.json +7 -3
  240. package/dist/docx/comments/contentTypes.d.ts +0 -7
  241. package/dist/docx/comments/contentTypes.js +0 -38
  242. package/dist/docx/comments/verifying.js +0 -206
  243. package/dist/docx/formatting/effectiveParagraph.d.ts +0 -15
  244. package/dist/docx/formatting/effectiveParagraph.js +0 -81
  245. package/dist/docx/propsXml.d.ts +0 -67
  246. package/dist/docx/uniqueControls.d.ts +0 -14
  247. package/dist/docx/uniqueControls.js +0 -62
  248. package/dist/editor/plugins/commentReservations.d.ts +0 -5
  249. package/dist/editor/plugins/commentReservations.js +0 -26
  250. package/dist/editor/plugins/styledParagraphs.d.ts +0 -15
  251. package/dist/editor/plugins/styledParagraphs.js +0 -65
  252. package/dist/page/tableMeasurements.d.ts +0 -18
  253. package/dist/page/tableMeasurements.js +0 -119
package/CHANGELOG.md CHANGED
@@ -1,5 +1,160 @@
1
1
  # @portone/docx-editor
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#102](https://github.com/portone-io/docx-editor/pull/102) [`4258530`](https://github.com/portone-io/docx-editor/commit/4258530aaf391ba546a282f73dff7b45f7063829) Thanks [@Deea222](https://github.com/Deea222)! - Draw the table styles and list numbering a document defines, and let a document that never held a list take one.
8
+
9
+ A table style is now displayed part by part: the header row, the closing row, the first and last column, the corners and the banded rows take the shading, the lines and the text formatting the style dresses them with (`w:tblStylePr`), and `w:tblLook` decides which of those parts a table takes.
10
+ The bands are as many rows or columns wide as the style says (`w:tblStyleRowBandSize`, `w:tblStyleColBandSize`), and the header row and the closing row are not banded with the rest.
11
+ Text already in a cell follows its new position after a row edit, and the conditional-formatting markup a document arrived with goes back out untouched.
12
+
13
+ A list that takes its numbers from a numbering style now draws them.
14
+ Such a list holds no numbers of its own: it names a style (`w:numStyleLink`), the style names a list, and that list's definition is where the numbers are, which is how Word writes a list built from its gallery.
15
+ Alongside decimal, bullets, upper and lower letters and lower Roman numerals, a list may now count in upper Roman numerals, decimal numbers with a leading zero, Ganada, Korean digits and the Chinese counting system; a format past those is still shown with decimal numbers.
16
+ Each level is drawn the way it asks to be: where its counting starts over (`w:lvlRestart`), whether the numbers in its text are all spelled as decimals (`w:isLgl`), what stands between its number and the paragraph text (`w:suff`), and where the number sits in the room kept for it (`w:lvlJc`).
17
+ A marker is also drawn in the character formatting its own level writes down (`lvl/rPr`), so bold, italic, color, size and typeface reach the number and never the text of the paragraph it stands in front of.
18
+ All of this is read; the numbering part goes back out exactly as it arrived.
19
+
20
+ A new list no longer needs the document to have arrived with a numbering part.
21
+ The export writes `word/numbering.xml`, relates it from the main part and declares it in the content types, so a document that never held a list can take one; the list commands, which used to report that they did not apply in such a document, now do.
22
+ If an existing numbering relationship points to a missing part, the new definition is written at that location so the document can find the list when it is reopened.
23
+
24
+ A new or pasted list is exported with the definition it was started with, rather than a format inferred from its numbering IDs, and undo restores that registration along with the edit.
25
+ A list whose definition is missing or unsupported is refused as `unsupported-content`, and a package with no `[Content_Types].xml` for the new numbering part to be declared in is refused as `missing-content-types`; `exportProblems` reports either ahead of the write.
26
+ List and abstract definition IDs stay distinct in a document already using the largest safely representable integer, and a value that cannot be written faithfully is rejected rather than silently changed or discarded.
27
+
28
+ An ECMA-376 Strict package is refused with the new `unsupported-conformance` code, and a document whose main part root does not bind `w` to Transitional WordprocessingML is refused as `unsupported-content`.
29
+ Word saves neither by default, and both used to open far enough to fail later and obscurely: a Strict package as `missing-part`, and a document under another prefix as a `malformed-xml` about bookmarks on its first edit.
30
+ A write needing a prefix already bound to a different namespace is refused instead of silently giving new markup the wrong meaning, and a new hyperlink relationship attribute is checked for a declaration that shadows the root binding.
31
+ The comment and hyperlink writers now have the part's root declare the prefix they write under rather than declaring it on every element written, and editing an existing numbering or comment extension part that uses another prefix adds the writer's declaration at the root, so an untouched document still exports byte for byte and the exported XML stays readable.
32
+
33
+ `DocxImportErrorCode` gains `unsupported-conformance`.
34
+ `DocxExportErrorCode` loses `missing-numbering-part`, since nothing can reach it any more, and that is a compile error for a `switch` over the code written to be exhaustive; drop the branch.
35
+ `missing-content-types` now also covers the numbering part a new list is defined in.
36
+ On `./core`, `Numbering` gains `added`, and the new `NewList` and `NewListLevel` types describe the definitions the editor registered.
37
+ Level maps are read-only, and a registered definition carries a restart, legal numbering and a suffix, while marker run formatting and custom tab stops stay outside what can be registered.
38
+
39
+ ### Patch Changes
40
+
41
+ - [#101](https://github.com/portone-io/docx-editor/pull/101) [`1b6c723`](https://github.com/portone-io/docx-editor/commit/1b6c723982eed9c10656d57aca1d496e6baad5ec) Thanks [@Deea222](https://github.com/Deea222)! - Stop drawing the page number on the corner of each page.
42
+
43
+ The page guides laid a small grey number inside the top right corner of every page, over the paper the text sits on.
44
+ It is gone, and the guides now draw the gaps between pages and the header and footer stories alone.
45
+ A document that prints its own page number through a `PAGE` field in a header or footer is unaffected: that number is the document's, not the editor's.
46
+
47
+ The `docx-editor-page-badge` class the number carried is no longer emitted, so a rule of your own written against it in the published stylesheet no longer matches anything.
48
+
49
+ ## 0.3.0
50
+
51
+ ### Minor Changes
52
+
53
+ - [#62](https://github.com/portone-io/docx-editor/pull/62) [`5c481e7`](https://github.com/portone-io/docx-editor/commit/5c481e7c6e9a27373dad90d866a70cd80919b294) Thanks [@Deea222](https://github.com/Deea222)! - `onlyCommentsChangedBy` answers `comment-markup-rejected` where it used to answer `part-changed` for a comment part entry this editor would not have written for this author, or an entry nothing refers to that changed. `part` still names the comment part the entry sits in.
54
+
55
+ The verdicts themselves are unchanged: every file accepted before is accepted now, and every file refused before is refused now. What moves is the name a server logs, so "a part this file was not supposed to touch" and "markup forged into a comment" no longer read alike. A `switch` over `verdict.reason` needs the new case.
56
+
57
+ - [#77](https://github.com/portone-io/docx-editor/pull/77) [`a0b5cc6`](https://github.com/portone-io/docx-editor/commit/a0b5cc643bbeb6cf3407a0d729e7cc74fec304d6) Thanks [@Deea222](https://github.com/Deea222)! - Ask whether a document can be exported before trying.
58
+
59
+ `exportProblems(doc, session)` on the core entry, and `canExport(state)` with `documentExportProblems(state)` on the commands entry, report known reasons the writer would refuse the document, in the order it would raise them: each under the code and with the message the `DocxExportError` would carry, and with its position where the problem stands in the document. `exportDocx` throws the first entry of the same list, so problems reported by the query are also refused by the write.
60
+
61
+ The editor's handle answers the same list as `exportProblems()` beside `exportBytes()`, and `downloadDocx` asks it first and returns `{ status: "blocked", problems }` instead of throwing. A refusal the list does not foresee, such as a node a plugin stripped of an attribute the writer needs, is still thrown. `DownloadDocxResult` gaining a fourth member is a compile error for a `switch` over `status` written to be exhaustive; add a `blocked` branch that shows the problems.
62
+
63
+ A document whose comments part arrived as an empty element used to refuse its first comment with `malformed-xml`, since the writer looked for a closing tag the element does not have; the part is now opened for the entry, the way an empty extended comments part already was.
64
+
65
+ - [#63](https://github.com/portone-io/docx-editor/pull/63) [`1a4ec92`](https://github.com/portone-io/docx-editor/commit/1a4ec92162477d468fdb14a95a47388befba45f9) Thanks [@Deea222](https://github.com/Deea222)! - Read what a document holds that this editor cannot model. `importDocx` returns a `notes` array alongside the document and the session, the new `exportDocxReport` returns the same list beside the bytes it writes, and the new `documentFidelity(state)` on `./commands` answers the question about the document standing in an editor. A `FidelityNote` says how much of the original survived, what kind of content it was, the part and body block it came from, where in the document it stands, and the original element name, so a host can list what a file lost instead of guessing at it. Destructuring `importDocx` is unaffected.
66
+
67
+ A table now carries its `w:tblGridChange` instead of losing it whenever the table is rebuilt. The grid is still written from the column widths, and the revision markup closes it where CT_TblGrid takes it. `onlyCommentsChangedBy` therefore catches a submission that lost a `w:tblGridChange`, where it used to accept one: a returned file that dropped it now answers `body-changed` rather than `ok`.
68
+
69
+ - [#79](https://github.com/portone-io/docx-editor/pull/79) [`70d4801`](https://github.com/portone-io/docx-editor/commit/70d48015f52a126824f25bbd03a65b5509699de2) Thanks [@Deea222](https://github.com/Deea222)! - Applying a paragraph style keeps the spacing the document defaults lay down, and formatting a style or the document defaults switch on can be switched off: the off is written into the run (`w:b w:val="0"`) and drawn as off, where it used to be dropped and the style's value drawn again.
70
+
71
+ Every display value a paragraph or a run carries is now resolved in the ECMA-376 §17.7.2 order by one resolver, whichever path built the paragraph: opening the document, applying a style, a paragraph edit, a paste, or typing into a fresh paragraph. A character style a run points at (`w:rStyle`) takes its place in that order, a hanging indent's implicit tab stop follows the indent actually drawn, and a document's `w:noTabHangInd` setting switches that stop off.
72
+
73
+ `RunFormat` grows to say so: `bold`, `italic`, `strike` and `smallCaps` are `boolean` (false is a toggle the run switches off outright), and `underline` may be `"none"`. A reader checking `=== true` or a truthy value is unaffected.
74
+
75
+ Supported character defaults now appear in the text and toolbar, so a default bold setting turns off with one press. Clearing a direct font size immediately restores the inherited paragraph or character style in the formatting controls.
76
+
77
+ - [#82](https://github.com/portone-io/docx-editor/pull/82) [`f804ba1`](https://github.com/portone-io/docx-editor/commit/f804ba1eb5e5e6ed5ebf811e1edf2fa1858dc601) Thanks [@Deea222](https://github.com/Deea222)! - A paragraph marked keep with next (`w:keepNext`), by its own properties or by its style, stays on the same page as the start of the block after it in the page guides, as it does in Word. A run of such paragraphs moves together with the first piece of the block the keeps end at; a run no page can hold is laid out as if no keep were set. The document is not changed: the mark is read, never written.
78
+
79
+ `ParagraphFormat` grows `keepNext?: boolean` to say so, beside `pageBreakBefore`.
80
+
81
+ An explicit off (`w:keepNext w:val="0"`) overrides an inherited keep, so a paragraph can opt out of the keep imposed by its style.
82
+
83
+ - [#80](https://github.com/portone-io/docx-editor/pull/80) [`a37b4fe`](https://github.com/portone-io/docx-editor/commit/a37b4fea75bbf6e9c342c830d358ba21119dd17c) Thanks [@Deea222](https://github.com/Deea222)! - Run formatting is read, written and compared through one property table, so the value a control reads, the XML an edit writes and the check that leaves text already in that state alone can no longer drift apart. The XML written is byte for byte what it was.
84
+
85
+ `RunFormat` gains `caps`, `doubleStrike` and `characterSpacingPt`, read off a run's `w:caps`, `w:dstrike` and `w:spacing`. They reach the `format` attr a plugin reads; the editor does not draw or edit them yet.
86
+
87
+ An underline setter now distinguishes underline kinds; the public underline toggle still turns any existing kind off.
88
+
89
+ - [#72](https://github.com/portone-io/docx-editor/pull/72) [`578e73e`](https://github.com/portone-io/docx-editor/commit/578e73ed9444f528231048621a13651511438e79) Thanks [@Deea222](https://github.com/Deea222)! - `srcId` now names the block within the session it was opened in. A preserved block used to carry a bare index into the blocks of whichever document it was exported against, so a block moved or pasted in from another document pointed at this document's block of the same number and went out as that block's XML instead of its own. The attribute is now a string naming the document, the story and the place in it, and a block whose document is not the one being exported is refused with `lost-original` rather than written as something else.
90
+
91
+ A plugin that read `node.attrs.srcId` as a number needs to change: it is a string, and the only thing to do with it is hand it back as it was found. Nothing else about the attribute is public, and no exported type or function signature changed.
92
+
93
+ - [#60](https://github.com/portone-io/docx-editor/pull/60) [`1b5d0fd`](https://github.com/portone-io/docx-editor/commit/1b5d0fd96f13341de0fe34374c2a7dedec57525c) Thanks [@Deea222](https://github.com/Deea222)! - Hand `importDocx`, `exportDocx`, `onlyCommentsChangedBy`, `documentNumbering` and `parseNumbering` an `xmlParser` to read a document on a runtime that has no `DOMParser` global, instead of installing one.
94
+
95
+ A call given neither is refused with `DocxImportError` and the new import code `no-xml-parser`. It used to fail with a bare `ReferenceError`, which a server checking a file a counterparty returned could not tell apart from a document that arrived damaged. Reading a document no longer asks for a `Node` global at all, so `DOMParser`, however it is supplied, is the only thing the core entry needs from a DOM.
96
+
97
+ Each entry point settles its parser as the call comes in, so a runtime holding none is turned down before the bytes are looked at: bytes that are not a docx opened without a parser now report `no-xml-parser` where they reported `not-a-docx`. A parser that answers markup it cannot read by throwing, rather than by handing back a document holding a `parsererror`, is read as `malformed-xml` instead of having its own exception reach the caller.
98
+
99
+ ### Patch Changes
100
+
101
+ - [#75](https://github.com/portone-io/docx-editor/pull/75) [`c79e417`](https://github.com/portone-io/docx-editor/commit/c79e417bc7c2ec9cc3be804a1010533780558954) Thanks [@Deea222](https://github.com/Deea222)! - Document which schema attributes plugins may rely on and which raw OOXML attributes are internal.
102
+ An internal classification now records the provenance of every node and mark attribute without changing import, editing, or export behavior.
103
+
104
+ - [#65](https://github.com/portone-io/docx-editor/pull/65) [`a9a7e6d`](https://github.com/portone-io/docx-editor/commit/a9a7e6d92277f7725d995415da43ae5f3488e079) Thanks [@Deea222](https://github.com/Deea222)! - Content control properties are written in the order the schema lays down. Locking a control that declares what kind of control it is - a date picker, a drop-down, plain text - used to write `w:lock` after that declaration, where CT_SdtPr puts `w:lock` before it, so a validator reading the exported file could refuse a control this editor had rewritten. A control carrying `w:label` or `w:tabIndex` was written the same wrong way round.
105
+
106
+ Untouched documents retain their original XML.
107
+
108
+ - [#73](https://github.com/portone-io/docx-editor/pull/73) [`ddda545`](https://github.com/portone-io/docx-editor/commit/ddda545d43788007cf8c2c0507a33b1326d593ca) Thanks [@Deea222](https://github.com/Deea222)! - Enter no longer duplicates paragraph identifiers or a paragraph-level section break. The continuing paragraph keeps its identifiers, and the section break stays on the last paragraph of the split.
109
+
110
+ Deleting or joining away a section-ending paragraph is refused until section editing is supported. Replacing text within that paragraph remains available.
111
+
112
+ - [#81](https://github.com/portone-io/docx-editor/pull/81) [`94d4ed7`](https://github.com/portone-io/docx-editor/commit/94d4ed748b22f49054acfb0b9cf7abcd83f19f09) Thanks [@Deea222](https://github.com/Deea222)! - The lines of a table's cells and the style values of a paragraph are worked out again by one plugin, which also works every value out again when the document's formatting is replaced under it; no behavior change for a document opened today.
113
+
114
+ Changing the formatting context also refreshes existing run marks, so text does not keep its previous style after the paragraph display values change. These updates preserve the original run XML, including in locked content and protected documents.
115
+
116
+ - [#74](https://github.com/portone-io/docx-editor/pull/74) [`c22f1da`](https://github.com/portone-io/docx-editor/commit/c22f1da7e1aec0a4a5ffbd805eb7b761655ea84f) Thanks [@Deea222](https://github.com/Deea222)! - Commands now share guard helpers so their applicability checks and dispatched edits respect the same rules. Formatting at a caret inside locked content is refused; formatting queries continue to report the selected text's values under document protection.
117
+
118
+ - [#90](https://github.com/portone-io/docx-editor/pull/90) [`3b37fbd`](https://github.com/portone-io/docx-editor/commit/3b37fbd69eb90fd27011af4ecce2dfd47b61b64f) Thanks [@Deea222](https://github.com/Deea222)! - Importing `emuToPx`, `pxToEmu` or `toImageExtent` off `./core`, or the image file helpers off `./commands`, no longer carries the XML naming layer into a consumer's bundle. The picture module read the namespace table at the top of the file, which a bundler keeps as a side effect, so one multiplication cost 817 bytes minified where it costs 182. Nothing written into a document changes.
119
+
120
+ - [#70](https://github.com/portone-io/docx-editor/pull/70) [`9d7f659`](https://github.com/portone-io/docx-editor/commit/9d7f6598c2f010ee53753cbd3c7952e8b4bc7f1e) Thanks [@Deea222](https://github.com/Deea222)! - The editor reads document-level values such as styles, numbering and page geometry from one snapshot; no visible change.
121
+
122
+ - [#69](https://github.com/portone-io/docx-editor/pull/69) [`4f8c94a`](https://github.com/portone-io/docx-editor/commit/4f8c94abf38c4b77eecb632dc783f215d5decb41) Thanks [@Deea222](https://github.com/Deea222)! - A page measurement applies its pushes, break spaces and table continuations in one transaction instead of three. The pages look exactly as they did; what changes is that a single measurement now reaches the editor as a single state change, so anything watching transactions - an `onStateChange` handler, a plugin, a React state hook - sees one rather than three per remeasure.
123
+
124
+ A table's repeated header now also refreshes as soon as its source row is edited, without waiting for the next measurement.
125
+
126
+ Changing a continued row's formatting keeps its page gap until remeasurement. Page pushes also update when their measured contribution changes but the total top margin stays the same.
127
+
128
+ - [#83](https://github.com/portone-io/docx-editor/pull/83) [`14f3b87`](https://github.com/portone-io/docx-editor/commit/14f3b875004ae28c41a3fd0d58c7783fa9731d67) Thanks [@Deea222](https://github.com/Deea222)! - A relationships part whose root carries a namespace prefix, or that arrived as an empty element, is now spliced correctly when the export adds a relationship to it: the entry goes inside the root, spelled under the root's own prefix, where the export used to refuse the file with `malformed-xml` for want of a bare closing tag. A numbering part that arrived as an empty element takes a new list definition the same way instead of being refused.
129
+
130
+ When one export adds several parts, `[Content_Types].xml` now declares them in the order they were added, a media type's `Default` ahead of any `Override`; each writer used to put its own declaration first, so the declarations came out in the reverse order of adding. Every declaration is still placed right after the opening tag, and the rest of the part is left as it arrived.
131
+
132
+ Every XML part the export rewrites is now read back before the file is repacked, so a part that would not open is refused with `malformed-xml` naming the part rather than handed back.
133
+
134
+ New part names and content-type requests recognize names differing only in case, avoiding duplicate package entries and declarations.
135
+
136
+ - [#71](https://github.com/portone-io/docx-editor/pull/71) [`a0bcd87`](https://github.com/portone-io/docx-editor/commit/a0bcd8798a33ecf3aba267bc2cdfbbca2b98d632) Thanks [@Deea222](https://github.com/Deea222)! - Comment-only verification and export now share the definitions for comment package parts. Public types are unchanged.
137
+
138
+ Verification rejects new or altered content around comment entries, including outside the XML root, while accepting annotations preserved from the original and those removed by normal comment-part rewrites. Namespace rebindings under rewritten comment markup are also rejected.
139
+
140
+ - [#76](https://github.com/portone-io/docx-editor/pull/76) [`46c8ba7`](https://github.com/portone-io/docx-editor/commit/46c8ba73cedd06cd85141ea44f09119648315396) Thanks [@Deea222](https://github.com/Deea222)! - Table pagination moves into a block-kind module; no visible change. What the page engine knows about a table - where it may be parted between rows, the spacer and repeated header a continued page is drawn with, and which positions a page cut may stand at - used to be spread over the measurer, the decorations and the plugin state. It is now one module beside the paragraph's, and the engine asks whichever kind claims a block. Pages, page breaks and continued tables look exactly as they did.
141
+
142
+ - [#63](https://github.com/portone-io/docx-editor/pull/63) [`1a4ec92`](https://github.com/portone-io/docx-editor/commit/1a4ec92162477d468fdb14a95a47388befba45f9) Thanks [@Deea222](https://github.com/Deea222)! - Keep namespace bindings declared on a table grid when preserving its revision history, so editing the table can still produce a readable DOCX. Rebuilt tables also retain the required empty table-properties element when no properties are set.
143
+
144
+ - [#78](https://github.com/portone-io/docx-editor/pull/78) [`3bdf81d`](https://github.com/portone-io/docx-editor/commit/3bdf81dc3c6b0a92091e46fc8312907e60cfc67e) Thanks [@Deea222](https://github.com/Deea222)! - A paragraph copied inside the editor no longer exports a duplicate `w14:paraId`. The copy goes out as a paragraph of its own, without the original's identifiers, and the original still goes out as the bytes it arrived as.
145
+
146
+ A preserved block copied twice, a body-level bookmark marker or a section break among them, is refused with `unsupported-content` instead of written twice. `exportProblems` and `canExport` report that refusal ahead of the write, at the place the second copy stands.
147
+
148
+ - [#67](https://github.com/portone-io/docx-editor/pull/67) [`77a468f`](https://github.com/portone-io/docx-editor/commit/77a468f5c4159e619a20b446bd35d14b4833f44a) Thanks [@Deea222](https://github.com/Deea222)! - Universal measures such as `8.5in` are read correctly. A measurement in a document may be written as a length with a unit - `8.5in`, `2.54cm`, `12pt` - as well as a count, and every one of them used to be read as its leading digits alone. A US Letter document whose section says `w:pgSz w:w="8.5in"` was drawn as a page 8.5 twips wide, which is no page at all, so the editor fell back to A4 and showed the wrong paper; a tab stop at `1.5in` landed at 0.08pt and an automatic tab interval of `0.75in` collapsed every tab in that document to no width. Page size and margins, indents, spacing, font sizes, table and cell widths, cell margins, row heights and tab stops are now read as the lengths they name.
149
+
150
+ `on` and `off` spellings of boolean attributes are read as the schema admits. A style marked `w:default="on"` is now recognised as the default style for its kind, as `w:default="1"` already was, so a document that marks its defaults that way is shown with the formatting they lay down.
151
+
152
+ Integer measurements retain support for an explicit `+` sign. Table and cell widths with an explicit `%` follow Word's percentage interpretation even when their width type says otherwise. Rebuilt table widths and grid columns are written in whole units; untouched XML is preserved.
153
+
154
+ Overflowing universal-measure and percentage conversions are rejected during import.
155
+
156
+ - [#65](https://github.com/portone-io/docx-editor/pull/65) [`a9a7e6d`](https://github.com/portone-io/docx-editor/commit/a9a7e6d92277f7725d995415da43ae5f3488e079) Thanks [@Deea222](https://github.com/Deea222)! - An edit to a cell border, a cell shading, a row height, a paragraph indent, or a line spacing now reads and writes the WordprocessingML attribute alone. A producer's own attribute that shares the local name (`x:val` beside `w:val`, declared ignorable) used to be taken for the formatting value, or written over in its place; it is now left as the producer wrote it, and the value Word reads is the one read and written.
157
+
3
158
  ## 0.2.1
4
159
 
5
160
  ### Patch Changes
package/CONTRIBUTING.md CHANGED
@@ -54,7 +54,11 @@ A command added to `./commands` or `./table` needs a writer probe in `src/docx/_
54
54
 
55
55
  If you changed anything under `src/`, run `pnpm changeset` and commit the file it writes.
56
56
  It becomes the CHANGELOG entry, so write it for someone reading release notes rather than the diff.
57
- Choose `patch` unless the change adds to or breaks the public API.
57
+
58
+ The public API is the exported names and types of the four entry points - `.`, `./core`, `./commands`, and `./table` - together with the parts of the document model that [What a plugin may rely on](https://docx-editor.portone.io/docs/custom-controls#what-a-plugin-may-rely-on) calls stable.
59
+ An attr that page calls internal is not part of it, and neither is anything under `src/` that no entry point reaches.
60
+
61
+ Choose `patch` unless the change adds to that surface, takes something out of it, or changes what a part of it means.
58
62
  Those are `minor` while the package is below 1.0.
59
63
  A declaration added, removed, or rewritten in `etc/*.api.md` after running `pnpm api:update` is what that looks like; a line that only gains or loses an `(undocumented)` marker is not.
60
64
  Commit the regenerated report in the same commit as the changeset.
@@ -11,6 +11,7 @@ import type { Plugin } from "prosemirror-state";
11
11
  import type { EditorView } from "prosemirror-view";
12
12
  import { type CSSProperties, type ReactNode } from "react";
13
13
  import { type DocxSource } from "./docx/importDocx";
14
+ import { type ExportProblem } from "./docx/invariants";
14
15
  import { type CommentAuthor } from "./editor/commands/commentCommands";
15
16
  import { DocxImportError } from "./ooxml/errors";
16
17
  import type { EditableComments } from "./schema/protection";
@@ -21,6 +22,11 @@ export interface DocxEditorHandle {
21
22
  view: EditorView;
22
23
  /** Turns the editor state currently on screen into docx bytes */
23
24
  exportBytes: () => Uint8Array;
25
+ /**
26
+ * Every reason `exportBytes` would refuse the state currently on screen, each under the code
27
+ * the refusal would carry; empty when it would write. `downloadDocx` answers `blocked` with it
28
+ */
29
+ exportProblems: () => readonly ExportProblem[];
24
30
  }
25
31
  /**
26
32
  * What the editor is for, which decides what it offers.
@@ -10,16 +10,16 @@ import {
10
10
  } from "react";
11
11
  import { exportDocx } from "./docx/exportDocx.js";
12
12
  import { importDocx } from "./docx/importDocx.js";
13
+ import { exportProblems } from "./docx/invariants.js";
13
14
  import {
14
15
  documentComments
15
16
  } from "./editor/commands/commentCommands.js";
16
17
  import { activeLinkSpan } from "./editor/commands/linkCommands.js";
17
- import { createEditorState, createEditorView } from "./editor/createEditor.js";
18
+ import { createEditorView, editorStateForSession } from "./editor/createEditor.js";
18
19
  import { setProtection } from "./editor/plugins/documentProtection.js";
19
20
  import { isLinkPanelOpen } from "./editor/plugins/linkPanel.js";
20
21
  import { tableMenuAnchor } from "./editor/plugins/tableContextMenu.js";
21
22
  import { textMenuAnchor } from "./editor/plugins/textContextMenu.js";
22
- import { parseNumbering } from "./numbering/parseNumbering.js";
23
23
  import { DocxImportError } from "./ooxml/errors.js";
24
24
  import { PageGuides } from "./page/PageGuides.js";
25
25
  import { A4_PAGE_PIXELS, pagePixels } from "./page/pageLayout.js";
@@ -71,12 +71,7 @@ function affordancesOf(mode) {
71
71
  function openDocument(bytes) {
72
72
  try {
73
73
  const { doc, session } = importDocx(bytes);
74
- return {
75
- status: "opened",
76
- doc,
77
- session,
78
- numbering: parseNumbering(session.numberingXml)
79
- };
74
+ return { status: "opened", doc, session };
80
75
  } catch (error) {
81
76
  if (error instanceof DocxImportError) return { status: "rejected", error };
82
77
  throw error;
@@ -112,11 +107,15 @@ function useDocumentBytes(source) {
112
107
  return read.bytes;
113
108
  }
114
109
  var IMPORT_REJECTION_REASON = {
110
+ // `DOMParser` is built into the browser rather than loaded with the page, so a browser that
111
+ // reaches this line has no XML reader at all and will not have gained one on a second try
112
+ "no-xml-parser": "This browser cannot read documents.",
115
113
  "not-a-docx": "This file is not a docx document, or it is damaged.",
116
114
  "too-large": "This document is too large to open.",
117
115
  "missing-part": "This document is missing the part that holds its body.",
118
116
  "missing-body": "This document has no body.",
119
117
  "malformed-xml": "The XML inside this document cannot be read.",
118
+ "unsupported-conformance": "This document is saved in a format this editor cannot open. Save it as a Word document and try again.",
120
119
  "unsupported-content": "This document holds content that could not be kept as it is."
121
120
  };
122
121
  function ImportRejection({ error }) {
@@ -184,32 +183,13 @@ function DocxEditorSurface({
184
183
  const kept = keptState.current;
185
184
  const view = createEditorView({
186
185
  mount,
187
- state: kept?.of === opened ? kept.state : createEditorState(opened.doc, {
188
- numbering: opened.numbering,
189
- styles: opened.session.styles,
190
- defaults: opened.session.defaults,
191
- paragraphDefaults: opened.session.paragraphDefaults,
192
- canStartNewList: opened.session.numberingPartPath !== null,
186
+ state: kept?.of === opened ? kept.state : editorStateForSession(opened, {
193
187
  consumerPlugins: mountedPlugins,
194
- paragraphStyles: opened.session.paragraphStyles,
195
188
  contextMenus: mountedContextMenus,
196
- geometry: opened.session.geometry,
197
- defaultTabStopPt: opened.session.defaultTabStopPt,
198
- reservedCommentIds: opened.session.comments.byId.keys(),
199
- reservedCommentParaIds: [
200
- ...opened.session.comments.ordered.flatMap(
201
- (comment) => comment.paraId === null ? [] : [comment.paraId]
202
- ),
203
- ...opened.session.comments.extendedOrdered.map(
204
- (extension) => extension.paraId
205
- )
206
- ],
207
189
  protection,
208
190
  author,
209
191
  editableComments
210
192
  }),
211
- defaults: opened.session.defaults,
212
- geometry: opened.session.geometry,
213
193
  fontFallbacks: mountedFontFallbacks,
214
194
  onStateChange: (state) => {
215
195
  keptState.current = { of: opened, state };
@@ -252,7 +232,11 @@ function DocxEditorSurface({
252
232
  const view = viewRef.current;
253
233
  if (!view || opened?.status !== "opened") return null;
254
234
  const session = opened.session;
255
- return { view, exportBytes: () => exportDocx(view.state.doc, session) };
235
+ return {
236
+ view,
237
+ exportBytes: () => exportDocx(view.state.doc, session),
238
+ exportProblems: () => exportProblems(view.state.doc, session)
239
+ };
256
240
  }, [opened]);
257
241
  const overlay = usePageLayout({
258
242
  view: live?.view ?? null,
package/dist/core.d.ts CHANGED
@@ -1,20 +1,33 @@
1
1
  /**
2
2
  * Framework-free DOCX import and export API. The opaque session preserves package parts between
3
- * calls; server runtimes must provide global `DOMParser` and `Node` implementations.
3
+ * calls.
4
+ *
5
+ * Reading a package needs an XML parser. A browser has one; anywhere else, hand one in as
6
+ * `xmlParser` or install a `DOMParser` global, or the call is refused with the import code
7
+ * `no-xml-parser`.
4
8
  */
5
9
  import type { Node as PMNode } from "prosemirror-model";
6
- import { type DocxBytes } from "./docx/importDocx";
10
+ import type { FidelityNote } from "./docx/fidelity";
11
+ import { type DocxBytes, type ImportOptions } from "./docx/importDocx";
7
12
  import type { DocxSession } from "./docx/session";
8
13
  export type { CommentOnlyVerdict } from "./docx/commentOnlyChange";
9
14
  export { onlyCommentsChangedBy } from "./docx/commentOnlyChange";
10
- export { exportDocx } from "./docx/exportDocx";
15
+ export type { ExportOptions } from "./docx/exportDocx";
16
+ export { exportDocx, exportDocxReport } from "./docx/exportDocx";
17
+ export type { FidelityCode, FidelityNote, FidelitySeverity, } from "./docx/fidelity";
11
18
  export type { ParagraphStyleOption } from "./docx/formatting";
12
- export type { DocxBytes } from "./docx/importDocx";
19
+ export type { DocxBytes, ImportOptions } from "./docx/importDocx";
20
+ /**
21
+ * What the writer would refuse the document over, asked ahead of the write. The first entry is
22
+ * what `exportDocx` throws, so the two cannot disagree.
23
+ */
24
+ export type { ExportProblem } from "./docx/invariants";
25
+ export { exportProblems } from "./docx/invariants";
13
26
  export type { DocxSession } from "./docx/session";
14
27
  export { documentNumbering, documentPartPath } from "./docx/session";
15
28
  export type { CellFormat, CellVerticalAlign, DocumentDefaults, HighlightName, LineSpacing, NumberingRef, ParagraphAlign, ParagraphFormat, RowFormat, RowHeight, RunFormat, TableFormat, TableWidth, TableWidthType, UnderlineKind, VerticalAlign, } from "./model/format";
16
29
  export { toCellFormat, toParagraphFormat, toRowFormat, toRunFormat, toTableFormat, toTableWidth, } from "./model/format";
17
- export type { LevelIndent, NumberFormat, Numbering, NumberingLevel, NumberingList, } from "./numbering/parseNumbering";
30
+ export type { LevelAlign, LevelIndent, LevelSuffix, NewList, NewListLevel, NumberFormat, Numbering, NumberingLevel, NumberingList, NumberingOptions, NumberingStyleLinks, ReadLevelRun, } from "./numbering/parseNumbering";
18
31
  export { parseNumbering } from "./numbering/parseNumbering";
19
32
  export type { DocxExportErrorCode, DocxImportErrorCode, } from "./ooxml/errors";
20
33
  export { DocxExportError, DocxImportError } from "./ooxml/errors";
@@ -24,15 +37,17 @@ export { DocxExportError, DocxImportError } from "./ooxml/errors";
24
37
  */
25
38
  export type { ImageExtent } from "./ooxml/image";
26
39
  export { emuToPx, pxToEmu, toImageExtent } from "./ooxml/image";
40
+ export type { XmlParser } from "./ooxml/xml";
27
41
  export { docxSchema } from "./schema";
28
42
  /**
29
- * Opens docx bytes into the document to work on and the session that remembers the file they came
30
- * from.
43
+ * Opens docx bytes into the document to work on, the session that remembers the file they came
44
+ * from, and what the file holds that this editor could not model.
31
45
  *
32
46
  * The engine hands out the store it fills in; this is where it narrows to the opaque session, so
33
47
  * that the original XML behind it stays the exporter's business.
34
48
  */
35
- export declare function importDocx(input: DocxBytes): {
49
+ export declare function importDocx(input: DocxBytes, options?: ImportOptions): {
36
50
  doc: PMNode;
37
51
  session: DocxSession;
52
+ notes: FidelityNote[];
38
53
  };
package/dist/core.js CHANGED
@@ -1,7 +1,10 @@
1
1
  // src/core.ts
2
- import { importDocx as openDocx } from "./docx/importDocx.js";
2
+ import {
3
+ importDocx as openDocx
4
+ } from "./docx/importDocx.js";
3
5
  import { onlyCommentsChangedBy } from "./docx/commentOnlyChange.js";
4
- import { exportDocx } from "./docx/exportDocx.js";
6
+ import { exportDocx, exportDocxReport } from "./docx/exportDocx.js";
7
+ import { exportProblems } from "./docx/invariants.js";
5
8
  import { documentNumbering, documentPartPath } from "./docx/session.js";
6
9
  import {
7
10
  toCellFormat,
@@ -15,8 +18,8 @@ import { parseNumbering } from "./numbering/parseNumbering.js";
15
18
  import { DocxExportError, DocxImportError } from "./ooxml/errors.js";
16
19
  import { emuToPx, pxToEmu, toImageExtent } from "./ooxml/image.js";
17
20
  import { docxSchema } from "./schema/index.js";
18
- function importDocx(input) {
19
- return openDocx(input);
21
+ function importDocx(input, options) {
22
+ return openDocx(input, options);
20
23
  }
21
24
  export {
22
25
  DocxExportError,
@@ -26,6 +29,8 @@ export {
26
29
  docxSchema,
27
30
  emuToPx,
28
31
  exportDocx,
32
+ exportDocxReport,
33
+ exportProblems,
29
34
  importDocx,
30
35
  onlyCommentsChangedBy,
31
36
  parseNumbering,
@@ -0,0 +1,38 @@
1
+ /**
2
+ * What a node an edit makes out of another node carries over from it.
3
+ *
4
+ * A paragraph built from another one - either half of the two Enter leaves behind, or a copy - used
5
+ * to arrive holding every attr of the original. Two paragraphs then claimed the same `w14:paraId`,
6
+ * and a paragraph-level `w:sectPr` went out twice, which
7
+ * gives the document a section break it never had.
8
+ *
9
+ * `CLONE_POLICIES` is the one place that answers what becomes of each attr, and it answers per
10
+ * side: the half a split leaves standing is not the half it makes, and a free-standing copy is
11
+ * neither. What the answer turns on is whether the attr names the node - an identifier, or the
12
+ * block it was opened from - or describes it. A name may be held by one node only; a description
13
+ * is free to be copied.
14
+ */
15
+ import type { Attrs, Node as PMNode } from "prosemirror-model";
16
+ /** Which half of a split the clone becomes, or a free-standing copy */
17
+ export type CloneSide = "before" | "after" | "copy";
18
+ export interface ClonePolicy {
19
+ /** The attrs a node made from `source` carries when it stands on `side` */
20
+ attrs(source: PMNode, side: CloneSide): Attrs;
21
+ }
22
+ /**
23
+ * The opening tag's attributes without the paragraph identifiers.
24
+ *
25
+ * A paragraph carrying none goes back out spelled exactly as it arrived, and so does one whose
26
+ * attribute text cannot be made out, which is left alone rather than written again from a guess.
27
+ */
28
+ export declare function withoutParagraphIds(value: unknown): unknown;
29
+ /** One policy per node type that an edit can make from another node */
30
+ export declare const CLONE_POLICIES: Readonly<Record<"paragraph" | "tableCell" | "tableRow", ClonePolicy>>;
31
+ /**
32
+ * The two halves Enter leaves behind. `before` keeps the text, `after` keeps the paragraph mark's
33
+ * section break
34
+ */
35
+ export declare function splitParagraphAttrs(parent: PMNode): {
36
+ before: Attrs;
37
+ after: Attrs;
38
+ };
@@ -0,0 +1,74 @@
1
+ // src/docx/cloning.ts
2
+ import { attrsText, withoutAttrs } from "../ooxml/element.js";
3
+ import { parseProps, renderProps, setChild } from "../ooxml/props.js";
4
+ import { parseAttrs } from "../ooxml/tagScan.js";
5
+ var carried = (value) => value;
6
+ var defaulted = () => void 0;
7
+ var PARAGRAPH_ID_ATTRS = ["paraId", "textId"];
8
+ function withoutParagraphIds(value) {
9
+ if (typeof value !== "string") return value;
10
+ const attrs = parseAttrs(value);
11
+ if (attrs === null) return value;
12
+ const kept = withoutAttrs(attrs, PARAGRAPH_ID_ATTRS, "w14");
13
+ if (kept.length === attrs.length) return value;
14
+ return kept.length === 0 ? null : attrsText(kept);
15
+ }
16
+ function withoutSectionBreak(value) {
17
+ if (typeof value !== "string") return value;
18
+ const props = parseProps(value);
19
+ if (props === null) return value;
20
+ const without = setChild(props, "sectPr", null);
21
+ if (without.children.length === props.children.length) return value;
22
+ return renderProps(without) || null;
23
+ }
24
+ var INHERITED_CELL_ATTRS = ["tcAttrs", "tcPr", "tcW", "format"];
25
+ var INHERITED_ROW_ATTRS = ["trAttrs", "trPr", "format"];
26
+ function inherits(names) {
27
+ return Object.fromEntries(names.map((name) => [name, carried]));
28
+ }
29
+ function policy(rules, rest) {
30
+ return {
31
+ attrs(source, side) {
32
+ const attrs = {};
33
+ for (const [name, value] of Object.entries(source.attrs)) {
34
+ const held = (rules[name] ?? rest)(value, side);
35
+ if (held !== void 0) attrs[name] = held;
36
+ }
37
+ return attrs;
38
+ }
39
+ };
40
+ }
41
+ var CLONE_POLICIES = {
42
+ paragraph: policy(
43
+ {
44
+ // The half that carries on where the original stood keeps the original's name. The one the
45
+ // edit made is a new paragraph and goes out with none, so no two ever claim the same
46
+ // paragraph identity.
47
+ pAttrs: (value, side) => side === "before" ? value : withoutParagraphIds(value),
48
+ // A paragraph-level `w:sectPr` ends the section it stands in, so it belongs to whichever
49
+ // paragraph ends up last in that section: the second half of a split, and no half of a copy,
50
+ // which is lifted out of the section it was taken from.
51
+ pPr: (value, side) => side === "after" ? value : withoutSectionBreak(value),
52
+ // What names the block this paragraph was opened from. Only the half still standing where
53
+ // that block stood may go on claiming it; `docx/exportDocx` writes the original bytes back
54
+ // for whatever claims one.
55
+ srcId: (value, side) => side === "before" ? value : void 0
56
+ },
57
+ // `format` and `styleRun` among them: display values `editor/plugins/paragraphDisplay` derives
58
+ // again from the formatting context, which nothing compares and nothing writes out.
59
+ carried
60
+ ),
61
+ tableCell: policy(inherits(INHERITED_CELL_ATTRS), defaulted),
62
+ tableRow: policy(inherits(INHERITED_ROW_ATTRS), defaulted)
63
+ };
64
+ function splitParagraphAttrs(parent) {
65
+ return {
66
+ before: CLONE_POLICIES.paragraph.attrs(parent, "before"),
67
+ after: CLONE_POLICIES.paragraph.attrs(parent, "after")
68
+ };
69
+ }
70
+ export {
71
+ CLONE_POLICIES,
72
+ splitParagraphAttrs,
73
+ withoutParagraphIds
74
+ };
@@ -7,11 +7,13 @@
7
7
  * free to rewrite anything the story does not carry - the paper the document is written on, its
8
8
  * styles, its headers - and a document comparison would see none of it.
9
9
  */
10
- import { type EditableComments } from "../schema/protection";
11
- import { type DocxBytes } from "./importDocx";
10
+ import type { XmlParser } from "../ooxml/xml";
11
+ import type { EditableComments } from "../schema/protection";
12
+ import type { DocxBytes } from "./importDocx";
12
13
  /**
13
- * Why a file is not the one it claims to be. `part-changed` and `relationship-changed` name the
14
- * part they were reached over; the other three are about the document story itself.
14
+ * Why a file is not the one it claims to be. `part-changed`, `relationship-changed` and
15
+ * `comment-markup-rejected` name the part they were reached over; the other three are about the
16
+ * document story itself.
15
17
  */
16
18
  export type CommentOnlyVerdict = {
17
19
  ok: true;
@@ -20,7 +22,7 @@ export type CommentOnlyVerdict = {
20
22
  reason: "body-changed" | "comment-not-owned" | "comment-author-forged";
21
23
  } | {
22
24
  ok: false;
23
- reason: "part-changed" | "relationship-changed";
25
+ reason: "part-changed" | "relationship-changed" | "comment-markup-rejected";
24
26
  part: string;
25
27
  };
26
28
  /**
@@ -30,7 +32,7 @@ export type CommentOnlyVerdict = {
30
32
  * Every part of the package has to arrive as it left, save for the three a comment is written
31
33
  * across and the relationship and content type they are declared with; the document story itself
32
34
  * has to read as it did, comments aside. Those three parts are read entry by entry instead
33
- * (`./comments/verifying`), since a comment edit is free to rewrite them and something has to say
35
+ * (`./comments/policy`), since a comment edit is free to rewrite them and something has to say
34
36
  * what it may have written there. A comment carrying no recorded identity is everyone's to
35
37
  * edit here as it is in the editor (`schema/protection`), while a comment that appeared has to
36
38
  * carry this identity: a file can claim any author, and the editor's own hand in writing it is
@@ -38,10 +40,13 @@ export type CommentOnlyVerdict = {
38
40
  *
39
41
  * `editableComments: "all"` judges the file of an editor opened for a moderator, where every
40
42
  * comment was theirs to edit; an identity is nobody's to rewrite under either setting.
43
+ * `xmlParser` names the parser both files are read through, for a runtime that holds no
44
+ * `DOMParser` global of its own.
41
45
  *
42
46
  * Bytes that are not a readable docx are turned down the way opening one is, with a
43
47
  * `DocxImportError`, rather than being answered as a file that changed.
44
48
  */
45
- export declare function onlyCommentsChangedBy(original: DocxBytes, submitted: DocxBytes, authorId: string, { editableComments }?: {
49
+ export declare function onlyCommentsChangedBy(original: DocxBytes, submitted: DocxBytes, authorId: string, { editableComments, xmlParser, }?: {
46
50
  editableComments?: EditableComments;
51
+ xmlParser?: XmlParser;
47
52
  }): CommentOnlyVerdict;