@stll/folio-core 0.8.0 → 0.10.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 (168) hide show
  1. package/README.md +39 -0
  2. package/dist/ai-edits/apply.js +18 -4
  3. package/dist/ai-edits/headless.d.ts +73 -6
  4. package/dist/ai-edits/headless.js +299 -60
  5. package/dist/ai-edits/index.d.ts +3 -3
  6. package/dist/ai-edits/index.js +2 -1
  7. package/dist/ai-edits/snapshot.js +40 -3
  8. package/dist/ai-edits/types.d.ts +2 -1
  9. package/dist/compat/eigenpal.d.ts +6 -4
  10. package/dist/compat/eigenpal.js +5 -3
  11. package/dist/controller/latestRequestGate.d.ts +13 -0
  12. package/dist/controller/latestRequestGate.js +16 -0
  13. package/dist/controller/layoutPipeline.js +13 -1
  14. package/dist/document-operations.d.ts +20 -4
  15. package/dist/document-operations.js +36 -15
  16. package/dist/document-stories.d.ts +10 -0
  17. package/dist/document-stories.js +27 -0
  18. package/dist/docx/blockContentParser.js +2 -2
  19. package/dist/docx/commentParser.js +1 -1
  20. package/dist/docx/compatibility.d.ts +3 -7
  21. package/dist/docx/compatibility.js +0 -11
  22. package/dist/docx/corePropertiesParser.d.ts +8 -0
  23. package/dist/docx/corePropertiesParser.js +53 -0
  24. package/dist/docx/encryption/agileDecryption.js +1 -1
  25. package/dist/docx/encryption/encryptionInfo.js +1 -1
  26. package/dist/docx/encryption/openEncryptedDocx.js +1 -1
  27. package/dist/docx/fontTableParser.d.ts +6 -0
  28. package/dist/docx/fontTableParser.js +72 -0
  29. package/dist/docx/groupDrawingParser.js +7 -2
  30. package/dist/docx/headerFooterParser.js +1 -1
  31. package/dist/docx/index.d.ts +2 -1
  32. package/dist/docx/index.js +2 -1
  33. package/dist/docx/metadataPrivacy.d.ts +40 -0
  34. package/dist/docx/metadataPrivacy.js +131 -0
  35. package/dist/docx/normalizeBaseDirection.js +1 -1
  36. package/dist/docx/numberingParser.js +1 -0
  37. package/dist/docx/paragraphParser.js +12 -1
  38. package/dist/docx/parser.d.ts +1 -1
  39. package/dist/docx/parser.js +16 -10
  40. package/dist/docx/rezip.d.ts +5 -4
  41. package/dist/docx/rezip.js +76 -13
  42. package/dist/docx/runConsolidator.js +4 -0
  43. package/dist/docx/runParser.js +19 -1
  44. package/dist/docx/selectiveSave.js +3 -3
  45. package/dist/docx/serializer/fontTableSerializer.d.ts +6 -0
  46. package/dist/docx/serializer/fontTableSerializer.js +26 -0
  47. package/dist/docx/serializer/headerFooterSerializer.js +1 -1
  48. package/dist/docx/serializer/paragraphSerializer.js +4 -0
  49. package/dist/docx/serializer/runSerializer.js +7 -0
  50. package/dist/docx/serializer/settingsSerializer.d.ts +6 -0
  51. package/dist/docx/serializer/settingsSerializer.js +16 -0
  52. package/dist/docx/serializer/stylesSerializer.d.ts +6 -0
  53. package/dist/docx/serializer/stylesSerializer.js +56 -0
  54. package/dist/docx/serializer/tableSerializer.js +25 -26
  55. package/dist/docx/serializer/themeSerializer.d.ts +6 -0
  56. package/dist/docx/serializer/themeSerializer.js +36 -0
  57. package/dist/docx/settingsParser.js +46 -0
  58. package/dist/docx/styleParser.js +26 -1
  59. package/dist/docx/tableParser.js +11 -1
  60. package/dist/docx/vmlImageParser.js +1 -0
  61. package/dist/i18n/messages/catalogs.gen.d.ts +5916 -5916
  62. package/dist/i18n/messages/catalogs.gen.js +5910 -5910
  63. package/dist/index.d.ts +6 -4
  64. package/dist/index.js +5 -3
  65. package/dist/layout-bridge/convert/footnoteLayout.d.ts +3 -0
  66. package/dist/layout-bridge/convert/footnoteLayout.js +3 -1
  67. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +3 -0
  68. package/dist/layout-bridge/convert/headerFooterLayout.js +6 -1
  69. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +14 -2
  70. package/dist/layout-bridge/convert/toFlowBlocks.js +52 -14
  71. package/dist/layout-bridge/engine/measuring/index.d.ts +2 -1
  72. package/dist/layout-bridge/engine/measuring/index.js +2 -1
  73. package/dist/layout-engine/index.js +36 -28
  74. package/dist/layout-engine/measure/cache.js +6 -3
  75. package/dist/layout-engine/measure/effectiveLineBreakPolicy.d.ts +29 -0
  76. package/dist/layout-engine/measure/effectiveLineBreakPolicy.js +60 -0
  77. package/dist/layout-engine/measure/font-metrics.worker.js +1 -0
  78. package/dist/layout-engine/measure/index.d.ts +2 -1
  79. package/dist/layout-engine/measure/index.js +2 -1
  80. package/dist/layout-engine/measure/lineBreakProvider.d.ts +33 -0
  81. package/dist/layout-engine/measure/lineBreakProvider.js +252 -0
  82. package/dist/layout-engine/measure/lineBreaks.d.ts +7 -2
  83. package/dist/layout-engine/measure/lineBreaks.js +11 -18
  84. package/dist/layout-engine/measure/listMarkerWidth.d.ts +1 -0
  85. package/dist/layout-engine/measure/listMarkerWidth.js +12 -6
  86. package/dist/layout-engine/measure/measureBlocks.d.ts +1 -2
  87. package/dist/layout-engine/measure/measureBlocks.js +6 -36
  88. package/dist/layout-engine/measure/measureContainer.js +32 -9
  89. package/dist/layout-engine/measure/measureHelpers.js +5 -2
  90. package/dist/layout-engine/measure/measureParagraph.js +332 -73
  91. package/dist/layout-engine/measure/measureTypes.d.ts +2 -1
  92. package/dist/layout-engine/measure/measureWorker.d.ts +2 -2
  93. package/dist/layout-engine/measure/measureWorker.js +8 -19
  94. package/dist/layout-engine/measure/measureWorkerProtocol.d.ts +3 -14
  95. package/dist/layout-engine/measure/tableCellFloating.d.ts +10 -3
  96. package/dist/layout-engine/measure/tableCellFloating.js +51 -37
  97. package/dist/layout-engine/measure/tableCellFlow.d.ts +27 -0
  98. package/dist/layout-engine/measure/tableCellFlow.js +73 -0
  99. package/dist/layout-engine/measure/tableCellGrid.js +1 -1
  100. package/dist/layout-engine/measure/textMeasurementPolicy.d.ts +18 -0
  101. package/dist/layout-engine/measure/textMeasurementPolicy.js +24 -0
  102. package/dist/layout-engine/renderedBreakReconciliation.d.ts +6 -1
  103. package/dist/layout-engine/renderedBreakReconciliation.js +34 -11
  104. package/dist/layout-engine/tableRowBreak.d.ts +5 -2
  105. package/dist/layout-engine/tableRowBreak.js +62 -29
  106. package/dist/layout-engine/types.d.ts +43 -8
  107. package/dist/layout-painter/anchoredImagePosition.d.ts +23 -0
  108. package/dist/layout-painter/anchoredImagePosition.js +95 -0
  109. package/dist/layout-painter/borderStroke.d.ts +23 -0
  110. package/dist/layout-painter/borderStroke.js +39 -0
  111. package/dist/layout-painter/renderImage.d.ts +5 -4
  112. package/dist/layout-painter/renderImage.js +18 -4
  113. package/dist/layout-painter/renderPage.d.ts +2 -27
  114. package/dist/layout-painter/renderPage.js +13 -99
  115. package/dist/layout-painter/renderParagraph.js +41 -23
  116. package/dist/layout-painter/renderTable.d.ts +2 -0
  117. package/dist/layout-painter/renderTable.js +223 -43
  118. package/dist/managers/DocumentLoaderManager.d.ts +1 -1
  119. package/dist/managers/DocumentLoaderManager.js +2 -2
  120. package/dist/prosemirror/attrs/index.d.ts +4 -2
  121. package/dist/prosemirror/attrs/index.js +22 -2
  122. package/dist/prosemirror/commands/propertyChangeScope.js +1 -1
  123. package/dist/prosemirror/conversion/effectiveTableCellFormatting.d.ts +62 -0
  124. package/dist/prosemirror/conversion/effectiveTableCellFormatting.js +131 -0
  125. package/dist/prosemirror/conversion/fromProseDoc.js +34 -18
  126. package/dist/prosemirror/conversion/toProseDoc.js +81 -77
  127. package/dist/prosemirror/extensions/StarterKit.js +2 -0
  128. package/dist/prosemirror/extensions/core/ParagraphExtension.js +7 -2
  129. package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +1 -1
  130. package/dist/prosemirror/extensions/features/ListExtension.js +1 -0
  131. package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +1 -0
  132. package/dist/prosemirror/extensions/marks/HighlightExtension.js +1 -1
  133. package/dist/prosemirror/extensions/marks/LanguageExtension.d.ts +7 -0
  134. package/dist/prosemirror/extensions/marks/LanguageExtension.js +30 -0
  135. package/dist/prosemirror/extensions/marks/RunShadingExtension.js +1 -1
  136. package/dist/prosemirror/extensions/marks/TextColorExtension.js +1 -1
  137. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +1 -1
  138. package/dist/prosemirror/extensions/marks/markUtils.js +12 -0
  139. package/dist/prosemirror/extensions/nodes/ImageExtension.js +3 -1
  140. package/dist/prosemirror/extensions/nodes/TableExtension.js +4 -2
  141. package/dist/prosemirror/schema/index.d.ts +2 -2
  142. package/dist/prosemirror/schema/marks.d.ts +6 -1
  143. package/dist/prosemirror/schema/nodes.d.ts +15 -12
  144. package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
  145. package/dist/prosemirror/utils/tabCalculator.d.ts +3 -1
  146. package/dist/prosemirror/utils/tabCalculator.js +12 -10
  147. package/dist/prosemirror/validation.js +4 -1
  148. package/dist/redline.d.ts +26 -11
  149. package/dist/redline.js +107 -64
  150. package/dist/server.d.ts +9 -5
  151. package/dist/server.js +8 -4
  152. package/dist/style-sets/extract.d.ts +35 -0
  153. package/dist/style-sets/extract.js +123 -0
  154. package/dist/style-sets/stellaStyle.d.ts +13 -0
  155. package/dist/style-sets/stellaStyle.js +516 -0
  156. package/dist/style-sets/types.d.ts +31 -0
  157. package/dist/style-sets/types.js +5 -0
  158. package/dist/utils/createDocument.d.ts +12 -2
  159. package/dist/utils/createDocument.js +42 -31
  160. package/dist/utils/fontResolver.js +6 -6
  161. package/dist/utils/formatToStyle.js +1 -1
  162. package/dist/utils/paragraphFormattingMerge.d.ts +14 -3
  163. package/dist/utils/paragraphFormattingMerge.js +14 -4
  164. package/dist/version-comparison.d.ts +65 -11
  165. package/dist/version-comparison.js +187 -29
  166. package/package.json +5 -1
  167. package/dist/docx/capabilities.d.ts +0 -41
  168. package/dist/docx/capabilities.js +0 -322
@@ -0,0 +1,72 @@
1
+ import { findChild, findChildren, getAttribute, parseXmlDocument } from "./xmlParser.js";
2
+ //#region src/docx/fontTableParser.ts
3
+ const FONT_FAMILIES = [
4
+ "decorative",
5
+ "modern",
6
+ "roman",
7
+ "script",
8
+ "swiss",
9
+ "auto"
10
+ ];
11
+ const FONT_PITCHES = [
12
+ "default",
13
+ "fixed",
14
+ "variable"
15
+ ];
16
+ const parseFontTable = (xml) => {
17
+ if (!xml) return;
18
+ const root = parseXmlDocument(xml);
19
+ if (!root) return;
20
+ const fonts = [];
21
+ for (const element of findChildren(root, "w", "font")) {
22
+ const font = parseFont(element);
23
+ if (font) fonts.push(font);
24
+ }
25
+ return fonts.length > 0 ? { fonts } : void 0;
26
+ };
27
+ const parseFont = (element) => {
28
+ const name = getAttribute(element, "w", "name");
29
+ if (!name) return;
30
+ const font = { name };
31
+ assignValue(font, "altName", childValue(element, "altName"));
32
+ assignValue(font, "panose1", childValue(element, "panose1"));
33
+ assignValue(font, "charset", childValue(element, "charset"));
34
+ const family = childValue(element, "family");
35
+ if (family && isFontFamily(family)) font.family = family;
36
+ const pitch = childValue(element, "pitch");
37
+ if (pitch && isFontPitch(pitch)) font.pitch = pitch;
38
+ const sig = findChild(element, "w", "sig");
39
+ if (sig) {
40
+ const parsed = {};
41
+ assignSignatureValue(parsed, "usb0", getAttribute(sig, "w", "usb0") ?? void 0);
42
+ assignSignatureValue(parsed, "usb1", getAttribute(sig, "w", "usb1") ?? void 0);
43
+ assignSignatureValue(parsed, "usb2", getAttribute(sig, "w", "usb2") ?? void 0);
44
+ assignSignatureValue(parsed, "usb3", getAttribute(sig, "w", "usb3") ?? void 0);
45
+ assignSignatureValue(parsed, "csb0", getAttribute(sig, "w", "csb0") ?? void 0);
46
+ assignSignatureValue(parsed, "csb1", getAttribute(sig, "w", "csb1") ?? void 0);
47
+ if (Object.values(parsed).some((value) => value !== void 0)) font.sig = parsed;
48
+ }
49
+ assignValue(font, "embedRegular", relationshipId(element, "embedRegular"));
50
+ assignValue(font, "embedBold", relationshipId(element, "embedBold"));
51
+ assignValue(font, "embedItalic", relationshipId(element, "embedItalic"));
52
+ assignValue(font, "embedBoldItalic", relationshipId(element, "embedBoldItalic"));
53
+ return font;
54
+ };
55
+ const childValue = (element, name) => {
56
+ const child = findChild(element, "w", name);
57
+ return child ? getAttribute(child, "w", "val") ?? void 0 : void 0;
58
+ };
59
+ const relationshipId = (element, name) => {
60
+ const child = findChild(element, "w", name);
61
+ return child ? getAttribute(child, "r", "id") ?? void 0 : void 0;
62
+ };
63
+ const assignValue = (font, key, value) => {
64
+ if (value !== void 0) font[key] = value;
65
+ };
66
+ const assignSignatureValue = (signature, key, value) => {
67
+ if (value !== void 0) signature[key] = value;
68
+ };
69
+ const isFontFamily = (value) => FONT_FAMILIES.some((family) => family === value);
70
+ const isFontPitch = (value) => FONT_PITCHES.some((pitch) => pitch === value);
71
+ //#endregion
72
+ export { parseFontTable };
@@ -37,7 +37,10 @@ const colorFrom = (parent, fallback) => {
37
37
  const value = getAttribute(parent, "w", "val");
38
38
  if (value && HEX_COLOR.test(value)) return value.toUpperCase();
39
39
  }
40
- const value = getAttribute(findChildByLocalName(findChildByLocalName(parent, "solidFill"), "srgbClr"), null, "val");
40
+ if (findChildByLocalName(parent, "noFill")) return "none";
41
+ const srgb = findChildByLocalName(findChildByLocalName(parent, "solidFill"), "srgbClr");
42
+ const referencedSrgb = findChildByLocalName(parent, "srgbClr");
43
+ const value = getAttribute(srgb ?? referencedSrgb, null, "val");
41
44
  if (value && HEX_COLOR.test(value)) return value.toUpperCase();
42
45
  return fallback;
43
46
  };
@@ -80,9 +83,11 @@ const renderGeometry = (wsp) => {
80
83
  const { x, y, width, height } = childTransform(wsp);
81
84
  if (width <= 0 || height <= 0) return "";
82
85
  const spPr = findChildByLocalName(wsp, "spPr");
86
+ const style = findChildByLocalName(wsp, "style");
87
+ const styleStroke = colorFrom(findChildByLocalName(style, "lnRef"), "none");
83
88
  const fill = colorFrom(spPr, "none");
84
89
  const line = findChildByLocalName(spPr, "ln");
85
- const stroke = colorFrom(line, "none");
90
+ const stroke = colorFrom(line, styleStroke);
86
91
  const strokeWidth = line ? parseNumericAttribute(line, null, "w") ?? DEFAULT_LINE_WIDTH_EMU : 0;
87
92
  const paths = findAllDeep(findChildByLocalName(spPr, "custGeom"), "a", "path");
88
93
  if (paths.length === 0) return `<rect x="${x}" y="${y}" width="${width}" height="${height}" fill="${fill === "none" ? "none" : `#${fill}`}" stroke="${stroke === "none" ? "none" : `#${stroke}`}" stroke-width="${strokeWidth}"/>`;
@@ -1,8 +1,8 @@
1
1
  import { collectXmlnsDeclarations, parseXml } from "./xmlParser.js";
2
2
  import { parseWatermark } from "./watermarkParser.js";
3
3
  import { parseFooterReference, parseFooterReferences, parseHeaderReference, parseHeaderReferences } from "./headerFooterRefParser.js";
4
- import { assignHeaderFooterVerbatimXml } from "./headerFooterVerbatim.js";
5
4
  import { parseBlockContent } from "./blockContentParser.js";
5
+ import { assignHeaderFooterVerbatimXml } from "./headerFooterVerbatim.js";
6
6
  //#region src/docx/headerFooterParser.ts
7
7
  /**
8
8
  * Parse a header XML file (word/header*.xml)
@@ -1,4 +1,5 @@
1
1
  import { getCachedNumberingMap } from "./numberingParser.js";
2
2
  import { DOCX_ENCRYPTION_ERROR_CODES, DocxEncryptionError, DocxEncryptionErrorCode, isDocxEncryptionError } from "./encryption/errors.js";
3
3
  import { DecryptDocxOptions, DecryptDocxResult, decryptDocxIfNeeded, openDocxBuffer } from "./encryption/openEncryptedDocx.js";
4
- export { DOCX_ENCRYPTION_ERROR_CODES, type DecryptDocxOptions, type DecryptDocxResult, DocxEncryptionError, type DocxEncryptionErrorCode, decryptDocxIfNeeded, getCachedNumberingMap, isDocxEncryptionError, openDocxBuffer };
4
+ import { FOLIO_DOCUMENT_METADATA_PROPERTIES, FOLIO_DOCUMENT_PRIVACY_TRANSFORMS, FolioDocumentMetadataProperty, FolioDocumentPrivacyArchiveError, FolioDocumentPrivacyOptions, FolioDocumentPrivacyReport, FolioDocumentPrivacyTransform, InvalidFolioDocumentPrivacyOptionsError, RewriteDocxMetadataPrivacyResult, isFolioDocumentPrivacyTransform, rewriteDocxMetadataPrivacy } from "./metadataPrivacy.js";
5
+ export { DOCX_ENCRYPTION_ERROR_CODES, type DecryptDocxOptions, type DecryptDocxResult, DocxEncryptionError, type DocxEncryptionErrorCode, FOLIO_DOCUMENT_METADATA_PROPERTIES, FOLIO_DOCUMENT_PRIVACY_TRANSFORMS, type FolioDocumentMetadataProperty, FolioDocumentPrivacyArchiveError, type FolioDocumentPrivacyOptions, type FolioDocumentPrivacyReport, type FolioDocumentPrivacyTransform, InvalidFolioDocumentPrivacyOptionsError, type RewriteDocxMetadataPrivacyResult, decryptDocxIfNeeded, getCachedNumberingMap, isDocxEncryptionError, isFolioDocumentPrivacyTransform, openDocxBuffer, rewriteDocxMetadataPrivacy };
@@ -1,4 +1,5 @@
1
1
  import { getCachedNumberingMap } from "./numberingParser.js";
2
2
  import { DOCX_ENCRYPTION_ERROR_CODES, DocxEncryptionError, isDocxEncryptionError } from "./encryption/errors.js";
3
3
  import { decryptDocxIfNeeded, openDocxBuffer } from "./encryption/openEncryptedDocx.js";
4
- export { DOCX_ENCRYPTION_ERROR_CODES, DocxEncryptionError, decryptDocxIfNeeded, getCachedNumberingMap, isDocxEncryptionError, openDocxBuffer };
4
+ import { FOLIO_DOCUMENT_METADATA_PROPERTIES, FOLIO_DOCUMENT_PRIVACY_TRANSFORMS, FolioDocumentPrivacyArchiveError, InvalidFolioDocumentPrivacyOptionsError, isFolioDocumentPrivacyTransform, rewriteDocxMetadataPrivacy } from "./metadataPrivacy.js";
5
+ export { DOCX_ENCRYPTION_ERROR_CODES, DocxEncryptionError, FOLIO_DOCUMENT_METADATA_PROPERTIES, FOLIO_DOCUMENT_PRIVACY_TRANSFORMS, FolioDocumentPrivacyArchiveError, InvalidFolioDocumentPrivacyOptionsError, decryptDocxIfNeeded, getCachedNumberingMap, isDocxEncryptionError, isFolioDocumentPrivacyTransform, openDocxBuffer, rewriteDocxMetadataPrivacy };
@@ -0,0 +1,40 @@
1
+ //#region src/docx/metadataPrivacy.d.ts
2
+ declare const FOLIO_DOCUMENT_METADATA_PROPERTIES: readonly ["title", "subject", "creator", "keywords", "description", "lastModifiedBy", "revision", "created", "modified"];
3
+ type FolioDocumentMetadataProperty = (typeof FOLIO_DOCUMENT_METADATA_PROPERTIES)[number];
4
+ declare const FOLIO_DOCUMENT_PRIVACY_TRANSFORMS: readonly ["remove-attribution", "remove-timestamps", "remove-descriptive-metadata"];
5
+ type FolioDocumentPrivacyTransform = (typeof FOLIO_DOCUMENT_PRIVACY_TRANSFORMS)[number];
6
+ declare const isFolioDocumentPrivacyTransform: (value: unknown) => value is FolioDocumentPrivacyTransform;
7
+ type FolioDocumentPrivacyOptions = {
8
+ transforms: readonly FolioDocumentPrivacyTransform[];
9
+ };
10
+ type FolioDocumentPrivacyReport = {
11
+ appliedTransforms: FolioDocumentPrivacyTransform[];
12
+ removedMetadataProperties: FolioDocumentMetadataProperty[];
13
+ };
14
+ type RewriteDocxMetadataPrivacyResult = {
15
+ buffer: ArrayBuffer;
16
+ privacyReport: FolioDocumentPrivacyReport;
17
+ };
18
+ declare const InvalidFolioDocumentPrivacyOptionsError_base: import("better-result").TaggedErrorClass<"InvalidFolioDocumentPrivacyOptionsError", {
19
+ message: string;
20
+ receivedValue: unknown;
21
+ }>;
22
+ declare class InvalidFolioDocumentPrivacyOptionsError extends InvalidFolioDocumentPrivacyOptionsError_base {}
23
+ declare const FolioDocumentPrivacyArchiveError_base: import("better-result").TaggedErrorClass<"FolioDocumentPrivacyArchiveError", {
24
+ message: string;
25
+ reason: "input-too-large" | "load-failed" | "too-many-entries" | "core-properties-too-large";
26
+ cause?: unknown;
27
+ }>;
28
+ declare class FolioDocumentPrivacyArchiveError extends FolioDocumentPrivacyArchiveError_base {}
29
+ declare const PRIVATE_METADATA_PROPERTIES_BY_TRANSFORM: {
30
+ readonly "remove-attribution": readonly ["creator", "lastModifiedBy"];
31
+ readonly "remove-timestamps": readonly ["created", "modified"];
32
+ readonly "remove-descriptive-metadata": readonly ["title", "subject", "keywords", "description"];
33
+ };
34
+ declare const resolveFolioDocumentPrivacyTransforms: (transforms: unknown) => FolioDocumentPrivacyTransform[];
35
+ /** Rewrite selected package metadata fields without changing other package parts. */
36
+ declare const rewriteDocxMetadataPrivacy: (buffer: ArrayBuffer, {
37
+ transforms
38
+ }: FolioDocumentPrivacyOptions) => Promise<RewriteDocxMetadataPrivacyResult>;
39
+ //#endregion
40
+ export { FOLIO_DOCUMENT_METADATA_PROPERTIES, FOLIO_DOCUMENT_PRIVACY_TRANSFORMS, FolioDocumentMetadataProperty, FolioDocumentPrivacyArchiveError, FolioDocumentPrivacyOptions, FolioDocumentPrivacyReport, FolioDocumentPrivacyTransform, InvalidFolioDocumentPrivacyOptionsError, PRIVATE_METADATA_PROPERTIES_BY_TRANSFORM, RewriteDocxMetadataPrivacyResult, isFolioDocumentPrivacyTransform, resolveFolioDocumentPrivacyTransforms, rewriteDocxMetadataPrivacy };
@@ -0,0 +1,131 @@
1
+ import { elementToXml, getLocalName, parseXmlDocument } from "./xmlParser.js";
2
+ import { TaggedError } from "better-result";
3
+ import JSZip from "jszip";
4
+ //#region src/docx/metadataPrivacy.ts
5
+ const FOLIO_DOCUMENT_METADATA_PROPERTIES = Object.freeze([
6
+ "title",
7
+ "subject",
8
+ "creator",
9
+ "keywords",
10
+ "description",
11
+ "lastModifiedBy",
12
+ "revision",
13
+ "created",
14
+ "modified"
15
+ ]);
16
+ const isFolioDocumentMetadataProperty = (value) => FOLIO_DOCUMENT_METADATA_PROPERTIES.some((property) => property === value);
17
+ const FOLIO_DOCUMENT_PRIVACY_TRANSFORMS = Object.freeze([
18
+ "remove-attribution",
19
+ "remove-timestamps",
20
+ "remove-descriptive-metadata"
21
+ ]);
22
+ const isFolioDocumentPrivacyTransform = (value) => FOLIO_DOCUMENT_PRIVACY_TRANSFORMS.some((transform) => transform === value);
23
+ var InvalidFolioDocumentPrivacyOptionsError = class extends TaggedError("InvalidFolioDocumentPrivacyOptionsError")() {};
24
+ var FolioDocumentPrivacyArchiveError = class extends TaggedError("FolioDocumentPrivacyArchiveError")() {};
25
+ const PRIVATE_METADATA_PROPERTIES_BY_TRANSFORM = {
26
+ "remove-attribution": ["creator", "lastModifiedBy"],
27
+ "remove-timestamps": ["created", "modified"],
28
+ "remove-descriptive-metadata": [
29
+ "title",
30
+ "subject",
31
+ "keywords",
32
+ "description"
33
+ ]
34
+ };
35
+ const resolveFolioDocumentPrivacyTransforms = (transforms) => {
36
+ if (!Array.isArray(transforms) || transforms.some((transform) => !isFolioDocumentPrivacyTransform(transform))) throw new InvalidFolioDocumentPrivacyOptionsError({
37
+ message: "Document privacy received an unrecognized transform",
38
+ receivedValue: transforms
39
+ });
40
+ const requested = new Set(transforms);
41
+ return FOLIO_DOCUMENT_PRIVACY_TRANSFORMS.filter((transform) => requested.has(transform));
42
+ };
43
+ const XML_DECLARATION_PATTERN = /^\s*<\?xml[^?]*\?>/u;
44
+ const MAX_INPUT_BYTES = 50 * 1024 * 1024;
45
+ const MAX_ARCHIVE_ENTRIES = 5e3;
46
+ const MAX_CORE_PROPERTIES_BYTES = 1024 * 1024;
47
+ const loadPrivacyArchive = async (buffer) => {
48
+ if (buffer.byteLength > MAX_INPUT_BYTES) throw new FolioDocumentPrivacyArchiveError({
49
+ message: "Document privacy input exceeded the compressed-size limit",
50
+ reason: "input-too-large"
51
+ });
52
+ let zip;
53
+ try {
54
+ zip = await JSZip.loadAsync(buffer);
55
+ } catch (cause) {
56
+ throw new FolioDocumentPrivacyArchiveError({
57
+ message: "Document privacy input is not a readable package",
58
+ reason: "load-failed",
59
+ cause
60
+ });
61
+ }
62
+ if (Object.values(zip.files).length > MAX_ARCHIVE_ENTRIES) throw new FolioDocumentPrivacyArchiveError({
63
+ message: "Document privacy input exceeded the package-entry limit",
64
+ reason: "too-many-entries"
65
+ });
66
+ const coreProperties = zip.file("docProps/core.xml");
67
+ if (!coreProperties) return zip;
68
+ const data = "_data" in coreProperties ? coreProperties._data : void 0;
69
+ const declaredBytes = typeof data === "object" && data !== null && "uncompressedSize" in data ? data.uncompressedSize : void 0;
70
+ if (typeof declaredBytes !== "number" || declaredBytes > MAX_CORE_PROPERTIES_BYTES) throw new FolioDocumentPrivacyArchiveError({
71
+ message: "Document privacy core properties exceeded the part-size limit",
72
+ reason: "core-properties-too-large"
73
+ });
74
+ return zip;
75
+ };
76
+ const rewriteCorePropertiesPrivacy = (xml, transforms) => {
77
+ const root = parseXmlDocument(xml);
78
+ if (!root?.elements) return {
79
+ xml,
80
+ removedMetadataProperties: []
81
+ };
82
+ const propertiesToRemove = /* @__PURE__ */ new Set();
83
+ for (const transform of transforms) for (const property of PRIVATE_METADATA_PROPERTIES_BY_TRANSFORM[transform]) propertiesToRemove.add(property);
84
+ const removedPropertySet = /* @__PURE__ */ new Set();
85
+ root.elements = root.elements.filter((element) => {
86
+ if (element.type !== "element") return true;
87
+ const property = getLocalName(element.name ?? "");
88
+ if (!isFolioDocumentMetadataProperty(property)) return true;
89
+ if (!propertiesToRemove.has(property)) return true;
90
+ removedPropertySet.add(property);
91
+ return false;
92
+ });
93
+ return {
94
+ xml: `${xml.match(XML_DECLARATION_PATTERN)?.at(0) ?? ""}${elementToXml(root)}`,
95
+ removedMetadataProperties: FOLIO_DOCUMENT_METADATA_PROPERTIES.filter((property) => removedPropertySet.has(property))
96
+ };
97
+ };
98
+ /** Rewrite selected package metadata fields without changing other package parts. */
99
+ const rewriteDocxMetadataPrivacy = async (buffer, { transforms }) => {
100
+ const appliedTransforms = resolveFolioDocumentPrivacyTransforms(transforms);
101
+ const zip = await loadPrivacyArchive(buffer);
102
+ const coreProperties = zip.file("docProps/core.xml");
103
+ if (!coreProperties) return {
104
+ buffer,
105
+ privacyReport: {
106
+ appliedTransforms,
107
+ removedMetadataProperties: []
108
+ }
109
+ };
110
+ const rewritten = rewriteCorePropertiesPrivacy(await coreProperties.async("text"), appliedTransforms);
111
+ if (rewritten.removedMetadataProperties.length === 0) return {
112
+ buffer,
113
+ privacyReport: {
114
+ appliedTransforms,
115
+ removedMetadataProperties: []
116
+ }
117
+ };
118
+ zip.file("docProps/core.xml", rewritten.xml);
119
+ return {
120
+ buffer: await zip.generateAsync({
121
+ type: "arraybuffer",
122
+ compression: "DEFLATE"
123
+ }),
124
+ privacyReport: {
125
+ appliedTransforms,
126
+ removedMetadataProperties: rewritten.removedMetadataProperties
127
+ }
128
+ };
129
+ };
130
+ //#endregion
131
+ export { FOLIO_DOCUMENT_METADATA_PROPERTIES, FOLIO_DOCUMENT_PRIVACY_TRANSFORMS, FolioDocumentPrivacyArchiveError, InvalidFolioDocumentPrivacyOptionsError, PRIVATE_METADATA_PROPERTIES_BY_TRANSFORM, isFolioDocumentPrivacyTransform, resolveFolioDocumentPrivacyTransforms, rewriteDocxMetadataPrivacy };
@@ -1,5 +1,5 @@
1
- import { detectBaseDirection } from "../utils/baseDirection.js";
2
1
  import { createStyleResolver } from "../prosemirror/styles/styleResolver.js";
2
+ import { detectBaseDirection } from "../utils/baseDirection.js";
3
3
  //#region src/docx/normalizeBaseDirection.ts
4
4
  const runText = (run) => {
5
5
  let text = "";
@@ -603,6 +603,7 @@ function computeListRendering(numPr, numbering) {
603
603
  const markerFont = level.rPr?.fontFamily?.ascii || level.rPr?.fontFamily?.hAnsi;
604
604
  if (markerFont) rendering.markerFontFamily = markerFont;
605
605
  if (level.rPr?.fontSize) rendering.markerFontSize = level.rPr.fontSize / 2;
606
+ if (level.rPr?.bold !== void 0) rendering.markerBold = level.rPr.bold;
606
607
  if (level.rPr?.allCaps) rendering.markerAllCaps = true;
607
608
  if (level.lvlJc) rendering.markerAlignment = level.lvlJc;
608
609
  if (level.suffix) rendering.markerSuffix = level.suffix;
@@ -164,12 +164,18 @@ function collectFirstParagraphPropertyChildren(pPr) {
164
164
  case "keepNext":
165
165
  children.keepNext ??= child;
166
166
  break;
167
+ case "kinsoku":
168
+ children.kinsoku ??= child;
169
+ break;
167
170
  case "numPr":
168
171
  children.numPr ??= child;
169
172
  break;
170
173
  case "outlineLvl":
171
174
  children.outlineLvl ??= child;
172
175
  break;
176
+ case "overflowPunct":
177
+ children.overflowPunct ??= child;
178
+ break;
173
179
  case "pageBreakBefore":
174
180
  children.pageBreakBefore ??= child;
175
181
  break;
@@ -226,6 +232,10 @@ function parseParagraphProperties(pPr, theme, styles) {
226
232
  if (!pPr) return;
227
233
  const formatting = {};
228
234
  const propertyChildren = collectFirstParagraphPropertyChildren(pPr);
235
+ const kinsoku = propertyChildren.kinsoku;
236
+ if (kinsoku) formatting.kinsoku = parseBooleanElement(kinsoku);
237
+ const overflowPunct = propertyChildren.overflowPunct;
238
+ if (overflowPunct) formatting.overflowPunctuation = parseBooleanElement(overflowPunct);
229
239
  const jc = propertyChildren.jc;
230
240
  if (jc) {
231
241
  const val = narrowEnum(getAttribute(jc, "w", "val"), ParagraphAlignmentSchema);
@@ -525,7 +535,7 @@ function isTrackedChangeWrapperChild(content) {
525
535
  return content.type === "run" || content.type === "hyperlink";
526
536
  }
527
537
  function isInlineSdtContent(content) {
528
- return content.type === "run" || content.type === "hyperlink" || content.type === "simpleField" || content.type === "complexField" || content.type === "inlineSdt" || content.type === "mathEquation";
538
+ return content.type === "run" || content.type === "hyperlink" || content.type === "simpleField" || content.type === "complexField" || content.type === "inlineSdt" || content.type === "insertion" || content.type === "deletion" || content.type === "mathEquation";
529
539
  }
530
540
  function pushTrackedChangeWrapper({ contents, type, info, content, preserveEmpty = false }) {
531
541
  if (content.length === 0 && !preserveEmpty) return;
@@ -981,6 +991,7 @@ function parseParagraph(node, styles, theme, numbering, rels = null, media = nul
981
991
  const markerFont = level.rPr?.fontFamily?.ascii || level.rPr?.fontFamily?.hAnsi;
982
992
  if (markerFont) listRendering.markerFontFamily = markerFont;
983
993
  if (level.rPr?.fontSize) listRendering.markerFontSize = level.rPr.fontSize / 2;
994
+ if (level.rPr?.bold !== void 0) listRendering.markerBold = level.rPr.bold;
984
995
  if (level.rPr?.allCaps) listRendering.markerAllCaps = true;
985
996
  if (level.lvlJc) listRendering.markerAlignment = level.lvlJc;
986
997
  if (level.suffix) listRendering.markerSuffix = level.suffix;
@@ -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,24 +1,26 @@
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";
14
8
  import { detectDocxConformanceClass } from "./conformance.js";
9
+ import { parseCoreProperties } from "./corePropertiesParser.js";
10
+ import { parseNumbering } from "./numberingParser.js";
15
11
  import { extractAllTemplateVariables, parseDocumentBody } from "./documentParser.js";
12
+ import { parseEndnotes, parseFootnotes } from "./footnoteParser.js";
13
+ import { parseFooter, parseHeader } from "./headerFooterParser.js";
16
14
  import { normalizeHeaderFooterReferences } from "./headerFooterReferenceNormalization.js";
15
+ import { DocxModelValidationError, formatDocumentModelIssues, validateFolioDocumentModel } from "./modelValidation.js";
17
16
  import { extractMetafileRaster, isMetafileMimeType } from "./metafileRaster.js";
17
+ import { parseFontTable } from "./fontTableParser.js";
18
18
  import { normalizeNumberingReferences } from "./numberingReferenceNormalization.js";
19
19
  import { parseSettings } from "./settingsParser.js";
20
20
  import { parseStylesPackage } from "./styleParser.js";
21
21
  import { normalizeTrackedMoveRanges } from "./trackedMoveRangeNormalization.js";
22
+ import { DocxEncryptionError } from "./encryption/errors.js";
23
+ import { getMediaMimeType, mediaToDataUrl, unzipDocx } from "./unzip.js";
22
24
  import { TaggedError } from "better-result";
23
25
  //#region src/docx/parser.ts
24
26
  /**
@@ -84,6 +86,7 @@ async function parseDocx(input, options = {}) {
84
86
  onProgress("Parsed styles", 30);
85
87
  onProgress("Parsing numbering...", 30);
86
88
  const numbering = timeStage("numbering", () => parseNumbering(raw.numberingXml));
89
+ const fontTable = timeStage("fontTable", () => parseFontTable(raw.fontTableXml));
87
90
  onProgress("Parsed numbering", 35);
88
91
  onProgress("Processing media files...", 35);
89
92
  const media = await timeStageAsync("media", () => buildMediaMap(raw, rels));
@@ -166,6 +169,7 @@ async function parseDocx(input, options = {}) {
166
169
  onProgress("Loaded fonts", 95);
167
170
  } else onProgress("Skipping font loading", 95);
168
171
  onProgress("Assembling document...", 95);
172
+ const properties = timeStage("coreProperties", () => parseCoreProperties(raw.corePropsXml));
169
173
  const document = {
170
174
  package: {
171
175
  conformanceClass: detectDocxConformanceClass(raw.documentXml),
@@ -174,12 +178,14 @@ async function parseDocx(input, options = {}) {
174
178
  ...styleDefinitions !== void 0 ? { styles: styleDefinitions } : {},
175
179
  theme,
176
180
  numbering: numbering.definitions,
181
+ ...fontTable ? { fontTable } : {},
177
182
  ...headers !== void 0 ? { headers } : {},
178
183
  ...footers !== void 0 ? { footers } : {},
179
184
  ...footnotes !== void 0 ? { footnotes } : {},
180
185
  ...endnotes !== void 0 ? { endnotes } : {},
181
186
  relationships: rels,
182
- media
187
+ media,
188
+ ...properties !== void 0 ? { properties } : {}
183
189
  },
184
190
  originalBuffer: raw.originalBuffer,
185
191
  ...templateVariables !== void 0 ? { templateVariables } : {},
@@ -124,10 +124,11 @@ declare function hasUnmaterializedHeaderFooter(doc: document_d_exports.Document)
124
124
  */
125
125
  declare function hasModelDrivenPictureWatermark(doc: document_d_exports.Document): boolean;
126
126
  declare function collectHeaderFooterUpdates(doc: document_d_exports.Document): Map<string, string>;
127
- /**
128
- * Update core properties XML with new modification date
129
- */
130
- declare function updateCoreProperties(corePropsXml: string, options: {
127
+ /** Update existing core-property values without synthesizing absent metadata. */
128
+ declare function updateCoreProperties(corePropsXml: string, {
129
+ updateModifiedDate,
130
+ modifiedBy
131
+ }: {
131
132
  updateModifiedDate?: boolean;
132
133
  modifiedBy?: string;
133
134
  }): string;
@@ -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
@@ -1018,18 +1022,16 @@ function findNotePartEntry(zip, conventionalLowerPath) {
1018
1022
  for (const [path, file] of Object.entries(zip.files)) if (!file.dir && path.toLowerCase() === conventionalLowerPath) return file;
1019
1023
  return null;
1020
1024
  }
1021
- /**
1022
- * Update core properties XML with new modification date
1023
- */
1024
- function updateCoreProperties(corePropsXml, options) {
1025
+ /** Update existing core-property values without synthesizing absent metadata. */
1026
+ function updateCoreProperties(corePropsXml, { updateModifiedDate, modifiedBy }) {
1025
1027
  let result = corePropsXml;
1026
- if (options.updateModifiedDate) {
1028
+ if (updateModifiedDate) {
1027
1029
  const now = (/* @__PURE__ */ new Date()).toISOString();
1028
1030
  if (result.includes("<dcterms:modified")) result = result.replace(/<dcterms:modified[^<>]*>[^<]*<\/dcterms:modified>/u, `<dcterms:modified xsi:type="dcterms:W3CDTF">${now}</dcterms:modified>`);
1029
- else result = result.replace("</cp:coreProperties>", `<dcterms:modified xsi:type="dcterms:W3CDTF">${now}</dcterms:modified></cp:coreProperties>`);
1030
1031
  }
1031
- if (options.modifiedBy) if (result.includes("<cp:lastModifiedBy")) result = result.replace(/<cp:lastModifiedBy>[^<]*<\/cp:lastModifiedBy>/u, `<cp:lastModifiedBy>${escapeXml(options.modifiedBy)}</cp:lastModifiedBy>`);
1032
- else result = result.replace("</cp:coreProperties>", `<cp:lastModifiedBy>${escapeXml(options.modifiedBy)}</cp:lastModifiedBy></cp:coreProperties>`);
1032
+ if (modifiedBy) {
1033
+ if (result.includes("<cp:lastModifiedBy")) result = result.replace(/<cp:lastModifiedBy>[^<]*<\/cp:lastModifiedBy>/u, `<cp:lastModifiedBy>${escapeXml(modifiedBy)}</cp:lastModifiedBy>`);
1034
+ }
1033
1035
  return result;
1034
1036
  }
1035
1037
  /**
@@ -1169,7 +1171,7 @@ function createEmptyDocx() {
1169
1171
  zip.file("docProps/app.xml", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
1170
1172
  <Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties">
1171
1173
  <Application>EigenPal DOCX Editor</Application>
1172
- <AppVersion>1.0.0</AppVersion>
1174
+ <AppVersion>1.0000</AppVersion>
1173
1175
  </Properties>`);
1174
1176
  return zip.generateAsync({
1175
1177
  type: "arraybuffer",
@@ -1184,11 +1186,72 @@ function createEmptyDocx() {
1184
1186
  * @returns Promise resolving to DOCX as ArrayBuffer
1185
1187
  */
1186
1188
  async function createDocx(doc) {
1187
- const emptyBuffer = await createEmptyDocx();
1189
+ const emptyBuffer = await createDocumentSeedDocx(doc);
1188
1190
  return repackDocx({
1189
1191
  ...doc,
1190
1192
  originalBuffer: emptyBuffer
1191
1193
  });
1192
1194
  }
1195
+ const createDocumentSeedDocx = async (doc) => {
1196
+ const buffer = await createEmptyDocx();
1197
+ const zip = await JSZip.loadAsync(buffer);
1198
+ const relationships = ["<Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\" Target=\"styles.xml\"/>"];
1199
+ const overrides = [];
1200
+ let nextRelationshipId = 2;
1201
+ if (doc.package.styles) {
1202
+ assertStyleNumberingReferences(doc);
1203
+ zip.file("word/styles.xml", serializeStylesXml(doc.package.styles));
1204
+ }
1205
+ const numbering = doc.package.numbering;
1206
+ if (numbering && (numbering.abstractNums.length > 0 || numbering.nums.length > 0)) {
1207
+ zip.file("word/numbering.xml", serializeNumberingXml(numbering));
1208
+ relationships.push(relationshipXml(nextRelationshipId, "numbering", "numbering.xml"));
1209
+ overrides.push(overrideXml("/word/numbering.xml", "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml"));
1210
+ nextRelationshipId += 1;
1211
+ }
1212
+ if (doc.package.theme) {
1213
+ zip.file("word/theme/theme1.xml", serializeThemeXml(doc.package.theme));
1214
+ relationships.push(relationshipXml(nextRelationshipId, "theme", "theme/theme1.xml"));
1215
+ overrides.push(overrideXml("/word/theme/theme1.xml", "application/vnd.openxmlformats-officedocument.theme+xml"));
1216
+ nextRelationshipId += 1;
1217
+ }
1218
+ if (doc.package.fontTable && doc.package.fontTable.fonts.length > 0) {
1219
+ zip.file("word/fontTable.xml", serializeFontTableXml(doc.package.fontTable));
1220
+ relationships.push(relationshipXml(nextRelationshipId, "fontTable", "fontTable.xml"));
1221
+ overrides.push(overrideXml("/word/fontTable.xml", "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml"));
1222
+ nextRelationshipId += 1;
1223
+ }
1224
+ if (doc.package.settings) {
1225
+ zip.file("word/settings.xml", serializeSettingsXml(doc.package.settings));
1226
+ relationships.push(relationshipXml(nextRelationshipId, "settings", "settings.xml"));
1227
+ overrides.push(overrideXml("/word/settings.xml", "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml"));
1228
+ }
1229
+ 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>`);
1230
+ if (overrides.length > 0) {
1231
+ const contentTypesFile = zip.file("[Content_Types].xml");
1232
+ if (!contentTypesFile) panic("Fresh DOCX seed is missing [Content_Types].xml");
1233
+ const contentTypes = await contentTypesFile.async("string");
1234
+ zip.file("[Content_Types].xml", contentTypes.replace("</Types>", `${overrides.join("")}\n</Types>`));
1235
+ }
1236
+ return zip.generateAsync({
1237
+ type: "arraybuffer",
1238
+ compression: "DEFLATE",
1239
+ compressionOptions: { level: 6 }
1240
+ });
1241
+ };
1242
+ const relationshipXml = (id, type, target) => `<Relationship Id="rId${id}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/${type}" Target="${target}"/>`;
1243
+ const overrideXml = (partName, contentType) => `<Override PartName="${partName}" ContentType="${contentType}"/>`;
1244
+ const assertStyleNumberingReferences = (doc) => {
1245
+ const referenced = /* @__PURE__ */ new Set();
1246
+ for (const style of doc.package.styles?.styles ?? []) {
1247
+ const numId = style.pPr?.numPr?.numId;
1248
+ if (numId !== void 0) referenced.add(numId);
1249
+ }
1250
+ if (referenced.size === 0) return;
1251
+ const available = new Set(doc.package.numbering?.nums.map((numbering) => numbering.numId) ?? []);
1252
+ for (const numId of referenced) if (!available.has(numId)) panic(`Style references missing numbering definition ${numId}`);
1253
+ const availableAbstract = new Set(doc.package.numbering?.abstractNums.map((numbering) => numbering.abstractNumId) ?? []);
1254
+ for (const numbering of doc.package.numbering?.nums ?? []) if (!availableAbstract.has(numbering.abstractNumId)) panic(`Numbering definition ${numbering.numId} references missing abstract numbering`);
1255
+ };
1193
1256
  //#endregion
1194
1257
  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":