@portone/docx-editor 0.2.1 → 0.3.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 (225) hide show
  1. package/CHANGELOG.md +109 -0
  2. package/CONTRIBUTING.md +5 -1
  3. package/dist/DocxEditor.d.ts +6 -0
  4. package/dist/DocxEditor.js +12 -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 +52 -111
  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 +69 -71
  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 +27 -0
  33. package/dist/docx/formatting/attrs.js +31 -0
  34. package/dist/docx/formatting/context.d.ts +31 -0
  35. package/dist/docx/formatting/context.js +42 -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 +45 -0
  39. package/dist/docx/formatting/resolve.js +140 -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.js +3 -3
  43. package/dist/docx/formatting/tabStops.js +7 -22
  44. package/dist/docx/formatting.d.ts +4 -1
  45. package/dist/docx/formatting.js +4 -1
  46. package/dist/docx/headersFooters.js +6 -13
  47. package/dist/docx/identities.d.ts +67 -0
  48. package/dist/docx/identities.js +174 -0
  49. package/dist/docx/importDocx.d.ts +12 -1
  50. package/dist/docx/importDocx.js +72 -79
  51. package/dist/docx/importParagraph.d.ts +1 -1
  52. package/dist/docx/importParagraph.js +4 -3
  53. package/dist/docx/importTable.d.ts +1 -1
  54. package/dist/docx/importTable.js +17 -1
  55. package/dist/docx/invariants.d.ts +33 -0
  56. package/dist/docx/invariants.js +256 -0
  57. package/dist/docx/media.d.ts +6 -4
  58. package/dist/docx/media.js +6 -37
  59. package/dist/docx/newLists.d.ts +20 -0
  60. package/dist/docx/newLists.js +36 -0
  61. package/dist/docx/notes.js +3 -7
  62. package/dist/docx/numberingPlanner.d.ts +8 -0
  63. package/dist/docx/numberingPlanner.js +19 -0
  64. package/dist/docx/packageParts.d.ts +42 -0
  65. package/dist/docx/packageParts.js +135 -0
  66. package/dist/docx/pageGeometry.d.ts +2 -0
  67. package/dist/docx/pageGeometry.js +18 -9
  68. package/dist/docx/paraProps.d.ts +10 -22
  69. package/dist/docx/paraProps.js +47 -76
  70. package/dist/docx/partPlan.d.ts +36 -0
  71. package/dist/docx/partPlan.js +59 -0
  72. package/dist/docx/protectionPolicy.d.ts +127 -0
  73. package/dist/docx/protectionPolicy.js +169 -0
  74. package/dist/docx/relationships.d.ts +1 -1
  75. package/dist/docx/relationships.js +8 -13
  76. package/dist/docx/runProps.d.ts +9 -22
  77. package/dist/docx/runProps.js +15 -168
  78. package/dist/docx/scan.js +20 -52
  79. package/dist/docx/sdt.js +9 -34
  80. package/dist/docx/sdtProps.d.ts +8 -1
  81. package/dist/docx/sdtProps.js +10 -0
  82. package/dist/docx/serializeBlock.d.ts +2 -0
  83. package/dist/docx/serializeBlock.js +8 -5
  84. package/dist/docx/serializeTable.js +32 -15
  85. package/dist/docx/session.d.ts +42 -14
  86. package/dist/docx/session.js +43 -17
  87. package/dist/docx/tableFormatting/editing.js +108 -139
  88. package/dist/docx/tableFormatting/reading.d.ts +16 -6
  89. package/dist/docx/tableFormatting/reading.js +40 -20
  90. package/dist/docx/tableTemplate.js +18 -7
  91. package/dist/download.d.ts +8 -5
  92. package/dist/download.js +2 -0
  93. package/dist/editor/clipboard/inlineFormatting.js +19 -30
  94. package/dist/editor/commands/comments/editing.d.ts +6 -2
  95. package/dist/editor/commands/comments/editing.js +19 -31
  96. package/dist/editor/commands/exportQueries.d.ts +15 -0
  97. package/dist/editor/commands/exportQueries.js +14 -0
  98. package/dist/editor/commands/fidelityQueries.d.ts +12 -0
  99. package/dist/editor/commands/fidelityQueries.js +8 -0
  100. package/dist/editor/commands/formatting/editing.d.ts +2 -2
  101. package/dist/editor/commands/formatting/editing.js +26 -108
  102. package/dist/editor/commands/formatting/propertyCommands.d.ts +21 -0
  103. package/dist/editor/commands/formatting/propertyCommands.js +103 -0
  104. package/dist/editor/commands/formatting/shared.d.ts +3 -3
  105. package/dist/editor/commands/formatting/shared.js +5 -2
  106. package/dist/editor/commands/indentCommands.js +5 -4
  107. package/dist/editor/commands/index.d.ts +11 -0
  108. package/dist/editor/commands/index.js +5 -0
  109. package/dist/editor/commands/linkCommands.js +5 -6
  110. package/dist/editor/commands/listCommands.js +8 -10
  111. package/dist/editor/commands/lockCommands.d.ts +7 -1
  112. package/dist/editor/commands/lockCommands.js +35 -46
  113. package/dist/editor/commands/paragraphCommands.js +28 -31
  114. package/dist/editor/commands/spacingCommands.js +1 -1
  115. package/dist/editor/createEditor.d.ts +17 -29
  116. package/dist/editor/createEditor.js +58 -58
  117. package/dist/editor/documentStyles.d.ts +11 -35
  118. package/dist/editor/documentStyles.js +9 -52
  119. package/dist/editor/editorDocument.d.ts +56 -0
  120. package/dist/editor/editorDocument.js +74 -0
  121. package/dist/editor/externalClipboard.js +16 -45
  122. package/dist/editor/insertTable.js +4 -3
  123. package/dist/editor/paragraphEdits.d.ts +11 -18
  124. package/dist/editor/paragraphEdits.js +7 -16
  125. package/dist/editor/plugins/displayDerivation.d.ts +47 -0
  126. package/dist/editor/plugins/displayDerivation.js +78 -0
  127. package/dist/editor/plugins/imagePaste.js +4 -3
  128. package/dist/editor/plugins/keymap.js +18 -3
  129. package/dist/editor/plugins/numberingDecorations.d.ts +5 -11
  130. package/dist/editor/plugins/numberingDecorations.js +7 -17
  131. package/dist/editor/plugins/paragraphDisplay.d.ts +7 -0
  132. package/dist/editor/plugins/paragraphDisplay.js +51 -0
  133. package/dist/editor/plugins/tabLayout.js +1 -1
  134. package/dist/editor/plugins/tableDisplay.d.ts +6 -0
  135. package/dist/editor/plugins/tableDisplay.js +16 -0
  136. package/dist/index.d.ts +2 -0
  137. package/dist/model/format.d.ts +30 -8
  138. package/dist/model/format.js +35 -22
  139. package/dist/model/tabStops.d.ts +9 -0
  140. package/dist/model/tabStops.js +18 -0
  141. package/dist/numbering/listTemplate.js +24 -7
  142. package/dist/numbering/parseNumbering.d.ts +14 -1
  143. package/dist/numbering/parseNumbering.js +35 -22
  144. package/dist/numbering/writeNumbering.d.ts +3 -4
  145. package/dist/numbering/writeNumbering.js +14 -25
  146. package/dist/ooxml/childOrder.d.ts +34 -0
  147. package/dist/ooxml/childOrder.js +496 -0
  148. package/dist/ooxml/element.d.ts +24 -11
  149. package/dist/ooxml/element.js +31 -12
  150. package/dist/ooxml/errors.d.ts +3 -2
  151. package/dist/ooxml/image.d.ts +4 -0
  152. package/dist/ooxml/image.js +2 -5
  153. package/dist/ooxml/partSplice.d.ts +67 -0
  154. package/dist/ooxml/partSplice.js +169 -0
  155. package/dist/ooxml/props.d.ts +112 -0
  156. package/dist/{docx/propsXml.js → ooxml/props.js} +72 -200
  157. package/dist/ooxml/simpleTypes.d.ts +103 -0
  158. package/dist/ooxml/simpleTypes.js +182 -0
  159. package/dist/ooxml/tabStops.js +8 -27
  160. package/dist/ooxml/tagScan.d.ts +34 -0
  161. package/dist/ooxml/tagScan.js +108 -0
  162. package/dist/ooxml/units.d.ts +25 -13
  163. package/dist/ooxml/units.js +65 -31
  164. package/dist/ooxml/xml.d.ts +27 -6
  165. package/dist/ooxml/xml.js +37 -5
  166. package/dist/page/blockKinds.d.ts +61 -0
  167. package/dist/page/blockKinds.js +11 -0
  168. package/dist/page/kinds/index.d.ts +6 -0
  169. package/dist/page/kinds/index.js +10 -0
  170. package/dist/page/kinds/paragraphKind.d.ts +10 -0
  171. package/dist/page/kinds/paragraphKind.js +71 -0
  172. package/dist/page/kinds/tableKind.d.ts +10 -0
  173. package/dist/page/kinds/tableKind.js +178 -0
  174. package/dist/page/measureBlocks.d.ts +3 -14
  175. package/dist/page/measureBlocks.js +24 -45
  176. package/dist/page/pageDecorations.d.ts +27 -44
  177. package/dist/page/pageDecorations.js +70 -152
  178. package/dist/page/pageLayout.d.ts +2 -19
  179. package/dist/page/pageLayout.js +36 -6
  180. package/dist/page/usePageLayout.d.ts +2 -17
  181. package/dist/page/usePageLayout.js +3 -39
  182. package/dist/schema/attrRoles.d.ts +25 -18
  183. package/dist/schema/attrRoles.js +102 -67
  184. package/dist/schema/displayDerivation.d.ts +82 -0
  185. package/dist/schema/displayDerivation.js +130 -0
  186. package/dist/schema/docxSchema.d.ts +3 -0
  187. package/dist/schema/docxSchema.js +26 -14
  188. package/dist/schema/editGuard.d.ts +1 -1
  189. package/dist/schema/guards.d.ts +37 -14
  190. package/dist/schema/guards.js +29 -3
  191. package/dist/schema/index.d.ts +2 -0
  192. package/dist/schema/index.js +2 -0
  193. package/dist/schema/locks.d.ts +11 -44
  194. package/dist/schema/locks.js +0 -9
  195. package/dist/schema/preservedGuards.d.ts +26 -6
  196. package/dist/schema/preservedGuards.js +31 -1
  197. package/dist/schema/protection.d.ts +7 -1
  198. package/dist/schema/protection.js +2 -1
  199. package/dist/schema/sourceEquality.d.ts +1 -9
  200. package/dist/schema/sourceEquality.js +1 -27
  201. package/dist/styles/inlineStyle.js +15 -6
  202. package/dist/table/cellFormatting.d.ts +8 -1
  203. package/dist/table/cellFormatting.js +10 -18
  204. package/dist/table/commands.js +20 -18
  205. package/dist/table/format.d.ts +3 -0
  206. package/dist/table/format.js +3 -9
  207. package/dist/table/gridBorders.d.ts +14 -16
  208. package/dist/table/gridBorders.js +3 -41
  209. package/dist/table/merge.d.ts +2 -6
  210. package/dist/table/merge.js +5 -5
  211. package/package.json +7 -3
  212. package/dist/docx/comments/contentTypes.d.ts +0 -7
  213. package/dist/docx/comments/contentTypes.js +0 -38
  214. package/dist/docx/comments/verifying.js +0 -206
  215. package/dist/docx/formatting/effectiveParagraph.d.ts +0 -15
  216. package/dist/docx/formatting/effectiveParagraph.js +0 -81
  217. package/dist/docx/propsXml.d.ts +0 -67
  218. package/dist/docx/uniqueControls.d.ts +0 -14
  219. package/dist/docx/uniqueControls.js +0 -62
  220. package/dist/editor/plugins/commentReservations.d.ts +0 -5
  221. package/dist/editor/plugins/commentReservations.js +0 -26
  222. package/dist/editor/plugins/styledParagraphs.d.ts +0 -15
  223. package/dist/editor/plugins/styledParagraphs.js +0 -65
  224. package/dist/page/tableMeasurements.d.ts +0 -18
  225. package/dist/page/tableMeasurements.js +0 -119
@@ -0,0 +1,174 @@
1
+ // src/docx/identities.ts
2
+ import { Fragment } from "prosemirror-model";
3
+ import { DocxExportError } from "../ooxml/errors.js";
4
+ import { qualify } from "../ooxml/names.js";
5
+ import { parseAttrs } from "../ooxml/tagScan.js";
6
+ import { docxSchema } from "../schema/index.js";
7
+ import { withoutParagraphIds } from "./cloning.js";
8
+ import { copiedControlPrefix, newControlId } from "./sdt.js";
9
+ var sourceBlockRule = {
10
+ name: "sourceBlock",
11
+ visit(block, written) {
12
+ const srcId = block.attrs.srcId;
13
+ if (typeof srcId !== "string" && typeof srcId !== "number") return block;
14
+ const name = String(srcId);
15
+ if (!written.has(name)) {
16
+ written.add(name);
17
+ return block;
18
+ }
19
+ if (block.type.isInGroup("preserved")) return null;
20
+ return block.type.create(
21
+ { ...block.attrs, srcId: null },
22
+ block.content,
23
+ block.marks
24
+ );
25
+ }
26
+ };
27
+ var PARA_ID = qualify("w14", "paraId");
28
+ var LONG_HEX = /^[0-9A-Fa-f]{8}$/;
29
+ function paragraphIdOf(pAttrs) {
30
+ if (typeof pAttrs !== "string") return null;
31
+ const value = parseAttrs(pAttrs)?.find(([name]) => name === PARA_ID)?.[1];
32
+ if (value === void 0 || !LONG_HEX.test(value)) return null;
33
+ const id = Number.parseInt(value, 16);
34
+ return id > 0 && id < 2147483648 ? id : null;
35
+ }
36
+ var paragraphIdRule = {
37
+ name: "paragraphId",
38
+ visit(block, written) {
39
+ if (block.type !== docxSchema.nodes.paragraph) return block;
40
+ const id = paragraphIdOf(block.attrs.pAttrs);
41
+ if (id === null) return block;
42
+ const name = String(id);
43
+ if (!written.has(name)) {
44
+ written.add(name);
45
+ return block;
46
+ }
47
+ return block.type.create(
48
+ { ...block.attrs, pAttrs: withoutParagraphIds(block.attrs.pAttrs) },
49
+ block.content,
50
+ block.marks
51
+ );
52
+ }
53
+ };
54
+ function sdtMarkOf(node) {
55
+ return node.marks.find((mark) => mark.type === docxSchema.marks.sdt) ?? null;
56
+ }
57
+ function controlName(mark) {
58
+ const key = mark.attrs.sdtKey;
59
+ const prefix = mark.attrs.sdtPrefix;
60
+ return `${typeof key === "number" ? key : 0} ${typeof prefix === "string" ? prefix : ""}`;
61
+ }
62
+ function copiedMark(mark) {
63
+ const prefix = mark.attrs.sdtPrefix;
64
+ if (typeof prefix !== "string") return mark;
65
+ return mark.type.create({
66
+ ...mark.attrs,
67
+ sdtPrefix: copiedControlPrefix(prefix, newControlId())
68
+ });
69
+ }
70
+ function claim(mark, written) {
71
+ const name = controlName(mark);
72
+ const copy = written.has(name) ? copiedMark(mark) : null;
73
+ written.add(name);
74
+ return { mark, copy };
75
+ }
76
+ function rewriteParagraph(paragraph, written) {
77
+ const inline = [];
78
+ let running = null;
79
+ let renamed = false;
80
+ paragraph.forEach((child) => {
81
+ const mark = sdtMarkOf(child);
82
+ if (!mark) {
83
+ running = null;
84
+ inline.push(child);
85
+ return;
86
+ }
87
+ const control = running?.mark.eq(mark) ? running : claim(mark, written);
88
+ running = control;
89
+ if (!control.copy) {
90
+ inline.push(child);
91
+ return;
92
+ }
93
+ renamed = true;
94
+ inline.push(
95
+ child.mark(control.copy.addToSet(mark.removeFromSet(child.marks)))
96
+ );
97
+ });
98
+ return renamed ? paragraph.copy(Fragment.fromArray(inline)) : paragraph;
99
+ }
100
+ var controlRule = {
101
+ name: "control",
102
+ visit(block, written) {
103
+ return block.type === docxSchema.nodes.paragraph ? rewriteParagraph(block, written) : block;
104
+ }
105
+ };
106
+ var IDENTITY_RULES = [
107
+ sourceBlockRule,
108
+ paragraphIdRule,
109
+ controlRule
110
+ ];
111
+ function refusalOf(block, pos) {
112
+ return {
113
+ code: "unsupported-content",
114
+ message: `a preserved block stands in two places (${block.type.name})`,
115
+ pos
116
+ };
117
+ }
118
+ function visitBlock(block, pos, walk) {
119
+ let current = block;
120
+ for (const [index, rule] of walk.rules.entries()) {
121
+ const next = rule.visit(current, walk.written[index]);
122
+ if (next === null) {
123
+ walk.refuse(refusalOf(block, pos));
124
+ return current;
125
+ }
126
+ current = next;
127
+ }
128
+ return current;
129
+ }
130
+ function rewriteBlock(block, pos, walk) {
131
+ const visited = visitBlock(block, pos, walk);
132
+ if (visited.inlineContent || visited.childCount === 0) return visited;
133
+ const children = [];
134
+ let changed = false;
135
+ visited.forEach((child, offset) => {
136
+ const next = rewriteBlock(child, pos + 1 + offset, walk);
137
+ changed ||= next !== child;
138
+ children.push(next);
139
+ });
140
+ return changed ? visited.copy(Fragment.fromArray(children)) : visited;
141
+ }
142
+ function walkBlocks(doc, rules, refuse) {
143
+ const walk = {
144
+ rules,
145
+ written: rules.map(() => /* @__PURE__ */ new Set()),
146
+ refuse
147
+ };
148
+ const blocks = [];
149
+ let changed = false;
150
+ doc.forEach((block, offset) => {
151
+ const next = rewriteBlock(block, offset, walk);
152
+ changed ||= next !== block;
153
+ blocks.push(next);
154
+ });
155
+ return changed ? doc.copy(Fragment.fromArray(blocks)) : doc;
156
+ }
157
+ function withUniqueIdentities(doc, rules = IDENTITY_RULES) {
158
+ return walkBlocks(doc, rules, (problem) => {
159
+ throw new DocxExportError(problem.code, problem.message);
160
+ });
161
+ }
162
+ function identityProblems(doc, rules = IDENTITY_RULES) {
163
+ const problems = [];
164
+ walkBlocks(doc, rules, (problem) => problems.push(problem));
165
+ return problems;
166
+ }
167
+ export {
168
+ IDENTITY_RULES,
169
+ controlRule,
170
+ identityProblems,
171
+ paragraphIdRule,
172
+ sourceBlockRule,
173
+ withUniqueIdentities
174
+ };
@@ -4,6 +4,8 @@
4
4
  * This module knows nothing about the screen. All it knows is the file and the document model.
5
5
  */
6
6
  import { type Node as PMNode } from "prosemirror-model";
7
+ import { type XmlParser } from "../ooxml/xml";
8
+ import { type FidelityNote } from "./fidelity";
7
9
  import { SessionStore } from "./session";
8
10
  /** A docx file as bytes, however it arrived (file input, fetch, filesystem) */
9
11
  export type DocxBytes = ArrayBuffer | Uint8Array;
@@ -15,7 +17,16 @@ export type DocxBytes = ArrayBuffer | Uint8Array;
15
17
  * engine on `./core` stays synchronous and bytes-only.
16
18
  */
17
19
  export type DocxSource = DocxBytes | Blob;
18
- export declare function importDocx(input: DocxBytes): {
20
+ /** What a caller may say about a read beyond handing over the bytes */
21
+ export interface ImportOptions {
22
+ /**
23
+ * The parser every part of the package is read through. Left out, the `DOMParser` global is
24
+ * used, and a runtime carrying none refuses the read with `no-xml-parser`.
25
+ */
26
+ xmlParser?: XmlParser;
27
+ }
28
+ export declare function importDocx(input: DocxBytes, options?: ImportOptions): {
19
29
  doc: PMNode;
20
30
  session: SessionStore;
31
+ notes: FidelityNote[];
21
32
  };
@@ -1,6 +1,5 @@
1
1
  // src/docx/importDocx.ts
2
2
  import { Fragment } from "prosemirror-model";
3
- import { toRunFormat } from "../model/format.js";
4
3
  import { parseNumbering } from "../numbering/parseNumbering.js";
5
4
  import { DocxImportError } from "../ooxml/errors.js";
6
5
  import {
@@ -9,24 +8,26 @@ import {
9
8
  elementChildren,
10
9
  localPart,
11
10
  parseXml,
12
- R_NS
11
+ R_NS,
12
+ withXmlParser
13
13
  } from "../ooxml/xml.js";
14
14
  import { docxSchema } from "../schema/index.js";
15
15
  import { commentReferencesIn, readComments } from "./comments.js";
16
16
  import { openParts } from "./container.js";
17
- import { DEFAULT_TAB_STOP_PT, readDefaultTabStop } from "./documentSettings.js";
18
17
  import {
19
- defaultParagraphStyleIdOf,
20
- defaultTableStyleIdOf,
21
- effectiveParagraphFormat,
22
- effectiveParagraphStyle,
23
- layerRunFormat,
18
+ DEFAULT_TAB_STOP_PT,
19
+ readCompatSettings,
20
+ readDefaultTabStop
21
+ } from "./documentSettings.js";
22
+ import { fidelityNotesOf } from "./fidelity.js";
23
+ import {
24
+ formattingContextOf,
24
25
  NO_DOCUMENT_DEFAULTS,
25
- NO_STYLES,
26
- readDefaultParagraphFormat,
26
+ paragraphAttrsOf,
27
27
  readDocumentDefaults,
28
28
  readParagraphStyles,
29
- readStyles
29
+ resolveParagraph,
30
+ runMarkUnder
30
31
  } from "./formatting.js";
31
32
  import { readHeadersFooters } from "./headersFooters.js";
32
33
  import { readLinkTargets } from "./hyperlink.js";
@@ -34,28 +35,26 @@ import { buildParagraph } from "./importParagraph.js";
34
35
  import { buildTable } from "./importTable.js";
35
36
  import { readImageSources } from "./media.js";
36
37
  import { readNotes } from "./notes.js";
38
+ import { readPart, relatedPartPath } from "./packageParts.js";
37
39
  import { readBodyGeometry } from "./pageGeometry.js";
38
- import { resolveTarget } from "./relationships.js";
40
+ import { readRelationships } from "./relationships.js";
39
41
  import { scanBody } from "./scan.js";
40
- import { SessionStore } from "./session.js";
42
+ import {
43
+ BODY_STORY_KEY,
44
+ blockKey,
45
+ newSessionId,
46
+ SessionStore
47
+ } from "./session.js";
41
48
  import { NO_THEME_FONTS, readThemeFonts } from "./theme.js";
42
49
  var OFFICE_DOCUMENT_REL = `${R_NS}/officeDocument`;
43
50
  var STYLES_REL = `${R_NS}/styles`;
44
51
  var NUMBERING_REL = `${R_NS}/numbering`;
45
52
  var THEME_REL = `${R_NS}/theme`;
46
53
  var SETTINGS_REL = `${R_NS}/settings`;
47
- function relationshipTarget(parts, relsPath, type) {
48
- const rels = parts.get(relsPath);
49
- if (!rels) return null;
50
- for (const rel of elementChildren(
51
- parseXml(decodeUtf8(rels).text).documentElement
52
- )) {
53
- if (rel.getAttribute("Type") === type) return rel.getAttribute("Target");
54
- }
55
- return null;
56
- }
57
54
  function findMainPartPath(parts) {
58
- const target = relationshipTarget(parts, "_rels/.rels", OFFICE_DOCUMENT_REL);
55
+ const target = readRelationships(parts, "_rels/.rels").find(
56
+ (rel) => rel.type === OFFICE_DOCUMENT_REL
57
+ )?.target;
59
58
  if (!target) {
60
59
  throw new DocxImportError(
61
60
  "missing-part",
@@ -64,22 +63,7 @@ function findMainPartPath(parts) {
64
63
  }
65
64
  return target.replace(/^\//, "");
66
65
  }
67
- function relatedPartPath(parts, mainPartPath, type) {
68
- const directory = mainPartPath.replace(/[^/]+$/, "");
69
- const fileName = mainPartPath.slice(directory.length);
70
- const target = relationshipTarget(
71
- parts,
72
- `${directory}_rels/${fileName}.rels`,
73
- type
74
- );
75
- if (!target) return null;
76
- return resolveTarget(mainPartPath, target);
77
- }
78
- function readPart(parts, path) {
79
- const bytes = path === null ? void 0 : parts.get(path);
80
- return bytes ? decodeUtf8(bytes).text : null;
81
- }
82
- function buildBlock(el, srcId, sources, styles, defaultTableStyleId) {
66
+ function buildBlock(el, srcId, sources, context) {
83
67
  if (el.localName === "bookmarkStart" || el.localName === "bookmarkEnd") {
84
68
  return docxSchema.nodes.bookmarkBlock.create({
85
69
  srcId,
@@ -91,27 +75,34 @@ function buildBlock(el, srcId, sources, styles, defaultTableStyleId) {
91
75
  if (paragraph) return paragraph;
92
76
  }
93
77
  if (el.localName === "tbl") {
94
- const table = buildTable(el, srcId, sources, styles, defaultTableStyleId);
78
+ const table = buildTable(
79
+ el,
80
+ srcId,
81
+ sources,
82
+ context.styles,
83
+ context.defaultTableStyleId
84
+ );
95
85
  if (table) return table;
96
86
  }
97
87
  return docxSchema.nodes.docxRaw.create({ srcId, name: el.nodeName });
98
88
  }
99
- function styledInline(node, style) {
100
- const mark = node.marks.find((entry) => entry.type === docxSchema.marks.run);
101
- if (!mark) return node;
102
- const format = layerRunFormat(style, toRunFormat(mark.attrs.format));
103
- const next = mark.type.create({ ...mark.attrs, format });
104
- return node.mark(next.addToSet(node.marks));
105
- }
106
89
  function styledParagraph(node, context) {
107
- const style = effectiveParagraphStyle(node.attrs.pPr, context);
108
- const inline = style ? node.children.map((child) => styledInline(child, style.run)) : node.children;
90
+ const pPr = node.attrs.pPr;
91
+ const paragraph = resolveParagraph(
92
+ typeof pPr === "string" ? pPr : null,
93
+ context
94
+ );
95
+ const inline = node.children.map((child) => {
96
+ const mark = runMarkUnder(
97
+ child.marks.find((entry) => entry.type === docxSchema.marks.run) ?? null,
98
+ child.isText,
99
+ paragraph,
100
+ context
101
+ );
102
+ return mark ? child.mark(mark.addToSet(child.marks)) : child;
103
+ });
109
104
  return node.type.create(
110
- {
111
- ...node.attrs,
112
- format: effectiveParagraphFormat(node.attrs.pPr, context),
113
- styleRun: style ? layerRunFormat(style.run, null) : null
114
- },
105
+ { ...node.attrs, ...paragraphAttrsOf(paragraph) },
115
106
  Fragment.fromArray(inline),
116
107
  node.marks
117
108
  );
@@ -153,7 +144,10 @@ function foldTrailingSectPr(scan) {
153
144
  suffix: last.xml + scan.suffix
154
145
  };
155
146
  }
156
- function importDocx(input) {
147
+ function importDocx(input, options) {
148
+ return withXmlParser(options?.xmlParser, () => readDocx(input));
149
+ }
150
+ function readDocx(input) {
157
151
  const bytes = input instanceof Uint8Array ? input : new Uint8Array(input);
158
152
  const parts = openParts(bytes);
159
153
  const mainPartPath = findMainPartPath(parts);
@@ -182,25 +176,21 @@ function importDocx(input) {
182
176
  parts,
183
177
  relatedPartPath(parts, mainPartPath, SETTINGS_REL)
184
178
  );
185
- const defaultTabStopPt = readDefaultTabStop(settingsXml === null ? null : parseXml(settingsXml)) ?? DEFAULT_TAB_STOP_PT;
179
+ const settingsDom = settingsXml === null ? null : parseXml(settingsXml);
180
+ const defaultTabStopPt = readDefaultTabStop(settingsDom) ?? DEFAULT_TAB_STOP_PT;
186
181
  const numberingPartPath = relatedPartPath(parts, mainPartPath, NUMBERING_REL);
187
182
  const themeXml = readPart(
188
183
  parts,
189
184
  relatedPartPath(parts, mainPartPath, THEME_REL)
190
185
  );
191
186
  const themeFonts = themeXml === null ? NO_THEME_FONTS : readThemeFonts(parseXml(themeXml));
192
- const styles = stylesDom ? readStyles(stylesDom, themeFonts) : NO_STYLES;
193
- const defaultTableStyleId = stylesDom ? defaultTableStyleIdOf(stylesDom) : null;
194
- const defaultParagraphStyleId = stylesDom ? defaultParagraphStyleIdOf(stylesDom) : null;
195
- const paragraphDefaults = stylesDom ? readDefaultParagraphFormat(stylesDom) : {};
196
187
  const numberingXml = readPart(parts, numberingPartPath);
197
- const numbering = parseNumbering(numberingXml);
198
- const paragraphFormatting = {
199
- styles,
200
- defaultStyleId: defaultParagraphStyleId,
201
- defaults: paragraphDefaults,
202
- numbering
203
- };
188
+ const formatting = formattingContextOf(
189
+ stylesDom,
190
+ parseNumbering(numberingXml),
191
+ themeFonts,
192
+ readCompatSettings(settingsDom)
193
+ );
204
194
  const comments = readComments(parts, mainPartPath);
205
195
  const notes = readNotes(parts, mainPartPath);
206
196
  const noteLabels = {
@@ -224,15 +214,24 @@ function importDocx(input) {
224
214
  notes,
225
215
  noteLabel
226
216
  };
217
+ const sessionId = newSessionId();
227
218
  const blockNodes = blockElements.map(
228
219
  (el, i) => withStyleFormats(
229
- buildBlock(el, i, sources, styles, defaultTableStyleId),
230
- paragraphFormatting
220
+ buildBlock(
221
+ el,
222
+ blockKey({ sessionId }, BODY_STORY_KEY, i),
223
+ sources,
224
+ formatting
225
+ ),
226
+ formatting
231
227
  )
232
228
  );
229
+ const doc = docxSchema.nodes.doc.create(null, blockNodes);
233
230
  return {
234
- doc: docxSchema.nodes.doc.create(null, blockNodes),
231
+ doc,
232
+ notes: fidelityNotesOf(doc, mainPartPath),
235
233
  session: new SessionStore({
234
+ sessionId,
236
235
  parts,
237
236
  mainPartPath,
238
237
  documentPrefix: scan.prefix,
@@ -241,19 +240,13 @@ function importDocx(input) {
241
240
  blocks: blockNodes.map((node, i) => ({ xml: scan.blocks[i].xml, node })),
242
241
  defaults: stylesDom ? readDocumentDefaults(stylesDom, themeFonts) : NO_DOCUMENT_DEFAULTS,
243
242
  defaultTabStopPt,
244
- paragraphDefaults,
245
243
  geometry,
246
- styles,
244
+ formatting,
247
245
  paragraphStyles: stylesDom ? readParagraphStyles(stylesDom) : [],
248
- defaultParagraphStyleId,
249
246
  numberingXml,
250
247
  numberingPartPath,
251
248
  comments,
252
- commentReferenceIds: new Set(
253
- commentReferencesIn(
254
- docxSchema.nodes.doc.create(null, blockNodes)
255
- ).keys()
256
- ),
249
+ commentReferenceIds: new Set(commentReferencesIn(doc).keys()),
257
250
  headersFooters
258
251
  })
259
252
  };
@@ -29,4 +29,4 @@ export interface ImportSources {
29
29
  }
30
30
  export declare const NO_IMPORT_SOURCES: ImportSources;
31
31
  /** Moves a paragraph into an editable node. null if it holds content we do not model */
32
- export declare function buildParagraph(el: Element, srcId: number | null, sources?: ImportSources): PMNode | null;
32
+ export declare function buildParagraph(el: Element, srcId: string | null, sources?: ImportSources): PMNode | null;
@@ -1,6 +1,8 @@
1
1
  // src/docx/importParagraph.ts
2
2
  import { readDrawingPicture } from "../ooxml/image.js";
3
+ import { ST_OnOff } from "../ooxml/simpleTypes.js";
3
4
  import {
5
+ attributeByLocalName,
4
6
  attrString,
5
7
  childByLocalName,
6
8
  elementChildren,
@@ -104,9 +106,8 @@ function buildRunChild(el, marks, images, comments, notes, noteLabel) {
104
106
  if (id === null) return null;
105
107
  const kind = el.localName === "footnoteReference" ? "footnote" : "endnote";
106
108
  const note = noteById(notes, kind, id);
107
- const customMarkFollows = Array.from(el.attributes).some(
108
- (entry) => entry.localName === "customMarkFollows" && !["0", "false", "off"].includes(entry.value)
109
- );
109
+ const written = attributeByLocalName(el, "customMarkFollows");
110
+ const customMarkFollows = written !== null && (ST_OnOff.parse(written) ?? true);
110
111
  return [
111
112
  docxSchema.nodes.noteReference.create(
112
113
  {
@@ -6,4 +6,4 @@ import type { Node as PMNode } from "prosemirror-model";
6
6
  import { type StyleTable } from "./formatting";
7
7
  import { type ImportSources } from "./importParagraph";
8
8
  /** Moves a `<w:tbl>` into a table node. null if it cannot be modelled */
9
- export declare function buildTable(el: Element, srcId: number | null, sources?: ImportSources, styles?: StyleTable, defaultTableStyleId?: string | null): PMNode | null;
9
+ export declare function buildTable(el: Element, srcId: string | null, sources?: ImportSources, styles?: StyleTable, defaultTableStyleId?: string | null): PMNode | null;
@@ -86,9 +86,23 @@ function readRow(el) {
86
86
  }
87
87
  return cells.length > 0 ? { el, tblPrEx, cells } : null;
88
88
  }
89
+ function gridRevisionXml(grid) {
90
+ const revision = childByLocalName(grid, "tblGridChange");
91
+ if (revision === null) return null;
92
+ const declarations = Array.from(grid.attributes).filter(
93
+ (attr) => attr.namespaceURI === "http://www.w3.org/2000/xmlns/" && !revision.hasAttribute(attr.name)
94
+ );
95
+ if (declarations.length === 0) return serializeXml(revision);
96
+ const preserved = revision.ownerDocument.importNode(revision, true);
97
+ for (const attr of declarations) {
98
+ preserved.setAttributeNS(attr.namespaceURI, attr.name, attr.value);
99
+ }
100
+ return serializeXml(preserved);
101
+ }
89
102
  function readTableParts(el) {
90
103
  let tblPr = null;
91
104
  let tblGrid = null;
105
+ let gridChange = null;
92
106
  const rows = [];
93
107
  for (const child of elementChildren(el)) {
94
108
  if (child.localName === "tblPr") {
@@ -97,6 +111,7 @@ function readTableParts(el) {
97
111
  }
98
112
  if (child.localName === "tblGrid") {
99
113
  tblGrid = child;
114
+ gridChange = gridRevisionXml(child);
100
115
  continue;
101
116
  }
102
117
  if (child.localName !== "tr") return null;
@@ -104,7 +119,7 @@ function readTableParts(el) {
104
119
  if (!row) return null;
105
120
  rows.push(row);
106
121
  }
107
- return rows.length > 0 ? { tblPr, tblGrid, rows } : null;
122
+ return rows.length > 0 ? { tblPr, tblGrid, gridChange, rows } : null;
108
123
  }
109
124
  function resolveVerticalMerges(rows, width) {
110
125
  const drafts = [];
@@ -262,6 +277,7 @@ function buildTable(el, srcId, sources = NO_IMPORT_SOURCES, styles = NO_STYLES,
262
277
  tblPr: parts.tblPr ? serializeXml(parts.tblPr) : null,
263
278
  tblW: readTableWidth(parts.tblPr, "tblW"),
264
279
  gridCols,
280
+ gridChange: parts.gridChange,
265
281
  format: tableFormat,
266
282
  // The cells need these again whenever an edit derives their display values afresh
267
283
  styleInside: toInsideBorders(style?.tableInside),
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Known export refusals, asked of the document before anything is written.
3
+ *
4
+ * Each invariant reads what the writer would refuse over and reports it with the code the writer
5
+ * would throw, so a screen can ask at edit time what `exportDocx` would say. The list is walked in
6
+ * order and `exportDocx` throws its first entry, which is what keeps the two from disagreeing.
7
+ *
8
+ * The checks inspect model attrs and preserved XML without running the writers. Bookmark
9
+ * fragments and list definitions use the export parser. `assertBookmarkPairs` in `./exportDocx`
10
+ * and `assertPartsParse` in `./partPlan` remain the final checks over the parts as actually written.
11
+ */
12
+ import type { Node as PMNode } from "prosemirror-model";
13
+ import type { DocxExportErrorCode } from "../ooxml/errors";
14
+ import type { ExportOptions } from "./exportDocx";
15
+ import { type DocxSession, type SessionStore } from "./session";
16
+ /** One reason the document cannot be written back, with the code `exportDocx` would throw it under */
17
+ export interface ExportProblem {
18
+ readonly code: DocxExportErrorCode;
19
+ readonly message: string;
20
+ /** Where the problem stands in the document. Absent for a problem of the package or of the session */
21
+ readonly pos?: number;
22
+ }
23
+ /** The problems as the writer sees them, for a caller already inside the writer's parser scope */
24
+ export declare function problemsOf(doc: PMNode, session: SessionStore): readonly ExportProblem[];
25
+ /**
26
+ * Known reasons writing this document back would be refused, in the order `exportDocx` would
27
+ * raise them. An empty list does not rule out failures while writing. Each entry carries the code and message the
28
+ * `DocxExportError` would carry, and the position in the document where there is one.
29
+ *
30
+ * The list definitions are read to tell a new list from one the document already had, so this
31
+ * needs an XML parser the way `exportDocx` does and takes the same option.
32
+ */
33
+ export declare function exportProblems(doc: PMNode, session: DocxSession, options?: ExportOptions): readonly ExportProblem[];