@stll/folio-core 0.7.0 → 0.9.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 (193) hide show
  1. package/README.md +39 -0
  2. package/dist/ai-edits/apply.js +18 -4
  3. package/dist/ai-edits/blockRange.d.ts +13 -2
  4. package/dist/ai-edits/blockRange.js +23 -2
  5. package/dist/ai-edits/headless.d.ts +31 -4
  6. package/dist/ai-edits/headless.js +148 -35
  7. package/dist/ai-edits/index.d.ts +6 -4
  8. package/dist/ai-edits/index.js +4 -1
  9. package/dist/ai-edits/scoped-reading.d.ts +9 -0
  10. package/dist/ai-edits/scoped-reading.js +60 -0
  11. package/dist/ai-edits/snapshot.js +53 -7
  12. package/dist/ai-edits/types.d.ts +46 -3
  13. package/dist/compat/eigenpal.d.ts +8 -3
  14. package/dist/compat/eigenpal.js +7 -2
  15. package/dist/controller/fontReadiness.d.ts +29 -0
  16. package/dist/controller/fontReadiness.js +139 -0
  17. package/dist/controller/latestRequestGate.d.ts +13 -0
  18. package/dist/controller/latestRequestGate.js +16 -0
  19. package/dist/controller/layoutPipeline.js +88 -10
  20. package/dist/document-operations.d.ts +10 -3
  21. package/dist/document-operations.js +29 -14
  22. package/dist/docx/blockContentParser.js +53 -10
  23. package/dist/docx/commentParser.js +1 -1
  24. package/dist/docx/compatibility.d.ts +30 -2
  25. package/dist/docx/compatibility.js +118 -39
  26. package/dist/docx/conformance.d.ts +6 -0
  27. package/dist/docx/conformance.js +18 -0
  28. package/dist/docx/encryption/agileDecryption.js +1 -1
  29. package/dist/docx/encryption/encryptionInfo.js +1 -1
  30. package/dist/docx/encryption/openEncryptedDocx.js +1 -1
  31. package/dist/docx/ensureParaIds.d.ts +29 -0
  32. package/dist/docx/ensureParaIds.js +423 -0
  33. package/dist/docx/fontTableParser.d.ts +6 -0
  34. package/dist/docx/fontTableParser.js +72 -0
  35. package/dist/docx/groupDrawingParser.js +7 -2
  36. package/dist/docx/headerFooterParser.js +1 -1
  37. package/dist/docx/normalizeBaseDirection.js +1 -1
  38. package/dist/docx/numberingParser.js +2 -0
  39. package/dist/docx/paragraphParser.js +21 -1
  40. package/dist/docx/paragraphTextBoxEnrichment.js +141 -2
  41. package/dist/docx/parser.d.ts +1 -1
  42. package/dist/docx/parser.js +14 -9
  43. package/dist/docx/rezip.js +70 -5
  44. package/dist/docx/runConsolidator.js +4 -0
  45. package/dist/docx/runParser.js +19 -1
  46. package/dist/docx/selectiveSave.js +3 -3
  47. package/dist/docx/selectiveXmlPatch.d.ts +10 -1
  48. package/dist/docx/selectiveXmlPatch.js +1 -1
  49. package/dist/docx/serializer/fontTableSerializer.d.ts +6 -0
  50. package/dist/docx/serializer/fontTableSerializer.js +26 -0
  51. package/dist/docx/serializer/headerFooterSerializer.js +1 -1
  52. package/dist/docx/serializer/paragraphSerializer.js +8 -0
  53. package/dist/docx/serializer/runSerializer.js +14 -2
  54. package/dist/docx/serializer/settingsSerializer.d.ts +6 -0
  55. package/dist/docx/serializer/settingsSerializer.js +16 -0
  56. package/dist/docx/serializer/stylesSerializer.d.ts +6 -0
  57. package/dist/docx/serializer/stylesSerializer.js +56 -0
  58. package/dist/docx/serializer/tableSerializer.js +29 -26
  59. package/dist/docx/serializer/themeSerializer.d.ts +6 -0
  60. package/dist/docx/serializer/themeSerializer.js +36 -0
  61. package/dist/docx/settingsParser.js +46 -0
  62. package/dist/docx/styleParser.js +26 -1
  63. package/dist/docx/tableParser.js +19 -1
  64. package/dist/docx/textBoxParser.js +6 -1
  65. package/dist/docx/vmlImageParser.js +146 -1
  66. package/dist/i18n/messages/catalogs.gen.d.ts +5916 -5916
  67. package/dist/i18n/messages/catalogs.gen.js +5910 -5910
  68. package/dist/index.d.ts +8 -3
  69. package/dist/index.js +7 -2
  70. package/dist/layout-bridge/convert/footnoteLayout.d.ts +3 -0
  71. package/dist/layout-bridge/convert/footnoteLayout.js +3 -1
  72. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +3 -0
  73. package/dist/layout-bridge/convert/headerFooterLayout.js +22 -3
  74. package/dist/layout-bridge/convert/paragraphFrames.d.ts +7 -0
  75. package/dist/layout-bridge/convert/paragraphFrames.js +136 -0
  76. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +14 -2
  77. package/dist/layout-bridge/convert/toFlowBlocks.js +93 -17
  78. package/dist/layout-bridge/engine/hitTest.js +2 -1
  79. package/dist/layout-bridge/engine/measuring/index.d.ts +2 -1
  80. package/dist/layout-bridge/engine/measuring/index.js +2 -1
  81. package/dist/layout-bridge/engine/selectionRects.js +2 -1
  82. package/dist/layout-engine/headerFooterRefs.d.ts +7 -0
  83. package/dist/layout-engine/headerFooterRefs.js +40 -0
  84. package/dist/layout-engine/index.d.ts +3 -2
  85. package/dist/layout-engine/index.js +68 -106
  86. package/dist/layout-engine/measure/cache.js +11 -3
  87. package/dist/layout-engine/measure/font-metrics.worker.js +1 -0
  88. package/dist/layout-engine/measure/index.d.ts +2 -1
  89. package/dist/layout-engine/measure/index.js +2 -1
  90. package/dist/layout-engine/measure/lineBreakProvider.d.ts +33 -0
  91. package/dist/layout-engine/measure/lineBreakProvider.js +252 -0
  92. package/dist/layout-engine/measure/lineBreaks.d.ts +7 -2
  93. package/dist/layout-engine/measure/lineBreaks.js +11 -18
  94. package/dist/layout-engine/measure/listMarkerWidth.d.ts +4 -1
  95. package/dist/layout-engine/measure/listMarkerWidth.js +33 -8
  96. package/dist/layout-engine/measure/measureBlocks.d.ts +4 -2
  97. package/dist/layout-engine/measure/measureBlocks.js +138 -86
  98. package/dist/layout-engine/measure/measureContainer.js +32 -9
  99. package/dist/layout-engine/measure/measureHelpers.js +5 -2
  100. package/dist/layout-engine/measure/measureParagraph.js +346 -74
  101. package/dist/layout-engine/measure/measureTypes.d.ts +2 -1
  102. package/dist/layout-engine/measure/measureWorker.d.ts +2 -2
  103. package/dist/layout-engine/measure/measureWorker.js +8 -19
  104. package/dist/layout-engine/measure/measureWorkerProtocol.d.ts +3 -14
  105. package/dist/layout-engine/measure/tableCellFloating.d.ts +10 -3
  106. package/dist/layout-engine/measure/tableCellFloating.js +37 -29
  107. package/dist/layout-engine/measure/tableCellFlow.d.ts +27 -0
  108. package/dist/layout-engine/measure/tableCellFlow.js +73 -0
  109. package/dist/layout-engine/measure/tableCellGrid.d.ts +15 -0
  110. package/dist/layout-engine/measure/tableCellGrid.js +62 -0
  111. package/dist/layout-engine/measure/textBoxParagraphLayout.d.ts +18 -0
  112. package/dist/layout-engine/measure/textBoxParagraphLayout.js +32 -0
  113. package/dist/layout-engine/measure/textMeasurementPolicy.d.ts +18 -0
  114. package/dist/layout-engine/measure/textMeasurementPolicy.js +24 -0
  115. package/dist/layout-engine/paginator.d.ts +2 -1
  116. package/dist/layout-engine/paginator.js +7 -6
  117. package/dist/layout-engine/paragraphFrame.d.ts +22 -0
  118. package/dist/layout-engine/paragraphFrame.js +17 -0
  119. package/dist/layout-engine/paragraphSequence.d.ts +7 -0
  120. package/dist/layout-engine/paragraphSequence.js +25 -0
  121. package/dist/layout-engine/paragraphSpacing.d.ts +17 -0
  122. package/dist/layout-engine/paragraphSpacing.js +30 -0
  123. package/dist/layout-engine/renderedBreakReconciliation.d.ts +63 -0
  124. package/dist/layout-engine/renderedBreakReconciliation.js +86 -0
  125. package/dist/layout-engine/tableRowBreak.d.ts +5 -2
  126. package/dist/layout-engine/tableRowBreak.js +62 -29
  127. package/dist/layout-engine/types.d.ts +54 -12
  128. package/dist/layout-engine/types.js +15 -2
  129. package/dist/layout-painter/anchoredImagePosition.d.ts +23 -0
  130. package/dist/layout-painter/anchoredImagePosition.js +95 -0
  131. package/dist/layout-painter/borderStroke.d.ts +23 -0
  132. package/dist/layout-painter/borderStroke.js +39 -0
  133. package/dist/layout-painter/renderImage.d.ts +5 -4
  134. package/dist/layout-painter/renderImage.js +18 -4
  135. package/dist/layout-painter/renderPage.d.ts +2 -27
  136. package/dist/layout-painter/renderPage.js +15 -101
  137. package/dist/layout-painter/renderParagraph.js +45 -26
  138. package/dist/layout-painter/renderTable.d.ts +2 -0
  139. package/dist/layout-painter/renderTable.js +257 -47
  140. package/dist/layout-painter/renderTextBox.js +17 -7
  141. package/dist/managers/DocumentLoaderManager.d.ts +1 -1
  142. package/dist/managers/DocumentLoaderManager.js +2 -2
  143. package/dist/paged-layout/sectionBlockWidths.d.ts +3 -0
  144. package/dist/paged-layout/sectionBlockWidths.js +9 -0
  145. package/dist/paged-layout/sectionGeometry.js +1 -1
  146. package/dist/prosemirror/attrs/index.d.ts +4 -2
  147. package/dist/prosemirror/attrs/index.js +32 -2
  148. package/dist/prosemirror/commands/propertyChangeScope.js +1 -1
  149. package/dist/prosemirror/conversion/fromProseDoc.js +35 -18
  150. package/dist/prosemirror/conversion/toProseDoc.js +73 -37
  151. package/dist/prosemirror/extensions/StarterKit.js +2 -0
  152. package/dist/prosemirror/extensions/core/ParagraphExtension.js +8 -2
  153. package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +1 -1
  154. package/dist/prosemirror/extensions/features/ListExtension.js +2 -0
  155. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +68 -16
  156. package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +1 -0
  157. package/dist/prosemirror/extensions/marks/HighlightExtension.js +1 -1
  158. package/dist/prosemirror/extensions/marks/LanguageExtension.d.ts +7 -0
  159. package/dist/prosemirror/extensions/marks/LanguageExtension.js +30 -0
  160. package/dist/prosemirror/extensions/marks/RunShadingExtension.js +1 -1
  161. package/dist/prosemirror/extensions/marks/TextColorExtension.js +1 -1
  162. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +1 -1
  163. package/dist/prosemirror/extensions/marks/markUtils.js +12 -0
  164. package/dist/prosemirror/extensions/nodes/ImageExtension.js +2 -1
  165. package/dist/prosemirror/extensions/nodes/TableExtension.js +4 -2
  166. package/dist/prosemirror/extensions/nodes/TextBoxExtension.d.ts +2 -1
  167. package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +7 -0
  168. package/dist/prosemirror/schema/index.d.ts +2 -2
  169. package/dist/prosemirror/schema/marks.d.ts +6 -1
  170. package/dist/prosemirror/schema/nodes.d.ts +16 -12
  171. package/dist/prosemirror/styles/resolvedStyleAttrs.js +2 -0
  172. package/dist/prosemirror/utils/tabCalculator.d.ts +3 -1
  173. package/dist/prosemirror/utils/tabCalculator.js +12 -10
  174. package/dist/prosemirror/validation.js +4 -1
  175. package/dist/redline.js +13 -3
  176. package/dist/server.d.ts +9 -4
  177. package/dist/server.js +7 -2
  178. package/dist/style-sets/extract.d.ts +35 -0
  179. package/dist/style-sets/extract.js +123 -0
  180. package/dist/style-sets/stellaStyle.d.ts +13 -0
  181. package/dist/style-sets/stellaStyle.js +516 -0
  182. package/dist/style-sets/types.d.ts +31 -0
  183. package/dist/style-sets/types.js +5 -0
  184. package/dist/types/index.d.ts +2 -1
  185. package/dist/utils/createDocument.d.ts +12 -2
  186. package/dist/utils/createDocument.js +55 -36
  187. package/dist/utils/fontResolver.js +6 -6
  188. package/dist/utils/formatToStyle.js +1 -1
  189. package/dist/utils/hexId.d.ts +8 -1
  190. package/dist/utils/hexId.js +11 -3
  191. package/dist/utils/paragraphFormattingMerge.d.ts +14 -3
  192. package/dist/utils/paragraphFormattingMerge.js +14 -4
  193. package/package.json +5 -1
@@ -1,7 +1,77 @@
1
- import { findDeep, getChildElements, getLocalName } from "./xmlParser.js";
1
+ import { findDeep, getAttribute, getChildElements, getLocalName } from "./xmlParser.js";
2
+ import { pixelsToEmu } from "../utils/units.js";
2
3
  import { getTextBoxContentElement, isTextBoxDrawing, parseTextBox, parseTextBoxContent } from "./textBoxParser.js";
3
4
  import { parseParagraph } from "./paragraphParser.js";
4
5
  //#region src/docx/paragraphTextBoxEnrichment.ts
6
+ const VML_HORIZONTAL_RELATIVES = /* @__PURE__ */ new Set([
7
+ "character",
8
+ "column",
9
+ "insideMargin",
10
+ "leftMargin",
11
+ "margin",
12
+ "outsideMargin",
13
+ "page",
14
+ "rightMargin"
15
+ ]);
16
+ const VML_VERTICAL_RELATIVES = /* @__PURE__ */ new Set([
17
+ "insideMargin",
18
+ "line",
19
+ "margin",
20
+ "outsideMargin",
21
+ "page",
22
+ "paragraph",
23
+ "topMargin",
24
+ "bottomMargin"
25
+ ]);
26
+ const parseVmlStyle = (value) => {
27
+ const declarations = {};
28
+ for (const declaration of value?.split(";") ?? []) {
29
+ const separator = declaration.indexOf(":");
30
+ if (separator < 0) continue;
31
+ const key = declaration.slice(0, separator).trim().toLowerCase();
32
+ if (key) declarations[key] = declaration.slice(separator + 1).trim();
33
+ }
34
+ return declarations;
35
+ };
36
+ const vmlLengthToPixels = (value) => {
37
+ const match = /^(?<amount>-?(?:\d+(?:\.\d+)?|\.\d+))\s*(?<unit>pt|in|px|cm|mm|pc)?$/iu.exec(value?.trim() ?? "");
38
+ const amount = Number.parseFloat(match?.groups?.["amount"] ?? "");
39
+ if (!Number.isFinite(amount)) return;
40
+ switch (match?.groups?.["unit"]?.toLowerCase()) {
41
+ case "pt": return amount / 72 * 96;
42
+ case "in": return amount * 96;
43
+ case "cm": return amount / 2.54 * 96;
44
+ case "mm": return amount / 25.4 * 96;
45
+ case "pc": return amount * 16;
46
+ case "px":
47
+ case void 0: return amount;
48
+ default: return;
49
+ }
50
+ };
51
+ const horizontalRelativeTo = (value) => {
52
+ for (const relative of VML_HORIZONTAL_RELATIVES) if (relative.toLowerCase() === value?.toLowerCase()) return relative;
53
+ return "character";
54
+ };
55
+ const verticalRelativeTo = (value) => {
56
+ for (const relative of VML_VERTICAL_RELATIVES) if (relative.toLowerCase() === value?.toLowerCase()) return relative;
57
+ return "paragraph";
58
+ };
59
+ const parseVmlInsets = (textBoxEl) => {
60
+ const [left, top, right, bottom, extra] = getAttribute(textBoxEl, null, "inset")?.split(",").map((value) => vmlLengthToPixels(value)) ?? [];
61
+ if (extra !== void 0 || left === void 0 || top === void 0 || right === void 0 || bottom === void 0) return;
62
+ return {
63
+ left: pixelsToEmu(left),
64
+ top: pixelsToEmu(top),
65
+ right: pixelsToEmu(right),
66
+ bottom: pixelsToEmu(bottom)
67
+ };
68
+ };
69
+ const parseVmlFill = (shapeEl) => getAttribute(shapeEl, null, "filled")?.toLowerCase() === "f" ? { type: "none" } : void 0;
70
+ const vmlWrapType = (positioned, zIndex) => {
71
+ if (!positioned) return "inline";
72
+ if (Number.isFinite(zIndex) && zIndex < 0) return "behind";
73
+ return "inFront";
74
+ };
5
75
  const enrichParagraphTextBoxes = (paragraph, paraXml, styles, theme, numbering, rels, media) => {
6
76
  const xmlChildren = getChildElements(paraXml);
7
77
  let parsedIndex = 0;
@@ -11,7 +81,7 @@ const enrichParagraphTextBoxes = (paragraph, paraXml, styles, theme, numbering,
11
81
  if (parsedIndex < paragraph.content.length && paragraph.content[parsedIndex]?.type !== "run") parsedIndex += 1;
12
82
  continue;
13
83
  }
14
- const { textBoxDrawings, hasNonTextBoxContent } = scanRunForTextBoxDrawings(xmlChild);
84
+ const { textBoxDrawings, vmlTextBoxes, hasNonTextBoxContent } = scanRunForTextBoxDrawings(xmlChild);
15
85
  const parsedContent = paragraph.content[parsedIndex];
16
86
  const parsedRun = parsedContent?.type === "run" ? parsedContent : void 0;
17
87
  const targetRun = parsedRun ?? (hasNonTextBoxContent ? lastConsumedRun : void 0);
@@ -33,6 +103,7 @@ const enrichParagraphTextBoxes = (paragraph, paraXml, styles, theme, numbering,
33
103
  ...textBox.outline !== void 0 ? { outline: textBox.outline } : {},
34
104
  textBody: {
35
105
  content: textBox.content,
106
+ ...textBox.autoFit !== void 0 ? { autoFit: textBox.autoFit } : {},
36
107
  ...textBox.margins !== void 0 ? { margins: textBox.margins } : {}
37
108
  }
38
109
  };
@@ -52,6 +123,24 @@ const enrichParagraphTextBoxes = (paragraph, paraXml, styles, theme, numbering,
52
123
  parsedIndex += 1;
53
124
  }
54
125
  }
126
+ for (const pictEl of vmlTextBoxes) {
127
+ const shape = parseVmlTextBoxShape(pictEl, styles, theme, numbering, rels, media);
128
+ if (!shape) continue;
129
+ const shapeContent = {
130
+ type: "shape",
131
+ shape
132
+ };
133
+ if (targetRun && hasNonTextBoxContent) targetRun.content.push(shapeContent);
134
+ else {
135
+ const newRun = {
136
+ type: "run",
137
+ content: [shapeContent]
138
+ };
139
+ paragraph.content.splice(parsedIndex, 0, newRun);
140
+ lastConsumedRun = newRun;
141
+ parsedIndex += 1;
142
+ }
143
+ }
55
144
  if (hasNonTextBoxContent && parsedRun) {
56
145
  lastConsumedRun = parsedRun;
57
146
  parsedIndex += 1;
@@ -60,6 +149,7 @@ const enrichParagraphTextBoxes = (paragraph, paraXml, styles, theme, numbering,
60
149
  };
61
150
  const scanRunForTextBoxDrawings = (xmlRun) => {
62
151
  const textBoxDrawings = [];
152
+ const vmlTextBoxes = [];
63
153
  let hasNonTextBoxContent = false;
64
154
  const visitDrawing = (drawingEl) => {
65
155
  if (isTextBoxDrawing(drawingEl)) {
@@ -75,6 +165,11 @@ const scanRunForTextBoxDrawings = (xmlRun) => {
75
165
  visitDrawing(el);
76
166
  continue;
77
167
  }
168
+ if (name === "pict") {
169
+ if (findDeep(el, "v", "textbox")) vmlTextBoxes.push(el);
170
+ else hasNonTextBoxContent = true;
171
+ continue;
172
+ }
78
173
  if (name === "AlternateContent") {
79
174
  const branches = getChildElements(el);
80
175
  const choice = branches.find((branch) => getLocalName(branch.name ?? "") === "Choice");
@@ -97,8 +192,52 @@ const scanRunForTextBoxDrawings = (xmlRun) => {
97
192
  }
98
193
  return {
99
194
  textBoxDrawings,
195
+ vmlTextBoxes,
100
196
  hasNonTextBoxContent
101
197
  };
102
198
  };
199
+ const parseVmlTextBoxShape = (pictEl, styles, theme, numbering, rels, media) => {
200
+ const shapeEl = findDeep(pictEl, "v", "shape");
201
+ const textBoxEl = shapeEl ? findDeep(shapeEl, "v", "textbox") : null;
202
+ const contentEl = textBoxEl ? findDeep(textBoxEl, "w", "txbxContent") : null;
203
+ if (!shapeEl || !textBoxEl || !contentEl) return null;
204
+ const style = parseVmlStyle(getAttribute(shapeEl, null, "style"));
205
+ const width = vmlLengthToPixels(style["width"]);
206
+ const height = vmlLengthToPixels(style["height"]);
207
+ if (width === void 0 || height === void 0 || width <= 0 || height <= 0) return null;
208
+ const left = vmlLengthToPixels(style["margin-left"] ?? style["left"]);
209
+ const top = vmlLengthToPixels(style["margin-top"] ?? style["top"]);
210
+ const positioned = style["position"]?.toLowerCase() === "absolute";
211
+ const zIndex = Number.parseInt(style["z-index"] ?? "", 10);
212
+ const margins = parseVmlInsets(textBoxEl);
213
+ const fill = parseVmlFill(shapeEl);
214
+ const shape = {
215
+ type: "shape",
216
+ shapeType: "textBox",
217
+ size: {
218
+ width: pixelsToEmu(width),
219
+ height: pixelsToEmu(height)
220
+ },
221
+ ...fill === void 0 ? {} : { fill },
222
+ wrap: { type: vmlWrapType(positioned, zIndex) },
223
+ textBody: {
224
+ content: parseTextBoxContent(contentEl, parseParagraph, null, styles, theme, numbering, rels ?? void 0, media ?? void 0),
225
+ ...margins === void 0 ? {} : { margins }
226
+ }
227
+ };
228
+ const id = getAttribute(shapeEl, null, "id");
229
+ if (id) shape.id = id;
230
+ if (positioned) shape.position = {
231
+ horizontal: {
232
+ relativeTo: horizontalRelativeTo(style["mso-position-horizontal-relative"]),
233
+ ...left === void 0 ? {} : { posOffset: pixelsToEmu(left) }
234
+ },
235
+ vertical: {
236
+ relativeTo: verticalRelativeTo(style["mso-position-vertical-relative"]),
237
+ ...top === void 0 ? {} : { posOffset: pixelsToEmu(top) }
238
+ }
239
+ };
240
+ return shape;
241
+ };
103
242
  //#endregion
104
243
  export { enrichParagraphTextBoxes };
@@ -1,6 +1,6 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
- import { DocxUnzipOptions } from "./unzip.js";
3
2
  import { DocxInput } from "../utils/docxInput.js";
3
+ import { DocxUnzipOptions } from "./unzip.js";
4
4
 
5
5
  //#region src/docx/parser.d.ts
6
6
  /**
@@ -1,23 +1,25 @@
1
- import { RELATIONSHIP_TYPES, parseRelationships, resolveRelativePath } from "./relsParser.js";
2
- import { applyThemeFontLang, parseTheme } from "./themeParser.js";
3
- import { parseEndnotes, parseFootnotes } from "./footnoteParser.js";
4
- import { DocxModelValidationError, formatDocumentModelIssues, validateFolioDocumentModel } from "./modelValidation.js";
5
- import { parseNumbering } from "./numberingParser.js";
6
- import { DocxEncryptionError } from "./encryption/errors.js";
7
- import { getMediaMimeType, mediaToDataUrl, unzipDocx } from "./unzip.js";
8
- import { parseComments } from "./commentParser.js";
9
- import { parseFooter, parseHeader } from "./headerFooterParser.js";
10
1
  import { toArrayBuffer } from "../utils/docxInput.js";
11
2
  import { loadFontsWithMapping } from "../utils/fontLoader.js";
12
3
  import { convertTiffToPngDataUrl, isTiffMimeType } from "../utils/tiffConverter.js";
4
+ import { RELATIONSHIP_TYPES, parseRelationships, resolveRelativePath } from "./relsParser.js";
5
+ import { applyThemeFontLang, parseTheme } from "./themeParser.js";
6
+ import { parseComments } from "./commentParser.js";
13
7
  import { normalizeCommentReferences } from "./commentReferenceNormalization.js";
8
+ import { detectDocxConformanceClass } from "./conformance.js";
9
+ import { parseNumbering } from "./numberingParser.js";
14
10
  import { extractAllTemplateVariables, parseDocumentBody } from "./documentParser.js";
11
+ import { parseEndnotes, parseFootnotes } from "./footnoteParser.js";
12
+ import { parseFooter, parseHeader } from "./headerFooterParser.js";
15
13
  import { normalizeHeaderFooterReferences } from "./headerFooterReferenceNormalization.js";
14
+ import { DocxModelValidationError, formatDocumentModelIssues, validateFolioDocumentModel } from "./modelValidation.js";
16
15
  import { extractMetafileRaster, isMetafileMimeType } from "./metafileRaster.js";
16
+ import { parseFontTable } from "./fontTableParser.js";
17
17
  import { normalizeNumberingReferences } from "./numberingReferenceNormalization.js";
18
18
  import { parseSettings } from "./settingsParser.js";
19
19
  import { parseStylesPackage } from "./styleParser.js";
20
20
  import { normalizeTrackedMoveRanges } from "./trackedMoveRangeNormalization.js";
21
+ import { DocxEncryptionError } from "./encryption/errors.js";
22
+ import { getMediaMimeType, mediaToDataUrl, unzipDocx } from "./unzip.js";
21
23
  import { TaggedError } from "better-result";
22
24
  //#region src/docx/parser.ts
23
25
  /**
@@ -83,6 +85,7 @@ async function parseDocx(input, options = {}) {
83
85
  onProgress("Parsed styles", 30);
84
86
  onProgress("Parsing numbering...", 30);
85
87
  const numbering = timeStage("numbering", () => parseNumbering(raw.numberingXml));
88
+ const fontTable = timeStage("fontTable", () => parseFontTable(raw.fontTableXml));
86
89
  onProgress("Parsed numbering", 35);
87
90
  onProgress("Processing media files...", 35);
88
91
  const media = await timeStageAsync("media", () => buildMediaMap(raw, rels));
@@ -167,11 +170,13 @@ async function parseDocx(input, options = {}) {
167
170
  onProgress("Assembling document...", 95);
168
171
  const document = {
169
172
  package: {
173
+ conformanceClass: detectDocxConformanceClass(raw.documentXml),
170
174
  document: documentBody,
171
175
  settings,
172
176
  ...styleDefinitions !== void 0 ? { styles: styleDefinitions } : {},
173
177
  theme,
174
178
  numbering: numbering.definitions,
179
+ ...fontTable ? { fontTable } : {},
175
180
  ...headers !== void 0 ? { headers } : {},
176
181
  ...footers !== void 0 ? { footers } : {},
177
182
  ...footnotes !== void 0 ? { footnotes } : {},
@@ -1,8 +1,9 @@
1
- import { applyReplyThreadMarkers } from "./commentReplyMarkers.js";
2
1
  import { RELATIONSHIP_TYPES, parseRelationships, resolveRelativePath } from "./relsParser.js";
2
+ import { parseNumbering } from "./numberingParser.js";
3
3
  import { parseEndnotes, parseFootnotes } from "./footnoteParser.js";
4
4
  import { assertValidFolioDocumentModel } from "./modelValidation.js";
5
- import { parseNumbering } from "./numberingParser.js";
5
+ import { isPreservableDocxEntry } from "./unzip.js";
6
+ import { applyReplyThreadMarkers } from "./commentReplyMarkers.js";
6
7
  import { buildPatchedNoteXml, buildPatchedNumberingXml, collectChangedNumberingDefs, collectParaIds, extractParagraphXml } from "./selectiveXmlPatch.js";
7
8
  import { escapeXml } from "./serializer/xmlUtils.js";
8
9
  import { ensureThreadedCommentParaIds, serializeComments, serializeCommentsExtended } from "./serializer/commentSerializer.js";
@@ -10,7 +11,10 @@ import { serializeDocument } from "./serializer/documentSerializer.js";
10
11
  import { serializeHeaderFooter } from "./serializer/headerFooterSerializer.js";
11
12
  import { serializeEndnotes, serializeFootnotes } from "./serializer/noteSerializer.js";
12
13
  import { serializeNumberingXml } from "./serializer/numberingSerializer.js";
13
- import { isPreservableDocxEntry } from "./unzip.js";
14
+ import { serializeFontTableXml } from "./serializer/fontTableSerializer.js";
15
+ import { serializeSettingsXml } from "./serializer/settingsSerializer.js";
16
+ import { serializeStylesXml } from "./serializer/stylesSerializer.js";
17
+ import { serializeThemeXml } from "./serializer/themeSerializer.js";
14
18
  import { panic } from "better-result";
15
19
  import JSZip from "jszip";
16
20
  //#region src/docx/rezip.ts
@@ -1169,7 +1173,7 @@ function createEmptyDocx() {
1169
1173
  zip.file("docProps/app.xml", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
1170
1174
  <Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties">
1171
1175
  <Application>EigenPal DOCX Editor</Application>
1172
- <AppVersion>1.0.0</AppVersion>
1176
+ <AppVersion>1.0000</AppVersion>
1173
1177
  </Properties>`);
1174
1178
  return zip.generateAsync({
1175
1179
  type: "arraybuffer",
@@ -1184,11 +1188,72 @@ function createEmptyDocx() {
1184
1188
  * @returns Promise resolving to DOCX as ArrayBuffer
1185
1189
  */
1186
1190
  async function createDocx(doc) {
1187
- const emptyBuffer = await createEmptyDocx();
1191
+ const emptyBuffer = await createDocumentSeedDocx(doc);
1188
1192
  return repackDocx({
1189
1193
  ...doc,
1190
1194
  originalBuffer: emptyBuffer
1191
1195
  });
1192
1196
  }
1197
+ const createDocumentSeedDocx = async (doc) => {
1198
+ const buffer = await createEmptyDocx();
1199
+ const zip = await JSZip.loadAsync(buffer);
1200
+ const relationships = ["<Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\" Target=\"styles.xml\"/>"];
1201
+ const overrides = [];
1202
+ let nextRelationshipId = 2;
1203
+ if (doc.package.styles) {
1204
+ assertStyleNumberingReferences(doc);
1205
+ zip.file("word/styles.xml", serializeStylesXml(doc.package.styles));
1206
+ }
1207
+ const numbering = doc.package.numbering;
1208
+ if (numbering && (numbering.abstractNums.length > 0 || numbering.nums.length > 0)) {
1209
+ zip.file("word/numbering.xml", serializeNumberingXml(numbering));
1210
+ relationships.push(relationshipXml(nextRelationshipId, "numbering", "numbering.xml"));
1211
+ overrides.push(overrideXml("/word/numbering.xml", "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml"));
1212
+ nextRelationshipId += 1;
1213
+ }
1214
+ if (doc.package.theme) {
1215
+ zip.file("word/theme/theme1.xml", serializeThemeXml(doc.package.theme));
1216
+ relationships.push(relationshipXml(nextRelationshipId, "theme", "theme/theme1.xml"));
1217
+ overrides.push(overrideXml("/word/theme/theme1.xml", "application/vnd.openxmlformats-officedocument.theme+xml"));
1218
+ nextRelationshipId += 1;
1219
+ }
1220
+ if (doc.package.fontTable && doc.package.fontTable.fonts.length > 0) {
1221
+ zip.file("word/fontTable.xml", serializeFontTableXml(doc.package.fontTable));
1222
+ relationships.push(relationshipXml(nextRelationshipId, "fontTable", "fontTable.xml"));
1223
+ overrides.push(overrideXml("/word/fontTable.xml", "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml"));
1224
+ nextRelationshipId += 1;
1225
+ }
1226
+ if (doc.package.settings) {
1227
+ zip.file("word/settings.xml", serializeSettingsXml(doc.package.settings));
1228
+ relationships.push(relationshipXml(nextRelationshipId, "settings", "settings.xml"));
1229
+ overrides.push(overrideXml("/word/settings.xml", "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml"));
1230
+ }
1231
+ zip.file("word/_rels/document.xml.rels", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">${relationships.join("")}</Relationships>`);
1232
+ if (overrides.length > 0) {
1233
+ const contentTypesFile = zip.file("[Content_Types].xml");
1234
+ if (!contentTypesFile) panic("Fresh DOCX seed is missing [Content_Types].xml");
1235
+ const contentTypes = await contentTypesFile.async("string");
1236
+ zip.file("[Content_Types].xml", contentTypes.replace("</Types>", `${overrides.join("")}\n</Types>`));
1237
+ }
1238
+ return zip.generateAsync({
1239
+ type: "arraybuffer",
1240
+ compression: "DEFLATE",
1241
+ compressionOptions: { level: 6 }
1242
+ });
1243
+ };
1244
+ const relationshipXml = (id, type, target) => `<Relationship Id="rId${id}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/${type}" Target="${target}"/>`;
1245
+ const overrideXml = (partName, contentType) => `<Override PartName="${partName}" ContentType="${contentType}"/>`;
1246
+ const assertStyleNumberingReferences = (doc) => {
1247
+ const referenced = /* @__PURE__ */ new Set();
1248
+ for (const style of doc.package.styles?.styles ?? []) {
1249
+ const numId = style.pPr?.numPr?.numId;
1250
+ if (numId !== void 0) referenced.add(numId);
1251
+ }
1252
+ if (referenced.size === 0) return;
1253
+ const available = new Set(doc.package.numbering?.nums.map((numbering) => numbering.numId) ?? []);
1254
+ for (const numId of referenced) if (!available.has(numId)) panic(`Style references missing numbering definition ${numId}`);
1255
+ const availableAbstract = new Set(doc.package.numbering?.abstractNums.map((numbering) => numbering.abstractNumId) ?? []);
1256
+ for (const numbering of doc.package.numbering?.nums ?? []) if (!availableAbstract.has(numbering.abstractNumId)) panic(`Numbering definition ${numbering.numId} references missing abstract numbering`);
1257
+ };
1193
1258
  //#endregion
1194
1259
  export { COMMENTS_CONTENT_TYPE, COMMENTS_EXTENDED_CONTENT_TYPE, COMMENTS_EXTENDED_PART, COMMENTS_EXTENDED_PART_LOWER, DocxPackageFidelityError, addCommentsExtendedOverride, addCommentsExtendedRelationship, addMedia, addRelationship, applyUpdatesToZip, collectHeaderFooterUpdates, createDocx, createEmptyDocx, findMaxRId, hasModelDrivenPictureWatermark, hasUnmaterializedHeaderFooter, isDocxBuffer, removeCommentsExtendedOverride, removeCommentsExtendedRelationship, repackDocx, repackDocxFromRaw, updateCoreProperties, updateDocumentXml, updateMultipleFiles, updateXmlFile, validateDocx };
@@ -38,8 +38,12 @@ function formattingEquals(a, b) {
38
38
  if (!colorEquals(a.color, b.color)) return false;
39
39
  if (!shadingEquals(a.shading, b.shading)) return false;
40
40
  if (!fontFamilyEquals(a.fontFamily, b.fontFamily)) return false;
41
+ if (!languageEquals(a.language, b.language)) return false;
41
42
  return true;
42
43
  }
44
+ function languageEquals(a, b) {
45
+ return a?.val === b?.val && a?.eastAsia === b?.eastAsia && a?.bidi === b?.bidi;
46
+ }
43
47
  /**
44
48
  * Compare underline settings
45
49
  */
@@ -89,6 +89,9 @@ function collectFirstRunPropertyChildren(rPr) {
89
89
  case "kern":
90
90
  children.kern ??= child;
91
91
  break;
92
+ case "lang":
93
+ children.lang ??= child;
94
+ break;
92
95
  case "outline":
93
96
  children.outline ??= child;
94
97
  break;
@@ -262,6 +265,17 @@ function parseRunProperties(rPr, theme, _styles) {
262
265
  }
263
266
  formatting.fontFamily = fontFamily;
264
267
  }
268
+ const lang = propertyChildren.lang;
269
+ if (lang) {
270
+ const val = getAttribute(lang, "w", "val") || void 0;
271
+ const eastAsia = getAttribute(lang, "w", "eastAsia") || void 0;
272
+ const bidi = getAttribute(lang, "w", "bidi") || void 0;
273
+ if (val || eastAsia || bidi) formatting.language = {
274
+ ...val ? { val } : {},
275
+ ...eastAsia ? { eastAsia } : {},
276
+ ...bidi ? { bidi } : {}
277
+ };
278
+ }
265
279
  const spacing = propertyChildren.spacing;
266
280
  if (spacing) {
267
281
  const val = parseNumericAttribute(spacing, "w", "val");
@@ -531,7 +545,11 @@ function parseRunContents(runElement, rels, media, rootXmlns = {}) {
531
545
  if (vmlDrawing) contents.push(vmlDrawing);
532
546
  break;
533
547
  }
534
- case "object": break;
548
+ case "object": {
549
+ const objectPreview = parseVmlImageContent(child, rels, media, rootXmlns);
550
+ if (objectPreview) contents.push(objectPreview);
551
+ break;
552
+ }
535
553
  case "rPr": break;
536
554
  case "lastRenderedPageBreak": break;
537
555
  case "cr":
@@ -1,14 +1,14 @@
1
- import { hasUnsynthesizedReplyRanges } from "./commentReplyMarkers.js";
2
1
  import { RELATIONSHIP_TYPES } from "./relsParser.js";
3
- import { validateFolioDocumentModel } from "./modelValidation.js";
2
+ import { parseCommentsExtended } from "./commentParser.js";
4
3
  import { parseNumbering } from "./numberingParser.js";
4
+ import { validateFolioDocumentModel } from "./modelValidation.js";
5
+ import { hasUnsynthesizedReplyRanges } from "./commentReplyMarkers.js";
5
6
  import { buildPatchedDocumentXml, buildPatchedNoteXml, buildPatchedNumberingXml, collectChangedNumberingDefs, collectParaIds } from "./selectiveXmlPatch.js";
6
7
  import { ensureThreadedCommentParaIds, serializeComments, serializeCommentsExtended } from "./serializer/commentSerializer.js";
7
8
  import { serializeDocument } from "./serializer/documentSerializer.js";
8
9
  import { serializeEndnotes, serializeFootnotes } from "./serializer/noteSerializer.js";
9
10
  import { serializeNumberingXml } from "./serializer/numberingSerializer.js";
10
11
  import { COMMENTS_CONTENT_TYPE, COMMENTS_EXTENDED_PART_LOWER, addCommentsExtendedOverride, addCommentsExtendedRelationship, applyUpdatesToZip, collectHeaderFooterUpdates, findMaxRId, hasModelDrivenPictureWatermark, hasUnmaterializedHeaderFooter, updateCoreProperties } from "./rezip.js";
11
- import { parseCommentsExtended } from "./commentParser.js";
12
12
  import "./selectiveSaveFlags.js";
13
13
  //#region src/docx/selectiveSave.ts
14
14
  const SYNTHETIC_IMAGE_RID_PREFIX = "rId_img_";
@@ -6,6 +6,15 @@
6
6
  * unchanged content byte-for-byte. Uses string offset tracking
7
7
  * with proper tag depth counting (not regex) to handle nested elements.
8
8
  */
9
+ /**
10
+ * Whether `char` ends an element's tag name in XML — a whitespace separator
11
+ * (space, tab, CR, or LF, all valid before attributes per XML 1.0 §3.1), the
12
+ * tag close `>`, or a self-close `/`. Manual tag scanners must accept every
13
+ * whitespace form, not just a literal space, so newline-formatted markup
14
+ * (`<w:p\n w14:paraId="…">`) is still recognized as the element rather than
15
+ * mistaken for a longer-named sibling.
16
+ */
17
+ declare function isXmlNameBoundary(char: string | undefined): boolean;
9
18
  /**
10
19
  * Find the exact string start and end offsets of a <w:p> element
11
20
  * identified by its w14:paraId attribute.
@@ -100,4 +109,4 @@ declare function collectChangedNumberingDefs(baselineXml: string, currentXml: st
100
109
  */
101
110
  declare function buildPatchedNumberingXml(originalXml: string, currentXml: string, changed: ChangedNumberingDefs): string | null;
102
111
  //#endregion
103
- export { ChangedNumberingDefs, PatchSafetyOptions, PatchValidationResult, buildPatchedDocumentXml, buildPatchedNoteXml, buildPatchedNumberingXml, collectChangedNumberingDefs, collectParaIds, countParagraphElements, extractParagraphXml, findParagraphOffsets, validatePatchSafety };
112
+ export { ChangedNumberingDefs, PatchSafetyOptions, PatchValidationResult, buildPatchedDocumentXml, buildPatchedNoteXml, buildPatchedNumberingXml, collectChangedNumberingDefs, collectParaIds, countParagraphElements, extractParagraphXml, findParagraphOffsets, isXmlNameBoundary, validatePatchSafety };
@@ -484,4 +484,4 @@ function escapeRegExp(str) {
484
484
  return str.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
485
485
  }
486
486
  //#endregion
487
- export { buildPatchedDocumentXml, buildPatchedNoteXml, buildPatchedNumberingXml, collectChangedNumberingDefs, collectParaIds, countParagraphElements, extractParagraphXml, findParagraphOffsets, validatePatchSafety };
487
+ export { buildPatchedDocumentXml, buildPatchedNoteXml, buildPatchedNumberingXml, collectChangedNumberingDefs, collectParaIds, countParagraphElements, extractParagraphXml, findParagraphOffsets, isXmlNameBoundary, validatePatchSafety };
@@ -0,0 +1,6 @@
1
+ import { document_d_exports } from "../../types/document.js";
2
+
3
+ //#region src/docx/serializer/fontTableSerializer.d.ts
4
+ declare const serializeFontTableXml: (fontTable: document_d_exports.FontTable) => string;
5
+ //#endregion
6
+ export { serializeFontTableXml };
@@ -0,0 +1,26 @@
1
+ import { escapeXml } from "./xmlUtils.js";
2
+ //#region src/docx/serializer/fontTableSerializer.ts
3
+ const W_NS = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
4
+ const serializeFontTableXml = (fontTable) => {
5
+ const fonts = fontTable.fonts.map(serializeFont).join("");
6
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<w:fonts xmlns:w="${W_NS}">${fonts}</w:fonts>`;
7
+ };
8
+ const serializeFont = (font) => {
9
+ const parts = [];
10
+ if (font.altName) parts.push(`<w:altName w:val="${escapeXml(font.altName)}"/>`);
11
+ if (font.panose1) parts.push(`<w:panose1 w:val="${escapeXml(font.panose1)}"/>`);
12
+ if (font.charset) parts.push(`<w:charset w:val="${escapeXml(font.charset)}"/>`);
13
+ if (font.family) parts.push(`<w:family w:val="${font.family}"/>`);
14
+ if (font.pitch) parts.push(`<w:pitch w:val="${font.pitch}"/>`);
15
+ if (font.sig) {
16
+ const attrs = [];
17
+ for (const [key, value] of Object.entries(font.sig)) {
18
+ if (value === void 0) continue;
19
+ attrs.push(`w:${key}="${escapeXml(value)}"`);
20
+ }
21
+ if (attrs.length > 0) parts.push(`<w:sig ${attrs.join(" ")}/>`);
22
+ }
23
+ return `<w:font w:name="${escapeXml(font.name)}">${parts.join("")}</w:font>`;
24
+ };
25
+ //#endregion
26
+ export { serializeFontTableXml };
@@ -1,8 +1,8 @@
1
+ import { canReplayHeaderFooterVerbatim, getHeaderFooterVerbatimXml } from "../headerFooterVerbatim.js";
1
2
  import { escapeXml } from "./xmlUtils.js";
2
3
  import { serializeBlockSdt } from "./blockSdtSerializer.js";
3
4
  import { serializeParagraph } from "./paragraphSerializer.js";
4
5
  import { serializeTable } from "./tableSerializer.js";
5
- import { canReplayHeaderFooterVerbatim, getHeaderFooterVerbatimXml } from "../headerFooterVerbatim.js";
6
6
  //#region src/docx/serializer/headerFooterSerializer.ts
7
7
  const NAMESPACES = {
8
8
  wpc: "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas",
@@ -112,8 +112,12 @@ function serializeNumbering(numPr) {
112
112
  function serializeFrameProperties(frame) {
113
113
  if (!frame) return "";
114
114
  const attrs = [];
115
+ if (frame.dropCap) attrs.push(`w:dropCap="${frame.dropCap}"`);
116
+ if (frame.lines !== void 0) attrs.push(`w:lines="${intAttr(frame.lines)}"`);
115
117
  if (frame.width !== void 0) attrs.push(`w:w="${intAttr(frame.width)}"`);
116
118
  if (frame.height !== void 0) attrs.push(`w:h="${intAttr(frame.height)}"`);
119
+ if (frame.hSpace !== void 0) attrs.push(`w:hSpace="${intAttr(frame.hSpace)}"`);
120
+ if (frame.vSpace !== void 0) attrs.push(`w:vSpace="${intAttr(frame.vSpace)}"`);
117
121
  if (frame.hAnchor) attrs.push(`w:hAnchor="${frame.hAnchor}"`);
118
122
  if (frame.vAnchor) attrs.push(`w:vAnchor="${frame.vAnchor}"`);
119
123
  if (frame.x !== void 0) attrs.push(`w:x="${frame.x}"`);
@@ -161,6 +165,8 @@ function serializeParagraphFormatting(formatting, propertyChanges, pPrMark) {
161
165
  if (tabsXml) parts.push(tabsXml);
162
166
  pushToggle("suppressLineNumbers", formatting.suppressLineNumbers);
163
167
  pushToggle("suppressAutoHyphens", formatting.suppressAutoHyphens);
168
+ pushToggle("kinsoku", formatting.kinsoku);
169
+ pushToggle("overflowPunct", formatting.overflowPunctuation);
164
170
  const spacingXml = serializeSpacing(formatting);
165
171
  if (spacingXml) parts.push(spacingXml);
166
172
  const indXml = serializeIndentation(formatting);
@@ -346,6 +352,8 @@ function serializeInlineSdt(sdt) {
346
352
  case "simpleField": return serializeSimpleField(item);
347
353
  case "complexField": return serializeComplexField(item);
348
354
  case "inlineSdt": return serializeInlineSdt(item);
355
+ case "insertion": return serializeTrackedChange("ins", item);
356
+ case "deletion": return serializeTrackedChange("del", item);
349
357
  case "mathEquation": return item.ommlXml || "";
350
358
  default: return item;
351
359
  }
@@ -85,6 +85,13 @@ function serializeTextFormatting(formatting) {
85
85
  if (formatting.fontFamily.csTheme) fontAttrs.push(`w:cstheme="${formatting.fontFamily.csTheme}"`);
86
86
  if (fontAttrs.length > 0) parts.push(`<w:rFonts ${fontAttrs.join(" ")}/>`);
87
87
  }
88
+ if (formatting.language) {
89
+ const languageAttrs = [];
90
+ if (formatting.language.val) languageAttrs.push(`w:val="${escapeXml(formatting.language.val)}"`);
91
+ if (formatting.language.eastAsia) languageAttrs.push(`w:eastAsia="${escapeXml(formatting.language.eastAsia)}"`);
92
+ if (formatting.language.bidi) languageAttrs.push(`w:bidi="${escapeXml(formatting.language.bidi)}"`);
93
+ if (languageAttrs.length > 0) parts.push(`<w:lang ${languageAttrs.join(" ")}/>`);
94
+ }
88
95
  if (formatting.bold === true) parts.push("<w:b/>");
89
96
  else if (formatting.bold === false) parts.push("<w:b w:val=\"0\"/>");
90
97
  if (formatting.boldCs === true) parts.push("<w:bCs/>");
@@ -456,13 +463,18 @@ function serializeShapeContent(content) {
456
463
  if (tb.margins.right != null) bpAttrs.push(`rIns="${intAttr(tb.margins.right)}"`);
457
464
  if (tb.margins.bottom != null) bpAttrs.push(`bIns="${intAttr(tb.margins.bottom)}"`);
458
465
  }
466
+ let autoFitXml = "";
467
+ if (tb.autoFit === "shape") autoFitXml = "<a:spAutoFit/>";
468
+ else if (tb.autoFit === "normal") autoFitXml = "<a:normAutofit/>";
469
+ else if (tb.autoFit === "none") autoFitXml = "<a:noAutofit/>";
470
+ const bodyPrXml = autoFitXml ? `<wps:bodyPr ${bpAttrs.join(" ")}>${autoFitXml}</wps:bodyPr>` : `<wps:bodyPr ${bpAttrs.join(" ")}/>`;
459
471
  if (isTextBox) textBody = [
460
472
  "<wps:txbx><w:txbxContent>",
461
473
  serializeShapeTextBody(tb.content),
462
474
  "</w:txbxContent></wps:txbx>",
463
- `<wps:bodyPr ${bpAttrs.join(" ")}/>`
475
+ bodyPrXml
464
476
  ].join("");
465
- else textBody = [`<wps:bodyPr ${bpAttrs.join(" ")}/>`].join("");
477
+ else textBody = bodyPrXml;
466
478
  }
467
479
  const graphic = [
468
480
  "<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">",
@@ -0,0 +1,6 @@
1
+ import { document_d_exports } from "../../types/document.js";
2
+
3
+ //#region src/docx/serializer/settingsSerializer.d.ts
4
+ declare const serializeSettingsXml: (settings: document_d_exports.DocumentSettings) => string;
5
+ //#endregion
6
+ export { serializeSettingsXml };
@@ -0,0 +1,16 @@
1
+ import { escapeXml, intAttr } from "./xmlUtils.js";
2
+ //#region src/docx/serializer/settingsSerializer.ts
3
+ const W_NS = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
4
+ const serializeSettingsXml = (settings) => {
5
+ const parts = [`<w:defaultTabStop w:val="${intAttr(settings.defaultTabStop)}"/>`];
6
+ if (settings.evenAndOddHeaders) parts.push("<w:evenAndOddHeaders/>");
7
+ if (settings.themeFontLang) {
8
+ const attrs = [];
9
+ if (settings.themeFontLang.eastAsia) attrs.push(`w:eastAsia="${escapeXml(settings.themeFontLang.eastAsia)}"`);
10
+ if (settings.themeFontLang.bidi) attrs.push(`w:bidi="${escapeXml(settings.themeFontLang.bidi)}"`);
11
+ if (attrs.length > 0) parts.push(`<w:themeFontLang ${attrs.join(" ")}/>`);
12
+ }
13
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<w:settings xmlns:w="${W_NS}">${parts.join("")}</w:settings>`;
14
+ };
15
+ //#endregion
16
+ export { serializeSettingsXml };
@@ -0,0 +1,6 @@
1
+ import { document_d_exports } from "../../types/document.js";
2
+
3
+ //#region src/docx/serializer/stylesSerializer.d.ts
4
+ declare const serializeStylesXml: (definitions: document_d_exports.StyleDefinitions) => string;
5
+ //#endregion
6
+ export { serializeStylesXml };