@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.
- package/dist/ai-edits/__fixtures__/paragraphs.d.ts +17 -0
- package/dist/ai-edits/__fixtures__/paragraphs.js +33 -0
- package/dist/ai-edits/apply.d.ts +49 -3
- package/dist/ai-edits/apply.js +649 -85
- package/dist/ai-edits/blockRange.d.ts +7 -3
- package/dist/ai-edits/blockRange.js +14 -6
- package/dist/ai-edits/headless.d.ts +39 -5
- package/dist/ai-edits/headless.js +76 -17
- package/dist/ai-edits/index.d.ts +6 -6
- package/dist/ai-edits/index.js +3 -3
- package/dist/ai-edits/read.d.ts +4 -0
- package/dist/ai-edits/read.js +30 -6
- package/dist/ai-edits/scoped-reading.js +4 -3
- package/dist/ai-edits/snapshot.d.ts +42 -2
- package/dist/ai-edits/snapshot.js +127 -62
- package/dist/ai-edits/table-row-column-mutations.d.ts +24 -1
- package/dist/ai-edits/table-row-column-mutations.js +98 -6
- package/dist/ai-edits/table-targets.d.ts +12 -3
- package/dist/ai-edits/table-targets.js +15 -5
- package/dist/ai-edits/types.d.ts +219 -15
- package/dist/ai-edits/word-diff.d.ts +54 -11
- package/dist/ai-edits/word-diff.js +221 -61
- package/dist/compare/__fixtures__/body-sequence.d.ts +33 -0
- package/dist/compare/__fixtures__/body-sequence.js +67 -0
- package/dist/compare/__fixtures__/nested-table.d.ts +16 -0
- package/dist/compare/__fixtures__/nested-table.js +50 -0
- package/dist/compare/__fixtures__/numbered-list.d.ts +34 -0
- package/dist/compare/__fixtures__/numbered-list.js +85 -0
- package/dist/compare/column-alignment.d.ts +27 -0
- package/dist/compare/column-alignment.js +162 -0
- package/dist/compare/compare.d.ts +107 -0
- package/dist/compare/compare.js +406 -0
- package/dist/compare/formatting.d.ts +29 -0
- package/dist/compare/formatting.js +84 -0
- package/dist/compare/plan.d.ts +22 -0
- package/dist/compare/plan.js +1059 -0
- package/dist/compare/reproducible-package.d.ts +17 -0
- package/dist/compare/reproducible-package.js +30 -0
- package/dist/compare/scenario.d.ts +77 -0
- package/dist/compare/scenario.js +263 -0
- package/dist/compare/types.d.ts +282 -0
- package/dist/compare/types.js +32 -0
- package/dist/compare/verification.d.ts +55 -0
- package/dist/compare/verification.js +146 -0
- package/dist/compat/eigenpal.d.ts +9 -6
- package/dist/compat/eigenpal.js +6 -3
- package/dist/controller/layoutPipeline.d.ts +13 -0
- package/dist/controller/layoutPipeline.js +15 -1
- package/dist/display-list/build/buildContext.d.ts +39 -0
- package/dist/display-list/build/buildContext.js +31 -0
- package/dist/display-list/build/buildDisplayList.d.ts +79 -0
- package/dist/display-list/build/buildDisplayList.js +283 -0
- package/dist/display-list/build/colors.d.ts +20 -0
- package/dist/display-list/build/colors.js +136 -0
- package/dist/display-list/build/floatingImages.d.ts +24 -0
- package/dist/display-list/build/floatingImages.js +41 -0
- package/dist/display-list/build/fontTable.d.ts +31 -0
- package/dist/display-list/build/fontTable.js +97 -0
- package/dist/display-list/build/furniture.d.ts +86 -0
- package/dist/display-list/build/furniture.js +98 -0
- package/dist/display-list/build/glyphs.d.ts +55 -0
- package/dist/display-list/build/glyphs.js +103 -0
- package/dist/display-list/build/headerFooterPrimitives.d.ts +17 -0
- package/dist/display-list/build/headerFooterPrimitives.js +40 -0
- package/dist/display-list/build/imagePrimitives.d.ts +35 -0
- package/dist/display-list/build/imagePrimitives.js +264 -0
- package/dist/display-list/build/pageBorderPrimitives.d.ts +23 -0
- package/dist/display-list/build/pageBorderPrimitives.js +111 -0
- package/dist/display-list/build/pageFurniture.d.ts +35 -0
- package/dist/display-list/build/pageFurniture.js +141 -0
- package/dist/display-list/build/paragraphPrimitives.d.ts +19 -0
- package/dist/display-list/build/paragraphPrimitives.js +819 -0
- package/dist/display-list/build/regions.d.ts +46 -0
- package/dist/display-list/build/regions.js +56 -0
- package/dist/display-list/build/storyPrimitives.d.ts +29 -0
- package/dist/display-list/build/storyPrimitives.js +279 -0
- package/dist/display-list/build/strokes.d.ts +19 -0
- package/dist/display-list/build/strokes.js +78 -0
- package/dist/display-list/build/tablePrimitives.d.ts +38 -0
- package/dist/display-list/build/tablePrimitives.js +409 -0
- package/dist/display-list/build/textBoxPrimitives.d.ts +14 -0
- package/dist/display-list/build/textBoxPrimitives.js +129 -0
- package/dist/display-list/build/textDecorations.d.ts +29 -0
- package/dist/display-list/build/textDecorations.js +29 -0
- package/dist/display-list/build/unsupported.d.ts +57 -0
- package/dist/display-list/build/unsupported.js +0 -0
- package/dist/display-list/build/watermarkPrimitives.d.ts +15 -0
- package/dist/display-list/build/watermarkPrimitives.js +128 -0
- package/dist/display-list/dom/renderDisplayListToDom.d.ts +26 -0
- package/dist/display-list/dom/renderDisplayListToDom.js +620 -0
- package/dist/display-list/editor/displayListPagePainter.d.ts +22 -0
- package/dist/display-list/editor/displayListPagePainter.js +63 -0
- package/dist/display-list/editor/pageRenderer.d.ts +24 -0
- package/dist/display-list/editor/pageRenderer.js +36 -0
- package/dist/display-list/primitives.d.ts +95 -0
- package/dist/display-list/primitives.js +127 -0
- package/dist/display-list/types.d.ts +472 -0
- package/dist/display-list/types.js +0 -0
- package/dist/document-operations.d.ts +39 -8
- package/dist/document-operations.js +169 -16
- package/dist/document-stories.d.ts +16 -0
- package/dist/document-stories.js +48 -4
- package/dist/docx/packageParts.d.ts +35 -0
- package/dist/docx/packageParts.js +120 -0
- package/dist/docx/paragraphParser.js +22 -22
- package/dist/docx/paragraphTraversal.js +1 -1
- package/dist/docx/renderedPageBreakNormalization.js +3 -1
- package/dist/docx/revisionIdNormalization.d.ts +13 -0
- package/dist/docx/revisionIdNormalization.js +103 -0
- package/dist/docx/rezip.js +26 -17
- package/dist/docx/selectiveSave.js +2 -2
- package/dist/docx/serializer/commentSerializer.js +6 -1
- package/dist/docx/serializer/paragraphSerializer.js +33 -4
- package/dist/docx/serializer/runSerializer.js +11 -10
- package/dist/docx/serializer/tableSerializer.js +2 -1
- package/dist/docx/server/applyDocxXmlPatchProposal.js +1 -1
- package/dist/docx/server/createBilingualDocx.js +3 -2
- package/dist/docx/streamingXmlParser.d.ts +13 -1
- package/dist/docx/streamingXmlParser.js +49 -11
- package/dist/docx/unzip.d.ts +1 -2
- package/dist/docx/unzip.js +25 -6
- package/dist/docx/xmlParser.d.ts +3 -1
- package/dist/docx/xmlParser.js +33 -27
- package/dist/export-pdf.d.ts +43 -0
- package/dist/export-pdf.js +98 -0
- package/dist/fonts/headlessMeasure.d.ts +76 -0
- package/dist/fonts/headlessMeasure.js +0 -0
- package/dist/fonts/sfnt/parse.d.ts +51 -0
- package/dist/fonts/sfnt/parse.js +525 -0
- package/dist/fonts/sfnt/subset.d.ts +20 -0
- package/dist/fonts/sfnt/subset.js +350 -0
- package/dist/fonts/sfnt/tables.d.ts +88 -0
- package/dist/fonts/sfnt/tables.js +131 -0
- package/dist/fonts/sfnt/woff.d.ts +14 -0
- package/dist/fonts/sfnt/woff.js +163 -0
- package/dist/generated/text_shaper.js +324 -0
- package/dist/generated/text_shaper_bg.wasm +0 -0
- package/dist/headless-layout.d.ts +75 -0
- package/dist/headless-layout.js +350 -0
- package/dist/index.d.ts +9 -6
- package/dist/index.js +6 -3
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/footnoteLayout.js +1 -0
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/headerFooterLayout.js +2 -0
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +3 -1
- package/dist/layout-bridge/convert/toFlowBlocks.js +2 -0
- package/dist/layout-engine/measure/advanceComposition.d.ts +62 -0
- package/dist/layout-engine/measure/advanceComposition.js +148 -0
- package/dist/layout-engine/measure/cache.d.ts +2 -0
- package/dist/layout-engine/measure/measureContainer.js +13 -0
- package/dist/layout-engine/measure/measureParagraph.js +1 -2
- package/dist/layout-engine/measure/measureTypes.d.ts +12 -0
- package/dist/layout-engine/measure/tableInlinePlacement.d.ts +3 -2
- package/dist/layout-engine/measure/tableInlinePlacement.js +14 -1
- package/dist/layout-engine/tableIndentCompatibility.d.ts +5 -0
- package/dist/layout-engine/tableIndentCompatibility.js +15 -0
- package/dist/layout-engine/types.d.ts +8 -0
- package/dist/layout-painter/renderPage.d.ts +29 -1
- package/dist/layout-painter/renderPage.js +47 -19
- package/dist/layout-painter/renderParagraph.d.ts +21 -2
- package/dist/layout-painter/renderParagraph.js +1 -1
- package/dist/layout-painter/renderTable.js +37 -4
- package/dist/managers/editorShortcuts.d.ts +33 -1
- package/dist/managers/editorShortcuts.js +20 -1
- package/dist/markdown/renderRuns.js +7 -2
- package/dist/markdown/renderTable.js +5 -1
- package/dist/model.d.ts +3 -3
- package/dist/model.js +2 -2
- package/dist/pdf/contentStream.d.ts +73 -0
- package/dist/pdf/contentStream.js +143 -0
- package/dist/pdf/fonts.d.ts +96 -0
- package/dist/pdf/fonts.js +593 -0
- package/dist/pdf/images.d.ts +28 -0
- package/dist/pdf/images.js +439 -0
- package/dist/pdf/objects.d.ts +93 -0
- package/dist/pdf/objects.js +237 -0
- package/dist/pdf/pageSpace.d.ts +43 -0
- package/dist/pdf/pageSpace.js +57 -0
- package/dist/pdf/paint.d.ts +32 -0
- package/dist/pdf/paint.js +442 -0
- package/dist/pdf/writePdf.d.ts +56 -0
- package/dist/pdf/writePdf.js +345 -0
- package/dist/prosemirror/commands/comments.js +91 -6
- package/dist/prosemirror/conversion/fromProseDoc.js +41 -7
- package/dist/prosemirror/conversion/toProseDoc.js +41 -4
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +15 -2
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +35 -6
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +2 -2
- package/dist/prosemirror/extensions/features/pasteCleanup.js +4 -3
- package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.d.ts +3 -1
- package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +5 -3
- package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.d.ts +7 -1
- package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.js +9 -3
- package/dist/prosemirror/extensions/nodes/TableExtension.js +56 -39
- package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.d.ts +3 -1
- package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.js +5 -3
- package/dist/prosemirror/plugins/suggestionMode.js +1 -0
- package/dist/prosemirror/revisionCarriers.js +19 -2
- package/dist/prosemirror/utils/extractTrackedChanges.d.ts +2 -2
- package/dist/prosemirror/utils/extractTrackedChanges.js +59 -23
- package/dist/prosemirror/validation.js +55 -27
- package/dist/prosemirror/zeroWidthAnchors.d.ts +10 -0
- package/dist/prosemirror/zeroWidthAnchors.js +23 -0
- package/dist/redline.js +12 -79
- package/dist/server.d.ts +3 -3
- package/dist/server.js +2 -2
- package/dist/shaping/placeRun.d.ts +51 -0
- package/dist/shaping/placeRun.js +84 -0
- package/dist/shaping/shaper.d.ts +92 -0
- package/dist/shaping/shaper.js +102 -0
- package/dist/types/block-id.d.ts +18 -2
- package/dist/types/block-id.js +49 -5
- package/dist/types/content.d.ts +2 -2
- package/dist/utils/clipboard.js +4 -3
- package/dist/utils/fontResolver.js +183 -0
- package/dist/utils/htmlComments.d.ts +17 -0
- package/dist/utils/htmlComments.js +22 -0
- package/dist/utils/scriptSegments.d.ts +12 -1
- package/dist/utils/scriptSegments.js +17 -1
- package/dist/version-comparison.d.ts +1 -1
- package/package.json +7 -3
package/dist/docx/xmlParser.js
CHANGED
|
@@ -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
|
-
|
|
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 };
|