@stll/folio-core 0.32.2 → 0.33.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 (222) hide show
  1. package/dist/ai-edits/__fixtures__/paragraphs.d.ts +17 -0
  2. package/dist/ai-edits/__fixtures__/paragraphs.js +33 -0
  3. package/dist/ai-edits/apply.d.ts +49 -3
  4. package/dist/ai-edits/apply.js +649 -85
  5. package/dist/ai-edits/blockRange.d.ts +7 -3
  6. package/dist/ai-edits/blockRange.js +14 -6
  7. package/dist/ai-edits/headless.d.ts +39 -5
  8. package/dist/ai-edits/headless.js +76 -17
  9. package/dist/ai-edits/index.d.ts +6 -6
  10. package/dist/ai-edits/index.js +3 -3
  11. package/dist/ai-edits/read.d.ts +4 -0
  12. package/dist/ai-edits/read.js +30 -6
  13. package/dist/ai-edits/scoped-reading.js +4 -3
  14. package/dist/ai-edits/snapshot.d.ts +42 -2
  15. package/dist/ai-edits/snapshot.js +127 -62
  16. package/dist/ai-edits/table-row-column-mutations.d.ts +24 -1
  17. package/dist/ai-edits/table-row-column-mutations.js +98 -6
  18. package/dist/ai-edits/table-targets.d.ts +12 -3
  19. package/dist/ai-edits/table-targets.js +15 -5
  20. package/dist/ai-edits/types.d.ts +219 -15
  21. package/dist/ai-edits/word-diff.d.ts +54 -11
  22. package/dist/ai-edits/word-diff.js +221 -61
  23. package/dist/compare/__fixtures__/body-sequence.d.ts +33 -0
  24. package/dist/compare/__fixtures__/body-sequence.js +67 -0
  25. package/dist/compare/__fixtures__/nested-table.d.ts +16 -0
  26. package/dist/compare/__fixtures__/nested-table.js +50 -0
  27. package/dist/compare/__fixtures__/numbered-list.d.ts +34 -0
  28. package/dist/compare/__fixtures__/numbered-list.js +85 -0
  29. package/dist/compare/column-alignment.d.ts +27 -0
  30. package/dist/compare/column-alignment.js +162 -0
  31. package/dist/compare/compare.d.ts +107 -0
  32. package/dist/compare/compare.js +406 -0
  33. package/dist/compare/formatting.d.ts +29 -0
  34. package/dist/compare/formatting.js +84 -0
  35. package/dist/compare/plan.d.ts +22 -0
  36. package/dist/compare/plan.js +1059 -0
  37. package/dist/compare/reproducible-package.d.ts +17 -0
  38. package/dist/compare/reproducible-package.js +30 -0
  39. package/dist/compare/scenario.d.ts +77 -0
  40. package/dist/compare/scenario.js +263 -0
  41. package/dist/compare/types.d.ts +282 -0
  42. package/dist/compare/types.js +32 -0
  43. package/dist/compare/verification.d.ts +55 -0
  44. package/dist/compare/verification.js +146 -0
  45. package/dist/compat/eigenpal.d.ts +9 -6
  46. package/dist/compat/eigenpal.js +6 -3
  47. package/dist/controller/layoutPipeline.d.ts +13 -0
  48. package/dist/controller/layoutPipeline.js +15 -1
  49. package/dist/display-list/build/buildContext.d.ts +39 -0
  50. package/dist/display-list/build/buildContext.js +31 -0
  51. package/dist/display-list/build/buildDisplayList.d.ts +79 -0
  52. package/dist/display-list/build/buildDisplayList.js +283 -0
  53. package/dist/display-list/build/colors.d.ts +20 -0
  54. package/dist/display-list/build/colors.js +136 -0
  55. package/dist/display-list/build/floatingImages.d.ts +24 -0
  56. package/dist/display-list/build/floatingImages.js +41 -0
  57. package/dist/display-list/build/fontTable.d.ts +31 -0
  58. package/dist/display-list/build/fontTable.js +97 -0
  59. package/dist/display-list/build/furniture.d.ts +86 -0
  60. package/dist/display-list/build/furniture.js +98 -0
  61. package/dist/display-list/build/glyphs.d.ts +55 -0
  62. package/dist/display-list/build/glyphs.js +103 -0
  63. package/dist/display-list/build/headerFooterPrimitives.d.ts +17 -0
  64. package/dist/display-list/build/headerFooterPrimitives.js +40 -0
  65. package/dist/display-list/build/imagePrimitives.d.ts +35 -0
  66. package/dist/display-list/build/imagePrimitives.js +264 -0
  67. package/dist/display-list/build/pageBorderPrimitives.d.ts +23 -0
  68. package/dist/display-list/build/pageBorderPrimitives.js +111 -0
  69. package/dist/display-list/build/pageFurniture.d.ts +35 -0
  70. package/dist/display-list/build/pageFurniture.js +141 -0
  71. package/dist/display-list/build/paragraphPrimitives.d.ts +19 -0
  72. package/dist/display-list/build/paragraphPrimitives.js +819 -0
  73. package/dist/display-list/build/regions.d.ts +46 -0
  74. package/dist/display-list/build/regions.js +56 -0
  75. package/dist/display-list/build/storyPrimitives.d.ts +29 -0
  76. package/dist/display-list/build/storyPrimitives.js +279 -0
  77. package/dist/display-list/build/strokes.d.ts +19 -0
  78. package/dist/display-list/build/strokes.js +78 -0
  79. package/dist/display-list/build/tablePrimitives.d.ts +38 -0
  80. package/dist/display-list/build/tablePrimitives.js +409 -0
  81. package/dist/display-list/build/textBoxPrimitives.d.ts +14 -0
  82. package/dist/display-list/build/textBoxPrimitives.js +129 -0
  83. package/dist/display-list/build/textDecorations.d.ts +29 -0
  84. package/dist/display-list/build/textDecorations.js +29 -0
  85. package/dist/display-list/build/unsupported.d.ts +57 -0
  86. package/dist/display-list/build/unsupported.js +0 -0
  87. package/dist/display-list/build/watermarkPrimitives.d.ts +15 -0
  88. package/dist/display-list/build/watermarkPrimitives.js +128 -0
  89. package/dist/display-list/dom/renderDisplayListToDom.d.ts +26 -0
  90. package/dist/display-list/dom/renderDisplayListToDom.js +620 -0
  91. package/dist/display-list/editor/displayListPagePainter.d.ts +22 -0
  92. package/dist/display-list/editor/displayListPagePainter.js +63 -0
  93. package/dist/display-list/editor/pageRenderer.d.ts +24 -0
  94. package/dist/display-list/editor/pageRenderer.js +36 -0
  95. package/dist/display-list/primitives.d.ts +95 -0
  96. package/dist/display-list/primitives.js +127 -0
  97. package/dist/display-list/types.d.ts +472 -0
  98. package/dist/display-list/types.js +0 -0
  99. package/dist/document-operations.d.ts +39 -8
  100. package/dist/document-operations.js +169 -16
  101. package/dist/document-stories.d.ts +16 -0
  102. package/dist/document-stories.js +48 -4
  103. package/dist/docx/packageParts.d.ts +35 -0
  104. package/dist/docx/packageParts.js +120 -0
  105. package/dist/docx/paragraphParser.js +22 -22
  106. package/dist/docx/paragraphTraversal.js +1 -1
  107. package/dist/docx/renderedPageBreakNormalization.js +3 -1
  108. package/dist/docx/revisionIdNormalization.d.ts +13 -0
  109. package/dist/docx/revisionIdNormalization.js +103 -0
  110. package/dist/docx/rezip.js +26 -17
  111. package/dist/docx/selectiveSave.js +2 -2
  112. package/dist/docx/serializer/commentSerializer.js +6 -1
  113. package/dist/docx/serializer/paragraphSerializer.js +33 -4
  114. package/dist/docx/serializer/runSerializer.js +11 -10
  115. package/dist/docx/serializer/tableSerializer.js +2 -1
  116. package/dist/docx/server/applyDocxXmlPatchProposal.js +1 -1
  117. package/dist/docx/server/createBilingualDocx.js +3 -2
  118. package/dist/docx/streamingXmlParser.d.ts +13 -1
  119. package/dist/docx/streamingXmlParser.js +49 -11
  120. package/dist/docx/unzip.d.ts +1 -2
  121. package/dist/docx/unzip.js +25 -6
  122. package/dist/docx/xmlParser.d.ts +3 -1
  123. package/dist/docx/xmlParser.js +33 -27
  124. package/dist/export-pdf.d.ts +43 -0
  125. package/dist/export-pdf.js +98 -0
  126. package/dist/fonts/headlessMeasure.d.ts +76 -0
  127. package/dist/fonts/headlessMeasure.js +0 -0
  128. package/dist/fonts/sfnt/parse.d.ts +51 -0
  129. package/dist/fonts/sfnt/parse.js +525 -0
  130. package/dist/fonts/sfnt/subset.d.ts +20 -0
  131. package/dist/fonts/sfnt/subset.js +350 -0
  132. package/dist/fonts/sfnt/tables.d.ts +88 -0
  133. package/dist/fonts/sfnt/tables.js +131 -0
  134. package/dist/fonts/sfnt/woff.d.ts +14 -0
  135. package/dist/fonts/sfnt/woff.js +163 -0
  136. package/dist/generated/text_shaper.js +324 -0
  137. package/dist/generated/text_shaper_bg.wasm +0 -0
  138. package/dist/headless-layout.d.ts +75 -0
  139. package/dist/headless-layout.js +350 -0
  140. package/dist/index.d.ts +9 -6
  141. package/dist/index.js +6 -3
  142. package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
  143. package/dist/layout-bridge/convert/footnoteLayout.js +1 -0
  144. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
  145. package/dist/layout-bridge/convert/headerFooterLayout.js +2 -0
  146. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +3 -1
  147. package/dist/layout-bridge/convert/toFlowBlocks.js +2 -0
  148. package/dist/layout-engine/measure/advanceComposition.d.ts +62 -0
  149. package/dist/layout-engine/measure/advanceComposition.js +148 -0
  150. package/dist/layout-engine/measure/cache.d.ts +2 -0
  151. package/dist/layout-engine/measure/measureContainer.js +13 -0
  152. package/dist/layout-engine/measure/measureParagraph.js +1 -2
  153. package/dist/layout-engine/measure/measureTypes.d.ts +12 -0
  154. package/dist/layout-engine/measure/tableInlinePlacement.d.ts +3 -2
  155. package/dist/layout-engine/measure/tableInlinePlacement.js +14 -1
  156. package/dist/layout-engine/tableIndentCompatibility.d.ts +5 -0
  157. package/dist/layout-engine/tableIndentCompatibility.js +15 -0
  158. package/dist/layout-engine/types.d.ts +8 -0
  159. package/dist/layout-painter/renderPage.d.ts +29 -1
  160. package/dist/layout-painter/renderPage.js +47 -19
  161. package/dist/layout-painter/renderParagraph.d.ts +21 -2
  162. package/dist/layout-painter/renderParagraph.js +1 -1
  163. package/dist/layout-painter/renderTable.js +37 -4
  164. package/dist/managers/editorShortcuts.d.ts +33 -1
  165. package/dist/managers/editorShortcuts.js +20 -1
  166. package/dist/markdown/renderRuns.js +7 -2
  167. package/dist/markdown/renderTable.js +5 -1
  168. package/dist/model.d.ts +3 -3
  169. package/dist/model.js +2 -2
  170. package/dist/pdf/contentStream.d.ts +73 -0
  171. package/dist/pdf/contentStream.js +143 -0
  172. package/dist/pdf/fonts.d.ts +96 -0
  173. package/dist/pdf/fonts.js +593 -0
  174. package/dist/pdf/images.d.ts +28 -0
  175. package/dist/pdf/images.js +439 -0
  176. package/dist/pdf/objects.d.ts +93 -0
  177. package/dist/pdf/objects.js +237 -0
  178. package/dist/pdf/pageSpace.d.ts +43 -0
  179. package/dist/pdf/pageSpace.js +57 -0
  180. package/dist/pdf/paint.d.ts +32 -0
  181. package/dist/pdf/paint.js +442 -0
  182. package/dist/pdf/writePdf.d.ts +56 -0
  183. package/dist/pdf/writePdf.js +345 -0
  184. package/dist/prosemirror/commands/comments.js +91 -6
  185. package/dist/prosemirror/conversion/fromProseDoc.js +41 -7
  186. package/dist/prosemirror/conversion/toProseDoc.js +41 -4
  187. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +15 -2
  188. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +35 -6
  189. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +2 -2
  190. package/dist/prosemirror/extensions/features/pasteCleanup.js +4 -3
  191. package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.d.ts +3 -1
  192. package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +5 -3
  193. package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.d.ts +7 -1
  194. package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.js +9 -3
  195. package/dist/prosemirror/extensions/nodes/TableExtension.js +56 -39
  196. package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.d.ts +3 -1
  197. package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.js +5 -3
  198. package/dist/prosemirror/plugins/suggestionMode.js +1 -0
  199. package/dist/prosemirror/revisionCarriers.js +19 -2
  200. package/dist/prosemirror/utils/extractTrackedChanges.d.ts +2 -2
  201. package/dist/prosemirror/utils/extractTrackedChanges.js +59 -23
  202. package/dist/prosemirror/validation.js +55 -27
  203. package/dist/prosemirror/zeroWidthAnchors.d.ts +10 -0
  204. package/dist/prosemirror/zeroWidthAnchors.js +23 -0
  205. package/dist/redline.js +12 -79
  206. package/dist/server.d.ts +3 -3
  207. package/dist/server.js +2 -2
  208. package/dist/shaping/placeRun.d.ts +51 -0
  209. package/dist/shaping/placeRun.js +84 -0
  210. package/dist/shaping/shaper.d.ts +92 -0
  211. package/dist/shaping/shaper.js +102 -0
  212. package/dist/types/block-id.d.ts +18 -2
  213. package/dist/types/block-id.js +49 -5
  214. package/dist/types/content.d.ts +2 -2
  215. package/dist/utils/clipboard.js +4 -3
  216. package/dist/utils/fontResolver.js +183 -0
  217. package/dist/utils/htmlComments.d.ts +17 -0
  218. package/dist/utils/htmlComments.js +22 -0
  219. package/dist/utils/scriptSegments.d.ts +12 -1
  220. package/dist/utils/scriptSegments.js +17 -1
  221. package/dist/version-comparison.d.ts +1 -1
  222. package/package.json +7 -3
@@ -64,6 +64,37 @@ const resolveNamespaceUri = (scope, prefix) => {
64
64
  current = current.parent;
65
65
  }
66
66
  };
67
+ /** Attach the element's resolved namespace metadata from its in-scope declarations. */
68
+ const attachXmlNamespaceContext = (element, inheritedNamespaceScope = EMPTY_NAMESPACE_SCOPE) => {
69
+ let localBindings = null;
70
+ if (element.attributes) for (const [attribute, value] of Object.entries(element.attributes)) {
71
+ if (typeof value !== "string" || attribute !== "xmlns" && !attribute.startsWith("xmlns:")) continue;
72
+ localBindings ??= /* @__PURE__ */ new Map();
73
+ const prefix = attribute === "xmlns" ? "" : attribute.slice(6);
74
+ localBindings.set(prefix, value);
75
+ }
76
+ const namespaceScope = localBindings === null ? inheritedNamespaceScope : {
77
+ bindings: localBindings,
78
+ parent: inheritedNamespaceScope
79
+ };
80
+ Object.defineProperty(element, "namespaceScope", {
81
+ configurable: false,
82
+ enumerable: false,
83
+ value: namespaceScope,
84
+ writable: false
85
+ });
86
+ const name = element.name ?? "";
87
+ const colonIndex = name.indexOf(":");
88
+ const prefix = colonIndex === -1 ? "" : name.slice(0, colonIndex);
89
+ const namespaceUri = resolveNamespaceUri(namespaceScope, prefix);
90
+ if (namespaceUri !== void 0) Object.defineProperty(element, "namespaceUri", {
91
+ configurable: false,
92
+ enumerable: false,
93
+ value: namespaceUri,
94
+ writable: false
95
+ });
96
+ return namespaceScope;
97
+ };
67
98
  /**
68
99
  * Convert a fast-xml-parser preserveOrder node into an XmlElement.
69
100
  *
@@ -85,32 +116,7 @@ function fxpNodeToElement(node, inheritedNamespaceScope = EMPTY_NAMESPACE_SCOPE)
85
116
  name: key
86
117
  };
87
118
  if (attrs) element.attributes = attrs;
88
- let localBindings = null;
89
- if (attrs) for (const [attribute, value] of Object.entries(attrs)) {
90
- if (attribute !== "xmlns" && !attribute.startsWith("xmlns:")) continue;
91
- localBindings ??= /* @__PURE__ */ new Map();
92
- const prefix = attribute === "xmlns" ? "" : attribute.slice(6);
93
- localBindings.set(prefix, value);
94
- }
95
- const namespaceScope = localBindings === null ? inheritedNamespaceScope : {
96
- bindings: localBindings,
97
- parent: inheritedNamespaceScope
98
- };
99
- Object.defineProperty(element, "namespaceScope", {
100
- configurable: false,
101
- enumerable: false,
102
- value: namespaceScope,
103
- writable: false
104
- });
105
- const colonIndex = key.indexOf(":");
106
- const prefix = colonIndex === -1 ? "" : key.slice(0, colonIndex);
107
- const namespaceUri = resolveNamespaceUri(namespaceScope, prefix);
108
- if (namespaceUri !== void 0) Object.defineProperty(element, "namespaceUri", {
109
- configurable: false,
110
- enumerable: false,
111
- value: namespaceUri,
112
- writable: false
113
- });
119
+ const namespaceScope = attachXmlNamespaceContext(element, inheritedNamespaceScope);
114
120
  if (children.length > 0) {
115
121
  for (let index = 0; index < children.length; index += 1) children[index] = fxpNodeToElement(children[index], namespaceScope);
116
122
  element.elements = children;
@@ -745,4 +751,4 @@ function cloneWithXmlnsDeclarations(element, xmlnsDecls) {
745
751
  return element;
746
752
  }
747
753
  //#endregion
748
- export { NAMESPACES, WORDPROCESSINGML_NAMESPACE_URIS, cloneWithXmlnsDeclarations, collectXmlnsDeclarations, elementToXml, findAllDeep, findAttributeByNamespaceUri, findByFullName, findChild, findChildByLocalName, findChildByNamespaceUri, findChildren, findChildrenByLocalName, findDeep, getAttribute, getAttributeAny, getAttributeAnyPrefix, getAttributeByNamespaceUri, getAttributes, getChildElements, getLocalName, getNamespacePrefix, getNamespaceUri, getTextContent, hasChild, hasFlag, matchesName, mergeXmlnsDeclarations, parseBooleanElement, parseColorElement, parseNumberingLevelAttribute, parseNumericAttribute, parseOnOffValue, parseTableMeasurementValue, parseXml, parseXmlDocument };
754
+ export { NAMESPACES, WORDPROCESSINGML_NAMESPACE_URIS, attachXmlNamespaceContext, cloneWithXmlnsDeclarations, collectXmlnsDeclarations, elementToXml, findAllDeep, findAttributeByNamespaceUri, findByFullName, findChild, findChildByLocalName, findChildByNamespaceUri, findChildren, findChildrenByLocalName, findDeep, getAttribute, getAttributeAny, getAttributeAnyPrefix, getAttributeByNamespaceUri, getAttributes, getChildElements, getLocalName, getNamespacePrefix, getNamespaceUri, getTextContent, hasChild, hasFlag, matchesName, mergeXmlnsDeclarations, parseBooleanElement, parseColorElement, parseNumberingLevelAttribute, parseNumericAttribute, parseOnOffValue, parseTableMeasurementValue, parseXml, parseXmlDocument };
@@ -0,0 +1,43 @@
1
+ import { DocxInput } from "./utils/docxInput.js";
2
+ import { DisplayMetadata, DisplayUnsupported } from "./display-list/types.js";
3
+ import { HeadlessFontSource, HeadlessFontSubstitution } from "./fonts/headlessMeasure.js";
4
+ import { HeadlessLayoutGap } from "./headless-layout.js";
5
+ import { PdfSubstitution } from "./pdf/fonts.js";
6
+ import { PdfUnencodable } from "./pdf/writePdf.js";
7
+ import { Result } from "better-result";
8
+ //#region src/export-pdf.d.ts
9
+ declare const ExportPdfError_base: import("better-result").TaggedErrorClass<"ExportPdfError">;
10
+ declare class ExportPdfError extends ExportPdfError_base<{
11
+ message: string;
12
+ cause?: unknown;
13
+ }> {}
14
+ type ExportDocxToPdfOptions = {
15
+ /** Supplies face binaries for measurement and for embedding alike. */
16
+ readonly fonts: HeadlessFontSource;
17
+ /**
18
+ * ISO-8601 instant stamped as the PDF's creation and modification date.
19
+ * Required rather than defaulted so a caller cannot get a nondeterministic
20
+ * document by omission; pass the source package's own timestamp or a fixed
21
+ * epoch.
22
+ */
23
+ readonly timestamp: string;
24
+ readonly metadata?: DisplayMetadata;
25
+ readonly producer?: string;
26
+ };
27
+ type ExportDocxToPdfResult = {
28
+ readonly bytes: Uint8Array;
29
+ readonly pageCount: number;
30
+ /** Constructs the display list could not represent. */
31
+ readonly unsupported: readonly DisplayUnsupported[];
32
+ /** Stories the headless pipeline does not paginate. */
33
+ readonly layoutGaps: readonly HeadlessLayoutGap[];
34
+ /** Faces measured with a stand-in. */
35
+ readonly measurementSubstitutions: readonly HeadlessFontSubstitution[];
36
+ /** Faces embedded as a stand-in. */
37
+ readonly embeddingSubstitutions: readonly PdfSubstitution[];
38
+ /** Code points painted as `.notdef` because no supplied face covers them. */
39
+ readonly unencodable: readonly PdfUnencodable[];
40
+ };
41
+ declare const exportDocxToPdf: (input: DocxInput, options: ExportDocxToPdfOptions) => Promise<Result<ExportDocxToPdfResult, ExportPdfError>>;
42
+ //#endregion
43
+ export { ExportDocxToPdfOptions, ExportDocxToPdfResult, ExportPdfError, exportDocxToPdf };
@@ -0,0 +1,98 @@
1
+ import { buildDisplayList } from "./display-list/build/buildDisplayList.js";
2
+ import { installHeadlessMeasureProvider } from "./fonts/headlessMeasure.js";
3
+ import { layoutDocxHeadless } from "./headless-layout.js";
4
+ import { getMeasureProvider, setMeasureProvider } from "./layout-engine/measure/measureProvider.js";
5
+ import { writePdf } from "./pdf/writePdf.js";
6
+ import { Result, TaggedError } from "better-result";
7
+ //#region src/export-pdf.ts
8
+ /**
9
+ * `.docx` to PDF, with no browser and no second painter.
10
+ *
11
+ * The chain is four steps and no shortcuts: paginate headlessly, build the
12
+ * display list, hand the display list to the PDF backend, return the bytes.
13
+ * The editor's DOM backend consumes the same display list from the same
14
+ * builder, so the exported page and the displayed page cannot be laid out by
15
+ * two different sets of rules.
16
+ *
17
+ * ## One font source, two consumers
18
+ *
19
+ * Measurement and embedding read the same {@link HeadlessFontSource}. Laying
20
+ * out against one face and embedding another is the subtle version of the
21
+ * divergence this design exists to prevent: the pagination would be right for
22
+ * a font the reader never sees.
23
+ *
24
+ * ## Determinism
25
+ *
26
+ * `exportDocxToPdf(bytes, options)` is a pure function of its arguments.
27
+ * `options.timestamp` is required rather than defaulted, the same contract
28
+ * `compareDocx` uses, so a caller cannot get nondeterministic output by
29
+ * omission.
30
+ */
31
+ var ExportPdfError = class extends TaggedError("ExportPdfError") {};
32
+ const toFontRequest = ({ family, weight, italic }) => ({
33
+ family,
34
+ bold: weight >= 700,
35
+ italic
36
+ });
37
+ /**
38
+ * Exports run one at a time.
39
+ *
40
+ * The measurement provider is process-wide, and an export must install its own
41
+ * fonts across an `await`. Two overlapping exports would otherwise interleave:
42
+ * the second replaces the first's provider, the first resumes and measures
43
+ * against the second's fonts, then restores the provider while the second is
44
+ * still running. Serialising is the honest fix while the provider is ambient;
45
+ * threading it explicitly through the layout call would remove the need, and
46
+ * is the larger change this defers to.
47
+ */
48
+ let exportQueue = Promise.resolve();
49
+ const runExclusively = (run) => {
50
+ const current = exportQueue.then(run, run);
51
+ exportQueue = current.then(() => void 0, () => void 0);
52
+ return current;
53
+ };
54
+ const exportDocxToPdf = (input, options) => runExclusively(() => exportOnce(input, options));
55
+ const exportOnce = async (input, options) => {
56
+ const callerProvider = getMeasureProvider();
57
+ try {
58
+ return await exportWithHeadlessProvider(input, options);
59
+ } finally {
60
+ setMeasureProvider(callerProvider);
61
+ }
62
+ };
63
+ const exportWithHeadlessProvider = async (input, options) => {
64
+ const headless = installHeadlessMeasureProvider(options.fonts);
65
+ const laidOut = await layoutDocxHeadless(input, { pageGap: 0 });
66
+ if (laidOut.isErr()) return Result.err(new ExportPdfError({
67
+ message: laidOut.error.message,
68
+ cause: laidOut.error
69
+ }));
70
+ const list = buildDisplayList({
71
+ layout: laidOut.value.layout,
72
+ blockLookup: laidOut.value.blockLookup,
73
+ documentFeatures: laidOut.value.documentFeatures,
74
+ ...laidOut.value.furniture,
75
+ embeddedFonts: laidOut.value.embeddedFonts,
76
+ ...options.metadata === void 0 ? {} : { metadata: options.metadata }
77
+ });
78
+ const written = await writePdf(list, {
79
+ fonts: { load: (face) => options.fonts.load(toFontRequest(face)) },
80
+ timestamp: options.timestamp,
81
+ ...options.producer === void 0 ? {} : { producer: options.producer }
82
+ });
83
+ if (written.isErr()) return Result.err(new ExportPdfError({
84
+ message: written.error.message,
85
+ cause: written.error
86
+ }));
87
+ return Result.ok({
88
+ bytes: written.value.bytes,
89
+ pageCount: list.pages.length,
90
+ unsupported: list.unsupported,
91
+ layoutGaps: laidOut.value.unsupported,
92
+ measurementSubstitutions: headless.substitutions(),
93
+ embeddingSubstitutions: written.value.substitutions,
94
+ unencodable: written.value.unencodable
95
+ });
96
+ };
97
+ //#endregion
98
+ export { ExportPdfError, exportDocxToPdf };
@@ -0,0 +1,76 @@
1
+ import { MeasureProvider } from "../layout-engine/measure/measureProvider.js";
2
+ import { Shaper } from "../shaping/shaper.js";
3
+ import { Result } from "better-result";
4
+ //#region src/fonts/headlessMeasure.d.ts
5
+ /** One concrete face, as a font source is asked for it. */
6
+ type HeadlessFontRequest = {
7
+ readonly family: string;
8
+ readonly bold: boolean;
9
+ readonly italic: boolean;
10
+ };
11
+ /**
12
+ * Where face binaries come from. A server reads them from disk, a browser
13
+ * fetches them, a package supplies its own embedded faces; none of that is
14
+ * this module's business.
15
+ *
16
+ * A face is a *list* of binaries rather than one, because a family is
17
+ * routinely shipped split by script: `@fontsource` cuts every family into
18
+ * disjoint `latin`, `latin-ext`, `cyrillic` and `greek` subsets, and a Czech
19
+ * or Polish document needs two of them at once. Returning one binary per face
20
+ * would mean picking a subset per document and painting `.notdef` for
21
+ * everything outside it. The list is in priority order, and a code point is
22
+ * served by the first binary whose `cmap` covers it.
23
+ */
24
+ type HeadlessFontSource = {
25
+ /** Plain sfnt or WOFF binaries, empty when the source has no such face. */
26
+ readonly load: (request: HeadlessFontRequest) => readonly Uint8Array[];
27
+ };
28
+ /** A face the source could not supply, measured with a stand-in instead. */
29
+ type HeadlessFontSubstitution = {
30
+ readonly requested: HeadlessFontRequest;
31
+ readonly reason: string;
32
+ };
33
+ declare const HeadlessMeasureError_base: import("better-result").TaggedErrorClass<"HeadlessMeasureError">;
34
+ declare class HeadlessMeasureError extends HeadlessMeasureError_base<{
35
+ message: string;
36
+ }> {}
37
+ type HeadlessMeasureOptions = {
38
+ /**
39
+ * The shaper to measure shaping scripts with.
40
+ *
41
+ * Omitted, the provider uses whichever shaper has been loaded, which is what
42
+ * the layout entry points resolve once they find a document that needs one.
43
+ * Pass one explicitly to measure against a shaper of your own; pass `null` to
44
+ * measure as if none existed.
45
+ */
46
+ readonly shaper?: Shaper | null;
47
+ };
48
+ type HeadlessMeasureProvider = {
49
+ readonly provider: MeasureProvider;
50
+ /**
51
+ * Faces measured with a stand-in, in first-request order. A caller that
52
+ * ships the result to a user must surface these: a substituted face
53
+ * measures differently, so the pagination is not the authored one.
54
+ */
55
+ readonly substitutions: () => readonly HeadlessFontSubstitution[];
56
+ };
57
+ /**
58
+ * Build a provider over a font source. The provider is stateful only in its
59
+ * face cache and its substitution log, both scoped to the returned object, so
60
+ * two providers never contaminate each other.
61
+ */
62
+ declare const createHeadlessMeasureProvider: (source: HeadlessFontSource, options?: HeadlessMeasureOptions) => HeadlessMeasureProvider;
63
+ /**
64
+ * Install a headless backend as the active provider. An explicit call, never a
65
+ * module side effect, so importing this module cannot silently change how a
66
+ * document measures.
67
+ */
68
+ declare const installHeadlessMeasureProvider: (source: HeadlessFontSource, options?: HeadlessMeasureOptions) => HeadlessMeasureProvider;
69
+ /**
70
+ * Refuse to measure when a source cannot supply a face that the document
71
+ * actually uses. Callers that would rather fail than paginate against a
72
+ * stand-in call this after layout.
73
+ */
74
+ declare const assertNoSubstitutions: (headless: HeadlessMeasureProvider) => Result<void, HeadlessMeasureError>;
75
+ //#endregion
76
+ export { HeadlessFontRequest, HeadlessFontSource, HeadlessFontSubstitution, HeadlessMeasureError, HeadlessMeasureOptions, HeadlessMeasureProvider, assertNoSubstitutions, createHeadlessMeasureProvider, installHeadlessMeasureProvider };
Binary file
@@ -0,0 +1,51 @@
1
+ import { Result } from "better-result";
2
+ //#region src/fonts/sfnt/parse.d.ts
3
+ type SfntFont = {
4
+ readonly unitsPerEm: number;
5
+ /** hhea ascender/descender/lineGap, in font units; descender is negative. */
6
+ readonly ascender: number;
7
+ readonly descender: number;
8
+ readonly lineGap: number;
9
+ /** OS/2 sCapHeight and sxHeight when version >= 2, else derived from glyph bounds. */
10
+ readonly capHeight: number;
11
+ readonly xHeight: number;
12
+ /** post table italicAngle, degrees, negative for forward slant. */
13
+ readonly italicAngle: number;
14
+ /** head glyph bounding box: [xMin, yMin, xMax, yMax] in font units. */
15
+ readonly bbox: readonly [number, number, number, number];
16
+ readonly postScriptName: string;
17
+ /** true when outlines live in a `CFF ` table rather than `glyf`. */
18
+ readonly isCff: boolean;
19
+ readonly numGlyphs: number;
20
+ /** OS/2 fsType embedding permission bits, for the caller to police. */
21
+ readonly fsType: number;
22
+ /** The decoded sfnt bytes this font was parsed from. */
23
+ readonly bytes: Uint8Array;
24
+ /** Best-available cmap lookup. Returns 0 (.notdef) when unmapped. */
25
+ readonly glyphIdFor: (codePoint: number) => number;
26
+ /** hmtx advance in font units. Clamped to the last entry, per spec. */
27
+ readonly advanceWidthFor: (glyphId: number) => number;
28
+ /**
29
+ * Ink bounding box of one glyph in font units, or null when the glyph is
30
+ * empty (a space) or has no outline this reader can measure.
31
+ *
32
+ * This is what a canvas backend reports as `actualBoundingBox*`, and it is
33
+ * not the hhea metrics: a headless measure provider needs the ink extent to
34
+ * place baselines the way canvas does.
35
+ */
36
+ readonly glyphBoundsFor: (glyphId: number) => SfntGlyphBounds | null;
37
+ };
38
+ /** Ink extent of a single glyph, in font units. */
39
+ type SfntGlyphBounds = {
40
+ readonly xMin: number;
41
+ readonly yMin: number;
42
+ readonly xMax: number;
43
+ readonly yMax: number;
44
+ };
45
+ declare const SfntParseError_base: import("better-result").TaggedErrorClass<"SfntParseError">;
46
+ declare class SfntParseError extends SfntParseError_base<{
47
+ message: string;
48
+ }> {}
49
+ declare const parseSfnt: (bytes: Uint8Array) => Result<SfntFont, SfntParseError>;
50
+ //#endregion
51
+ export { SfntFont, SfntGlyphBounds, SfntParseError, parseSfnt };