@stll/folio-core 0.43.0 → 0.45.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.js +2 -2
- package/dist/ai-edits/headless.js +7 -5
- package/dist/ai-edits/index.d.ts +2 -2
- package/dist/ai-edits/index.js +2 -2
- package/dist/ai-edits/snapshot.js +13 -9
- package/dist/compare/content-alignment.js +94 -54
- package/dist/compare/inline-atoms.js +34 -20
- package/dist/compare/style-resources.js +6 -0
- package/dist/content-controls/mutateContentControls.js +4 -2
- package/dist/display-list/dom/renderDisplayListToDom.js +8 -8
- package/dist/document-operations.js +14 -3
- package/dist/docx/appVersionNormalization.d.ts +0 -18
- package/dist/docx/blockContentParser.js +8 -0
- package/dist/docx/blockRangeMarkers.d.ts +36 -0
- package/dist/docx/blockRangeMarkers.js +59 -0
- package/dist/docx/bookmarkParser.d.ts +2 -20
- package/dist/docx/bookmarkParser.js +6 -30
- package/dist/docx/borderParser.d.ts +13 -0
- package/dist/docx/borderParser.js +71 -0
- package/dist/docx/builtInStyles.d.ts +165 -0
- package/dist/docx/builtInStyles.js +239 -0
- package/dist/docx/commentIdNormalization.d.ts +3 -1
- package/dist/docx/commentIdNormalization.js +18 -1
- package/dist/docx/commentParser.d.ts +2 -1
- package/dist/docx/commentParser.js +80 -42
- package/dist/docx/commentReferenceNormalization.d.ts +4 -1
- package/dist/docx/commentReferenceNormalization.js +23 -14
- package/dist/docx/commentThreadKey.d.ts +18 -0
- package/dist/docx/commentThreadKey.js +22 -0
- package/dist/docx/danglingRelationshipReferences.d.ts +15 -0
- package/dist/docx/danglingRelationshipReferences.js +30 -0
- package/dist/docx/defaultParagraphStyle.d.ts +18 -1
- package/dist/docx/defaultParagraphStyle.js +23 -1
- package/dist/docx/diagramPreview.js +87 -27
- package/dist/docx/documentParser.d.ts +2 -1
- package/dist/docx/documentParser.js +2 -2
- package/dist/docx/drawingUtils.d.ts +8 -1
- package/dist/docx/drawingUtils.js +12 -3
- package/dist/docx/fieldParser.js +3 -5
- package/dist/docx/footnoteParser.d.ts +3 -2
- package/dist/docx/footnoteParser.js +19 -4
- package/dist/docx/groupDrawingParser.js +4 -4
- package/dist/docx/headerFooterRefParser.d.ts +4 -3
- package/dist/docx/headerFooterRefParser.js +42 -12
- package/dist/docx/headerFooterReferenceNormalization.d.ts +4 -1
- package/dist/docx/headerFooterReferenceNormalization.js +5 -1
- package/dist/docx/hyperlinkParser.js +13 -17
- package/dist/docx/imageParser.d.ts +10 -2
- package/dist/docx/imageParser.js +80 -30
- package/dist/docx/imageRawXml.d.ts +14 -1
- package/dist/docx/imageRawXml.js +35 -11
- package/dist/docx/markupRangeMarker.d.ts +15 -0
- package/dist/docx/markupRangeMarker.js +44 -0
- package/dist/docx/mathToMathml.js +12 -14
- package/dist/docx/nonVisualDrawingProps.d.ts +34 -0
- package/dist/docx/nonVisualDrawingProps.js +46 -0
- package/dist/docx/noteReferenceStyles.d.ts +29 -0
- package/dist/docx/noteReferenceStyles.js +70 -0
- package/dist/docx/numberingReferenceNormalization.d.ts +4 -1
- package/dist/docx/numberingReferenceNormalization.js +20 -1
- package/dist/docx/paraIdRangeNormalization.d.ts +0 -19
- package/dist/docx/paragraphParser.js +66 -99
- package/dist/docx/paragraphPropertySource.js +1 -0
- package/dist/docx/paragraphTextBoxEnrichment.js +3 -0
- package/dist/docx/paragraphTraversal.d.ts +37 -1
- package/dist/docx/paragraphTraversal.js +84 -1
- package/dist/docx/parseContext.d.ts +37 -0
- package/dist/docx/parseContext.js +67 -0
- package/dist/docx/parseWarningMessage.d.ts +6 -0
- package/dist/docx/parseWarningMessage.js +44 -0
- package/dist/docx/parser.js +83 -29
- package/dist/docx/previewBudget.d.ts +64 -0
- package/dist/docx/previewBudget.js +88 -0
- package/dist/docx/relsParser.d.ts +28 -11
- package/dist/docx/relsParser.js +26 -13
- package/dist/docx/revisionIdNormalization.js +96 -10
- package/dist/docx/rezip.js +80 -40
- package/dist/docx/runConsolidator.js +1 -2
- package/dist/docx/runParser.d.ts +8 -1
- package/dist/docx/runParser.js +30 -48
- package/dist/docx/sdtPropertiesPatch.js +24 -18
- package/dist/docx/sectionParser.d.ts +2 -1
- package/dist/docx/sectionParser.js +21 -65
- package/dist/docx/sectionReferenceHistory.js +2 -2
- package/dist/docx/selectiveSave.js +6 -6
- package/dist/docx/serializer/blockSdtSerializer.js +38 -26
- package/dist/docx/serializer/borderSerializer.d.ts +2 -3
- package/dist/docx/serializer/borderSerializer.js +13 -12
- package/dist/docx/serializer/commentSerializer.d.ts +41 -16
- package/dist/docx/serializer/commentSerializer.js +82 -72
- package/dist/docx/serializer/documentSerializer.d.ts +1 -5
- package/dist/docx/serializer/documentSerializer.js +6 -16
- package/dist/docx/serializer/fontTableSerializer.js +6 -6
- package/dist/docx/serializer/headerFooterSerializer.js +10 -5
- package/dist/docx/serializer/markupRangeAttributes.d.ts +8 -0
- package/dist/docx/serializer/markupRangeAttributes.js +24 -0
- package/dist/docx/serializer/noteSerializer.js +5 -0
- package/dist/docx/serializer/numberingSerializer.js +7 -6
- package/dist/docx/serializer/paragraphSerializer.d.ts +1 -5
- package/dist/docx/serializer/paragraphSerializer.js +47 -52
- package/dist/docx/serializer/partNamespaces.js +2 -2
- package/dist/docx/serializer/runSerializer.js +57 -31
- package/dist/docx/serializer/sectionPropertiesSerializer.js +11 -10
- package/dist/docx/serializer/settingsSerializer.js +4 -3
- package/dist/docx/serializer/stylesSerializer.js +6 -6
- package/dist/docx/serializer/tableSerializer.js +37 -21
- package/dist/docx/serializer/textFormattingSerializer.d.ts +2 -3
- package/dist/docx/serializer/textFormattingSerializer.js +29 -28
- package/dist/docx/serializer/themeSerializer.js +6 -6
- package/dist/docx/serializer/trackedChangeAttributes.js +2 -2
- package/dist/docx/serializer/xmlUtils.d.ts +1 -2
- package/dist/docx/serializer/xmlUtils.js +1 -13
- package/dist/docx/server/boundedArchive.d.ts +12 -0
- package/dist/docx/server/boundedArchive.js +20 -1
- package/dist/docx/server/build.js +8 -1
- package/dist/docx/server/createBilingualDocument.js +10 -18
- package/dist/docx/server/extractDocxText.js +3 -4
- package/dist/docx/server/validateDocxConformance.js +22 -1
- package/dist/docx/shadingParser.d.ts +6 -0
- package/dist/docx/shadingParser.js +32 -0
- package/dist/docx/shapeParser.js +10 -8
- package/dist/docx/styleParser.js +13 -87
- package/dist/docx/styleReferenceResolution.d.ts +36 -0
- package/dist/docx/styleReferenceResolution.js +51 -0
- package/dist/docx/tableLook.d.ts +57 -0
- package/dist/docx/tableLook.js +63 -0
- package/dist/docx/tableParser.d.ts +7 -9
- package/dist/docx/tableParser.js +64 -110
- package/dist/docx/textBoxParser.js +11 -6
- package/dist/docx/trackedMoveRangeNormalization.d.ts +3 -1
- package/dist/docx/trackedMoveRangeNormalization.js +11 -21
- package/dist/docx/transitionalSpelling.d.ts +13 -2
- package/dist/docx/transitionalSpelling.js +23 -1
- package/dist/docx/unzip.d.ts +23 -0
- package/dist/docx/unzip.js +32 -22
- package/dist/docx/verbatimCapture.js +5 -12
- package/dist/docx/vmlImageParser.js +5 -4
- package/dist/docx/vmlPreview.d.ts +1 -3
- package/dist/docx/vmlPreview.js +2 -30
- package/dist/docx/watermarkParser.js +2 -2
- package/dist/docx/xmlParser.d.ts +38 -33
- package/dist/docx/xmlParser.js +92 -47
- package/dist/docx/xmlResourceLimits.d.ts +89 -9
- package/dist/docx/xmlResourceLimits.js +105 -24
- package/dist/internal/pageBreakRunSourceDescendantIndex.js +2 -1
- package/dist/internal/paragraphFormattingSerialization.d.ts +2 -3
- package/dist/internal/paragraphFormattingSerialization.js +29 -8
- package/dist/layout-bridge/convert/footnoteLayout.js +2 -7
- package/dist/layout-engine/index.d.ts +2 -2
- package/dist/layout-engine/index.js +2 -2
- package/dist/layout-engine/measure/measureBlocks.js +1 -6
- package/dist/layout-engine/types.d.ts +8 -2
- package/dist/layout-engine/types.js +35 -2
- package/dist/layout-painter/renderImage.js +4 -3
- package/dist/layout-painter/renderParagraph.js +4 -3
- package/dist/managers/autoSaveCodec.js +2 -8
- package/dist/markdown/images.js +1 -4
- package/dist/markdown/index.js +1 -1
- package/dist/markdown/internals.d.ts +6 -1
- package/dist/markdown/internals.js +14 -1
- package/dist/markdown/renderBlock.js +35 -21
- package/dist/markdown/renderParagraph.js +14 -5
- package/dist/markdown/renderRuns.js +4 -3
- package/dist/markdown/renderTable.js +4 -3
- package/dist/markdown/trailers.js +41 -7
- package/dist/markdown/types.d.ts +3 -7
- package/dist/prosemirror/attrs/index.js +71 -5
- package/dist/prosemirror/bookmarkBoundaryAttrs.d.ts +11 -1
- package/dist/prosemirror/bookmarkBoundaryAttrs.js +18 -3
- package/dist/prosemirror/commands/image.js +1 -0
- package/dist/prosemirror/commands/index.d.ts +3 -3
- package/dist/prosemirror/commands/index.js +2 -2
- package/dist/prosemirror/commands/paragraph.d.ts +3 -3
- package/dist/prosemirror/commands/paragraph.js +2 -2
- package/dist/prosemirror/commentIdAllocator.js +2 -7
- package/dist/prosemirror/conversion/fromProseDoc.js +197 -68
- package/dist/prosemirror/conversion/toProseDoc.d.ts +1 -14
- package/dist/prosemirror/conversion/toProseDoc.js +458 -335
- package/dist/prosemirror/extensions/core/ParagraphExtension.d.ts +14 -1
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +11 -6
- package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +3 -3
- package/dist/prosemirror/extensions/features/PasteCleanupExtension.d.ts +4 -1
- package/dist/prosemirror/extensions/features/PasteCleanupExtension.js +6 -2
- package/dist/prosemirror/extensions/features/pastedHeadingStyles.d.ts +7 -0
- package/dist/prosemirror/extensions/features/pastedHeadingStyles.js +74 -0
- package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +2 -3
- package/dist/prosemirror/extensions/marks/markUtils.d.ts +11 -3
- package/dist/prosemirror/extensions/marks/markUtils.js +98 -19
- package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +7 -3
- package/dist/prosemirror/extensions/nodes/ImageExtension.js +6 -1
- package/dist/prosemirror/extensions/nodes/ShapeExtension.js +8 -2
- package/dist/prosemirror/extensions/nodes/TableExtension.js +15 -1
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +8 -4
- package/dist/prosemirror/extensions/types.d.ts +2 -2
- package/dist/prosemirror/index.d.ts +3 -3
- package/dist/prosemirror/index.js +3 -3
- package/dist/prosemirror/insertOperations.d.ts +9 -2
- package/dist/prosemirror/insertOperations.js +9 -4
- package/dist/prosemirror/paragraphFormattingProvenance.d.ts +162 -0
- package/dist/prosemirror/paragraphFormattingProvenance.js +115 -0
- package/dist/prosemirror/plugins/documentStyles.d.ts +9 -1
- package/dist/prosemirror/plugins/documentStyles.js +11 -1
- package/dist/prosemirror/plugins/index.d.ts +2 -2
- package/dist/prosemirror/plugins/index.js +2 -2
- package/dist/prosemirror/plugins/revisionIds.d.ts +11 -2
- package/dist/prosemirror/plugins/revisionIds.js +21 -6
- package/dist/prosemirror/runFormattingReconciliation.js +3 -2
- package/dist/prosemirror/runStyleFormatting.d.ts +1 -1
- package/dist/prosemirror/schema/nodes.d.ts +81 -1
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +2 -0
- package/dist/prosemirror/styles/styleResolver.d.ts +9 -0
- package/dist/prosemirror/styles/styleResolver.js +12 -0
- package/dist/style-engine/styleEngine.d.ts +3 -0
- package/dist/style-engine/styleEngine.js +3 -0
- package/dist/style-sets/extract.js +1 -23
- package/dist/style-sets/stellaStyle.js +46 -39
- package/dist/style-sets/styleSetNormalization.d.ts +19 -0
- package/dist/style-sets/styleSetNormalization.js +99 -0
- package/dist/types/content.d.ts +2 -2
- package/dist/utils/base64.d.ts +36 -0
- package/dist/utils/base64.js +40 -0
- package/dist/utils/clipboard.js +2 -1
- package/dist/utils/createDocument.js +145 -20
- package/dist/utils/headingCollector.d.ts +8 -5
- package/dist/utils/headingCollector.js +23 -25
- package/dist/utils/tableOfContentsStyle.js +9 -2
- package/dist/utils/units.d.ts +10 -1
- package/dist/utils/units.js +12 -1
- package/dist/utils/urlSecurity.d.ts +8 -2
- package/dist/utils/urlSecurity.js +21 -3
- package/package.json +2 -2
- package/dist/docx/textWhitespace.d.ts +0 -4
- package/dist/docx/textWhitespace.js +0 -4
- package/dist/layout-bridge/engine/tableWidthUtils.d.ts +0 -6
- package/dist/layout-bridge/engine/tableWidthUtils.js +0 -25
- package/dist/markdown/headings.d.ts +0 -13
- package/dist/markdown/headings.js +0 -20
|
@@ -1,12 +1,60 @@
|
|
|
1
1
|
import { TaggedError } from "better-result";
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* Shared bounds for XML parts parsed by Folio.
|
|
4
|
+
*
|
|
5
|
+
* `maxBytes` and the package expansion ceiling bound the *markup*; they do not
|
|
6
|
+
* bound what parsing that markup allocates. A parsed element retains far more
|
|
7
|
+
* than the bytes it was written as, so a part that satisfies a byte bound can
|
|
8
|
+
* still cost multiples of it in tree. Measured on this repository's corpus
|
|
9
|
+
* generators (Bun 1.4, arm64, heap retained after a forced GC):
|
|
10
|
+
*
|
|
11
|
+
* shape bytes/element tree heap / part bytes
|
|
12
|
+
* `<w:r/>` 49.5 B 8.3x
|
|
13
|
+
* `<w:r a=".." x4/>` 105-124 B 2.8-3.3x
|
|
14
|
+
* `<w:r><w:t>x</w:t></w:r>` 162-171 B 14.1-14.8x
|
|
15
|
+
*
|
|
16
|
+
* An element is therefore the unit a memory bound has to count, because the
|
|
17
|
+
* adversarial shape is the cheap one: `<w:r/>` is 7 bytes of markup and 49.5
|
|
18
|
+
* bytes of tree, so 128 MiB of markup buys ~19M elements and ~950 MB of tree
|
|
19
|
+
* inside a byte budget that never trips.
|
|
20
|
+
*
|
|
21
|
+
* Corpus distribution (5,314 readable packages, every XML and .rels part):
|
|
22
|
+
*
|
|
23
|
+
* metric p50 p90 p99 p99.9 max
|
|
24
|
+
* elements / part 16 227 1,590 24,719 596,668
|
|
25
|
+
* elements / package 917 3,230 29,106 71,975 602,212
|
|
26
|
+
* attributes / part 27 577 1,993 21,037 630,374
|
|
27
|
+
* attributes / package 1,783 4,711 25,896 91,946 639,110
|
|
28
|
+
* depth / part 3 9 15 22 15,005
|
|
29
|
+
* elements per byte 0.012 0.027 0.036 0.043 0.111
|
|
30
|
+
*
|
|
31
|
+
* The defaults below reject no corpus package that today's bounds accept. The
|
|
32
|
+
* package budget is the one that matters: it caps a whole package at ~2.5M
|
|
33
|
+
* elements and ~3M attributes, which is at most ~425 MB of tree at the densest
|
|
34
|
+
* measured shape and ~124 MB at the cheapest. Before it existed, only
|
|
35
|
+
* `word/document.xml`, `word/styles.xml` and `word/numbering.xml` were counted
|
|
36
|
+
* at all, so a package of many merely-large parts could reach the expansion
|
|
37
|
+
* ceiling of 250 MiB, ~37M elements and well past 1.8 GB of tree while passing
|
|
38
|
+
* every bound. Lower these to trade format reach for a smaller ceiling.
|
|
39
|
+
*/
|
|
3
40
|
const FOLIO_XML_RESOURCE_LIMITS = {
|
|
4
41
|
maxBytes: 128 * (1024 * 1024),
|
|
5
42
|
maxDepth: 100,
|
|
6
|
-
|
|
43
|
+
/** 1.68x the corpus maximum (596,668). Unchanged; a shipped bound is not loosened. */
|
|
44
|
+
maxElementsPerPart: 1e6,
|
|
45
|
+
/** 3.97x the corpus maximum (630,374). */
|
|
46
|
+
maxAttributesPerPart: 25e5,
|
|
47
|
+
/** 4.15x the corpus maximum (602,212). */
|
|
48
|
+
maxElementsPerPackage: 25e5,
|
|
49
|
+
/** 4.69x the corpus maximum (639,110). */
|
|
50
|
+
maxAttributesPerPackage: 3e6
|
|
7
51
|
};
|
|
8
52
|
/** XML input exceeded a parser resource bound or could not be scanned safely. */
|
|
9
53
|
var XmlResourceLimitError = class extends TaggedError("XmlResourceLimitError") {};
|
|
54
|
+
const createXmlPackageBudget = () => ({
|
|
55
|
+
elements: 0,
|
|
56
|
+
attributes: 0
|
|
57
|
+
});
|
|
10
58
|
const exceedsUtf8ByteLimit = (value, maxBytes) => {
|
|
11
59
|
let bytes = 0;
|
|
12
60
|
for (let index = 0; index < value.length; index += 1) {
|
|
@@ -22,8 +70,9 @@ const exceedsUtf8ByteLimit = (value, maxBytes) => {
|
|
|
22
70
|
return false;
|
|
23
71
|
};
|
|
24
72
|
const isXmlWhitespace = (code) => code === 9 || code === 10 || code === 13 || code === 32;
|
|
25
|
-
const
|
|
73
|
+
const scanTag = (xml, start) => {
|
|
26
74
|
let quote = 0;
|
|
75
|
+
let attributes = 0;
|
|
27
76
|
for (let cursor = start; cursor < xml.length; cursor += 1) {
|
|
28
77
|
const code = xml.charCodeAt(cursor);
|
|
29
78
|
if (quote !== 0) {
|
|
@@ -34,29 +83,53 @@ const findTagClose = (xml, start) => {
|
|
|
34
83
|
quote = code;
|
|
35
84
|
continue;
|
|
36
85
|
}
|
|
37
|
-
if (code ===
|
|
86
|
+
if (code === 61) {
|
|
87
|
+
attributes += 1;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (code === 62) return {
|
|
91
|
+
close: cursor,
|
|
92
|
+
attributes
|
|
93
|
+
};
|
|
38
94
|
}
|
|
39
|
-
return
|
|
95
|
+
return {
|
|
96
|
+
close: -1,
|
|
97
|
+
attributes
|
|
98
|
+
};
|
|
40
99
|
};
|
|
41
100
|
const throwSyntaxLimit = () => {
|
|
42
101
|
throw new XmlResourceLimitError({
|
|
43
102
|
message: "XML resource preflight could not safely scan malformed markup",
|
|
44
|
-
limit: "syntax"
|
|
103
|
+
limit: "syntax",
|
|
104
|
+
observed: 0,
|
|
105
|
+
allowed: 0
|
|
45
106
|
});
|
|
46
107
|
};
|
|
47
108
|
/**
|
|
48
|
-
* Bound XML bytes, element count, and nesting before building
|
|
49
|
-
* The lexical scan is iterative, so deeply nested input cannot
|
|
50
|
-
* call stack before the depth limit is enforced
|
|
109
|
+
* Bound XML bytes, element count, attribute count and nesting before building
|
|
110
|
+
* an object tree. The lexical scan is iterative, so deeply nested input cannot
|
|
111
|
+
* consume the JS call stack before the depth limit is enforced, and every
|
|
112
|
+
* bound is checked at the point it is crossed, so the work done before a
|
|
113
|
+
* refusal is proportional to the limit rather than to the input.
|
|
51
114
|
*/
|
|
52
|
-
const assertXmlResourceLimits = (xml, limits = FOLIO_XML_RESOURCE_LIMITS) => {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
115
|
+
const assertXmlResourceLimits = ({ xml, limits = FOLIO_XML_RESOURCE_LIMITS, partPath, budget }) => {
|
|
116
|
+
const refuse = (limit, message, observed, allowed) => {
|
|
117
|
+
throw new XmlResourceLimitError({
|
|
118
|
+
message: partPath === void 0 ? message : `${message} (part ${partPath})`,
|
|
119
|
+
limit,
|
|
120
|
+
...partPath === void 0 ? {} : { partPath },
|
|
121
|
+
observed,
|
|
122
|
+
allowed
|
|
123
|
+
});
|
|
124
|
+
};
|
|
125
|
+
if (exceedsUtf8ByteLimit(xml, limits.maxBytes)) refuse("bytes", `XML part exceeds ${String(limits.maxBytes)} bytes`, limits.maxBytes + 1, limits.maxBytes);
|
|
126
|
+
const budgetElements = budget?.elements ?? 0;
|
|
127
|
+
const budgetAttributes = budget?.attributes ?? 0;
|
|
57
128
|
let cursor = 0;
|
|
58
129
|
let depth = 0;
|
|
130
|
+
let maxDepth = 0;
|
|
59
131
|
let nodes = 0;
|
|
132
|
+
let attributes = 0;
|
|
60
133
|
while (cursor < xml.length) {
|
|
61
134
|
const open = xml.indexOf("<", cursor);
|
|
62
135
|
if (open === -1) break;
|
|
@@ -79,7 +152,7 @@ const assertXmlResourceLimits = (xml, limits = FOLIO_XML_RESOURCE_LIMITS) => {
|
|
|
79
152
|
continue;
|
|
80
153
|
}
|
|
81
154
|
if (xml.startsWith("<!", open)) throwSyntaxLimit();
|
|
82
|
-
const close =
|
|
155
|
+
const { close, attributes: tagAttributes } = scanTag(xml, open + 1);
|
|
83
156
|
if (close === -1) throwSyntaxLimit();
|
|
84
157
|
if (xml.charCodeAt(open + 1) === 47) {
|
|
85
158
|
if (depth === 0) throwSyntaxLimit();
|
|
@@ -88,21 +161,29 @@ const assertXmlResourceLimits = (xml, limits = FOLIO_XML_RESOURCE_LIMITS) => {
|
|
|
88
161
|
continue;
|
|
89
162
|
}
|
|
90
163
|
nodes += 1;
|
|
91
|
-
if (nodes > limits.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
});
|
|
164
|
+
if (nodes > limits.maxElementsPerPart) refuse("elements", `XML part contains more than ${String(limits.maxElementsPerPart)} elements`, nodes, limits.maxElementsPerPart);
|
|
165
|
+
if (budgetElements + nodes > limits.maxElementsPerPackage) refuse("package-elements", `DOCX package contains more than ${String(limits.maxElementsPerPackage)} XML elements`, budgetElements + nodes, limits.maxElementsPerPackage);
|
|
166
|
+
attributes += tagAttributes;
|
|
167
|
+
if (attributes > limits.maxAttributesPerPart) refuse("attributes", `XML part contains more than ${String(limits.maxAttributesPerPart)} attributes`, attributes, limits.maxAttributesPerPart);
|
|
168
|
+
if (budgetAttributes + attributes > limits.maxAttributesPerPackage) refuse("package-attributes", `DOCX package contains more than ${String(limits.maxAttributesPerPackage)} XML attributes`, budgetAttributes + attributes, limits.maxAttributesPerPackage);
|
|
95
169
|
let lastContent = close - 1;
|
|
96
170
|
while (lastContent > open && isXmlWhitespace(xml.charCodeAt(lastContent))) lastContent -= 1;
|
|
97
171
|
const elementDepth = depth + 1;
|
|
98
|
-
if (elementDepth > limits.maxDepth)
|
|
99
|
-
|
|
100
|
-
limit: "depth"
|
|
101
|
-
});
|
|
172
|
+
if (elementDepth > limits.maxDepth) refuse("depth", `XML part is nested deeper than ${String(limits.maxDepth)} elements`, elementDepth, limits.maxDepth);
|
|
173
|
+
if (elementDepth > maxDepth) maxDepth = elementDepth;
|
|
102
174
|
if (xml.charCodeAt(lastContent) !== 47) depth = elementDepth;
|
|
103
175
|
cursor = close + 1;
|
|
104
176
|
}
|
|
105
177
|
if (depth !== 0) throwSyntaxLimit();
|
|
178
|
+
if (budget) {
|
|
179
|
+
budget.elements += nodes;
|
|
180
|
+
budget.attributes += attributes;
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
elements: nodes,
|
|
184
|
+
attributes,
|
|
185
|
+
maxDepth
|
|
186
|
+
};
|
|
106
187
|
};
|
|
107
188
|
//#endregion
|
|
108
|
-
export { FOLIO_XML_RESOURCE_LIMITS, XmlResourceLimitError, assertXmlResourceLimits };
|
|
189
|
+
export { FOLIO_XML_RESOURCE_LIMITS, XmlResourceLimitError, assertXmlResourceLimits, createXmlPackageBudget };
|
|
@@ -59,7 +59,8 @@ const buildPageBreakRunSourceDescendantIndex = (rootContent) => {
|
|
|
59
59
|
case "deletion":
|
|
60
60
|
case "moveFrom":
|
|
61
61
|
case "moveTo":
|
|
62
|
-
case "inlineSdt":
|
|
62
|
+
case "inlineSdt":
|
|
63
|
+
case "bidiWrapper": return inspectMany(content.content, inspectParagraphContent);
|
|
63
64
|
case "simpleField": {
|
|
64
65
|
const fieldResultFlags = inspectMany(content.content, inspectParagraphContent);
|
|
65
66
|
if (hasFlag(fieldResultFlags, SOURCE_FLAGS.paragraphPageBreak) && hasFlag(fieldResultFlags, SOURCE_FLAGS.paragraphTextBoxShape)) return fieldResultFlags | SOURCE_FLAGS.pageBreakSharesTextBoxShape;
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { document_d_exports } from "../types/document.js";
|
|
2
2
|
//#region src/internal/paragraphFormattingSerialization.d.ts
|
|
3
|
-
type ExhaustiveFields<Source, Classified extends keyof Source> = Exclude<keyof Source, Classified> extends never ? Source : never;
|
|
4
3
|
type ParagraphNumberingReference = document_d_exports.ParagraphFormatting["numPr"] | null;
|
|
5
|
-
type ClassifiedParagraphFormattingField = "alignment" | "bidi" | "kinsoku" | "overflowPunctuation" | "spaceBefore" | "spaceAfter" | "lineSpacing" | "lineSpacingRule" | "snapToGrid" | "beforeAutospacing" | "afterAutospacing" | "spacingExplicit" | "indentLeft" | "indentRight" | "indentFirstLine" | "hangingIndent" | "borders" | "shading" | "tabs" | "keepNext" | "keepLines" | "widowControl" | "pageBreakBefore" | "contextualSpacing" | "numPr" | "numPrFromStyle" | "outlineLevel" | "styleId" | "frame" | "suppressLineNumbers" | "suppressAutoHyphens" | "runProperties" | "runInWithNext";
|
|
6
|
-
type ExhaustiveParagraphFormatting = ExhaustiveFields<document_d_exports.ParagraphFormatting, ClassifiedParagraphFormattingField>;
|
|
4
|
+
type ClassifiedParagraphFormattingField = "alignment" | "bidi" | "kinsoku" | "overflowPunctuation" | "spaceBefore" | "spaceAfter" | "lineSpacing" | "lineSpacingRule" | "snapToGrid" | "beforeAutospacing" | "afterAutospacing" | "spacingExplicit" | "indentLeft" | "indentRight" | "indentFirstLine" | "hangingIndent" | "borders" | "shading" | "tabs" | "keepNext" | "keepLines" | "widowControl" | "pageBreakBefore" | "contextualSpacing" | "numPr" | "numPrFromStyle" | "numberingChangeXml" | "outlineLevel" | "styleId" | "frame" | "suppressLineNumbers" | "suppressAutoHyphens" | "runProperties" | "runInWithNext";
|
|
5
|
+
type ExhaustiveParagraphFormatting = document_d_exports.ExhaustiveFields<document_d_exports.ParagraphFormatting, ClassifiedParagraphFormattingField>;
|
|
7
6
|
/** Compare numbering references by their emitted id and effective level. */
|
|
8
7
|
declare const paragraphNumberingReferencesEqual: (left: ParagraphNumberingReference, right: ParagraphNumberingReference) => boolean;
|
|
9
8
|
/** Compare the authored `w:numPr` attributes, including an absent `w:ilvl`. */
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { serializeBorder } from "../docx/serializer/borderSerializer.js";
|
|
2
2
|
import { serializeShading, serializeTextFormatting } from "../docx/serializer/textFormattingSerializer.js";
|
|
3
|
-
import {
|
|
3
|
+
import { intAttr } from "../docx/serializer/xmlUtils.js";
|
|
4
|
+
import { sanitizeCapturedXmlElement } from "../docx/verbatimCapture.js";
|
|
5
|
+
import { NAMESPACES, OOXML_NAMESPACE_SCOPE } from "../docx/xmlParser.js";
|
|
6
|
+
import { escapeXmlAttribute } from "@stll/docx-core";
|
|
4
7
|
//#region src/internal/paragraphFormattingSerialization.ts
|
|
5
8
|
const modelParagraphNumberingReference = (reference) => {
|
|
6
9
|
if (!reference) return null;
|
|
@@ -74,14 +77,32 @@ const serializeIndentation = (formatting) => {
|
|
|
74
77
|
}
|
|
75
78
|
return attrs.length === 0 ? "" : `<w:ind ${attrs.join(" ")}/>`;
|
|
76
79
|
};
|
|
77
|
-
|
|
80
|
+
/**
|
|
81
|
+
* `w:numPr`, with the tracked record of the numbering it replaced.
|
|
82
|
+
*
|
|
83
|
+
* `w:numberingChange` is the revision a reviewer's numbering change left
|
|
84
|
+
* behind. It is history: nothing in the model derives it, and a rebuilt
|
|
85
|
+
* `w:numPr` that drops it discards the revision silently. It is written even
|
|
86
|
+
* when the paragraph's own numbering reference is gone, because a change
|
|
87
|
+
* record with nothing left to describe is still a record — the schema declares
|
|
88
|
+
* it last in `CT_NumPr`, after `w:ilvl` and `w:numId`.
|
|
89
|
+
*/
|
|
90
|
+
const serializeNumbering = (numPr, numberingChangeXml) => {
|
|
78
91
|
const modeled = modelParagraphNumberingReference(numPr ?? null);
|
|
79
|
-
if (!modeled) return "";
|
|
80
92
|
const parts = [];
|
|
81
|
-
if (modeled
|
|
82
|
-
if (modeled
|
|
93
|
+
if (modeled?.ilvl !== void 0) parts.push(`<w:ilvl w:val="${intAttr(modeled.ilvl)}"/>`);
|
|
94
|
+
if (modeled?.numId !== void 0) parts.push(`<w:numId w:val="${intAttr(modeled.numId)}"/>`);
|
|
95
|
+
const change = replayableNumberingChangeXml(numberingChangeXml);
|
|
96
|
+
if (change !== null) parts.push(change);
|
|
83
97
|
return parts.length === 0 ? "" : `<w:numPr>${parts.join("")}</w:numPr>`;
|
|
84
98
|
};
|
|
99
|
+
const NUMBERING_CHANGE_ROOT_NAME = /* @__PURE__ */ new Set(["numberingChange"]);
|
|
100
|
+
const WORDPROCESSINGML_NAMESPACE = /* @__PURE__ */ new Set([NAMESPACES.w]);
|
|
101
|
+
const replayableNumberingChangeXml = (numberingChangeXml) => sanitizeCapturedXmlElement(numberingChangeXml, {
|
|
102
|
+
allowedLocalNames: NUMBERING_CHANGE_ROOT_NAME,
|
|
103
|
+
allowedNamespaceUris: WORDPROCESSINGML_NAMESPACE,
|
|
104
|
+
inheritedNamespaceScope: OOXML_NAMESPACE_SCOPE
|
|
105
|
+
});
|
|
85
106
|
const serializeFrameProperties = (frame) => {
|
|
86
107
|
if (!frame) return "";
|
|
87
108
|
const { dropCap, lines, width, height, hSpace, vSpace, hAnchor, vAnchor, x, y, xAlign, yAlign, wrap } = frame;
|
|
@@ -117,16 +138,16 @@ const extractRunPropertiesInnerXml = (runPropertiesXml) => {
|
|
|
117
138
|
*/
|
|
118
139
|
const modelParagraphFormattingEmission = (input) => {
|
|
119
140
|
if (!input) return {};
|
|
120
|
-
const { alignment, bidi, kinsoku, overflowPunctuation, spaceBefore, spaceAfter, lineSpacing, lineSpacingRule, snapToGrid, beforeAutospacing, afterAutospacing, spacingExplicit, indentLeft, indentRight, indentFirstLine, hangingIndent, borders, shading, tabs, keepNext, keepLines, widowControl, pageBreakBefore, contextualSpacing, numPr, numPrFromStyle, outlineLevel, styleId, frame, suppressLineNumbers, suppressAutoHyphens, runProperties, runInWithNext } = input;
|
|
141
|
+
const { alignment, bidi, kinsoku, overflowPunctuation, spaceBefore, spaceAfter, lineSpacing, lineSpacingRule, snapToGrid, beforeAutospacing, afterAutospacing, spacingExplicit, indentLeft, indentRight, indentFirstLine, hangingIndent, borders, shading, tabs, keepNext, keepLines, widowControl, pageBreakBefore, contextualSpacing, numPr, numPrFromStyle, numberingChangeXml, outlineLevel, styleId, frame, suppressLineNumbers, suppressAutoHyphens, runProperties, runInWithNext } = input;
|
|
121
142
|
modelSpacingProvenance(spacingExplicit);
|
|
122
143
|
const propertiesXml = [
|
|
123
|
-
styleId ? `<w:pStyle w:val="${
|
|
144
|
+
styleId ? `<w:pStyle w:val="${escapeXmlAttribute(styleId)}"/>` : "",
|
|
124
145
|
serializeToggle("keepNext", keepNext),
|
|
125
146
|
serializeToggle("keepLines", keepLines),
|
|
126
147
|
serializeToggle("pageBreakBefore", pageBreakBefore),
|
|
127
148
|
serializeFrameProperties(frame),
|
|
128
149
|
serializeToggle("widowControl", widowControl),
|
|
129
|
-
isStyleSourcedParagraphNumbering(numPr, numPrFromStyle) ?
|
|
150
|
+
isStyleSourcedParagraphNumbering(numPr, numPrFromStyle) ? serializeNumbering(void 0, numberingChangeXml) : serializeNumbering(numPr, numberingChangeXml),
|
|
130
151
|
serializeToggle("suppressLineNumbers", suppressLineNumbers),
|
|
131
152
|
serializeParagraphBorders(borders),
|
|
132
153
|
serializeShading(shading),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { measureParagraph } from "../../layout-engine/measure/measureParagraph.js";
|
|
2
2
|
import { layoutTextBoxContent } from "../../layout-engine/measure/textBoxParagraphLayout.js";
|
|
3
|
-
import { DEFAULT_TEXTBOX_MARGINS, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, isFloatingImageRun } from "../../layout-engine/types.js";
|
|
3
|
+
import { DEFAULT_TEXTBOX_MARGINS, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, isFloatingImageRun, resolveTableWidthPx } from "../../layout-engine/types.js";
|
|
4
4
|
import { footnoteToProseDoc } from "../../prosemirror/conversion/toProseDoc.js";
|
|
5
5
|
import { toFlowBlocks } from "./toFlowBlocks.js";
|
|
6
6
|
//#region src/layout-bridge/convert/footnoteLayout.ts
|
|
@@ -264,14 +264,9 @@ function measureFootnoteBlock(block, contentWidth) {
|
|
|
264
264
|
default: return block;
|
|
265
265
|
}
|
|
266
266
|
}
|
|
267
|
-
function resolveFootnoteTableWidth(width, widthType, contentWidth) {
|
|
268
|
-
if (!width) return;
|
|
269
|
-
if (widthType === "pct") return contentWidth * width / 5e3;
|
|
270
|
-
if (widthType === "dxa" || !widthType || widthType === "auto") return width / 1440 * 96;
|
|
271
|
-
}
|
|
272
267
|
function measureFootnoteTable(tableBlock, contentWidth) {
|
|
273
268
|
let columnWidths = tableBlock.columnWidths ?? [];
|
|
274
|
-
const explicitWidth =
|
|
269
|
+
const explicitWidth = resolveTableWidthPx(tableBlock.width, tableBlock.widthType, contentWidth);
|
|
275
270
|
if (columnWidths.length === 0) {
|
|
276
271
|
const firstRow = tableBlock.rows.at(0);
|
|
277
272
|
let colCount = 0;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BlockId, BorderStyle, CellBorderSpec, CellBorders, ColumnBreakBlock, ColumnBreakMeasure, ColumnLayout, DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, DocumentPosition, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, FieldRun, FloatingTablePosition, FlowBlock, FootnoteContent, Fragment, FragmentBase, HeaderFooterContent, HeaderFooterContentHeights, HeaderFooterLayout, HitTestResult, HyperlinkInfo, ImageBlock, ImageFragment, ImageMeasure, ImageRun, ImageRunPosition, Layout, LayoutOptions, LineBreakRun, ListMarkerFormatting, ListNumPr, MathRun, Measure, MeasuredLine, Page, PageBreakBlock, PageBreakMeasure, PageHeaderFooterRefs, PageMargins, ParagraphAttrs, ParagraphBlock, ParagraphBorders, ParagraphFragment, ParagraphIndent, ParagraphMeasure, ParagraphSpacing, RenderedPageBreakRun, Run, RunFormatting, SdtGroup, SectionBreakBlock, SectionBreakMeasure, SectionPageNumbering, TabAlignment, TabRun, TabStop, TableBlock, TableCell, TableCellMeasure, TableFragment, TableMeasure, TableRow, TableRowMeasure, TextBoxBlock, TextBoxFlowAttrs, TextBoxFragment, TextBoxMeasure, TextRun, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, resolveTableCellPadding, tableColumnsArePinned } from "./types.js";
|
|
1
|
+
import { BlockId, BorderStyle, CellBorderSpec, CellBorders, ColumnBreakBlock, ColumnBreakMeasure, ColumnLayout, DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, DocumentPosition, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, FieldRun, FloatingTablePosition, FlowBlock, FootnoteContent, Fragment, FragmentBase, HeaderFooterContent, HeaderFooterContentHeights, HeaderFooterLayout, HitTestResult, HyperlinkInfo, ImageBlock, ImageFragment, ImageMeasure, ImageRun, ImageRunPosition, Layout, LayoutOptions, LineBreakRun, ListMarkerFormatting, ListNumPr, MathRun, Measure, MeasuredLine, Page, PageBreakBlock, PageBreakMeasure, PageHeaderFooterRefs, PageMargins, ParagraphAttrs, ParagraphBlock, ParagraphBorders, ParagraphFragment, ParagraphIndent, ParagraphMeasure, ParagraphSpacing, RenderedPageBreakRun, Run, RunFormatting, SdtGroup, SectionBreakBlock, SectionBreakMeasure, SectionPageNumbering, TabAlignment, TabRun, TabStop, TableBlock, TableCell, TableCellMeasure, TableFragment, TableMeasure, TableRow, TableRowMeasure, TextBoxBlock, TextBoxFlowAttrs, TextBoxFragment, TextBoxMeasure, TextRun, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, resolveTableCellPadding, resolveTableWidthPx, tableColumnsArePinned } from "./types.js";
|
|
2
2
|
import { PageState, Paginator, PaginatorOptions, createPaginator } from "./paginator.js";
|
|
3
3
|
import { KeepNextChain, calculateChainHeight, computeKeepNextChains, getMidChainIndices, hasKeepLines, hasPageBreakBefore } from "./keep-together.js";
|
|
4
4
|
import { resolveSectionHeaderFooterRefs } from "./headerFooterRefs.js";
|
|
@@ -42,4 +42,4 @@ declare function layoutDocument(blocks: FlowBlock[], measures: Measure[], option
|
|
|
42
42
|
*/
|
|
43
43
|
declare function getHeaderRowsHeight(measure: TableMeasure, headerRowCount: number): number;
|
|
44
44
|
//#endregion
|
|
45
|
-
export { BlockId, BorderStyle, type BreakDecision, CellBorderSpec, CellBorders, ColumnBreakBlock, ColumnBreakMeasure, ColumnLayout, DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, DocumentPosition, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, FieldRun, FloatingTablePosition, FlowBlock, FootnoteContent, Fragment, FragmentBase, HeaderFooterContent, HeaderFooterContentHeights, HeaderFooterLayout, HitTestResult, HyperlinkInfo, ImageBlock, ImageFragment, ImageMeasure, ImageRun, ImageRunPosition, type KeepNextChain, Layout, LayoutOptions, LineBreakRun, ListMarkerFormatting, ListNumPr, MathRun, Measure, MeasuredLine, Page, PageBreakBlock, PageBreakMeasure, PageHeaderFooterRefs, PageMargins, type PageState, type Paginator, type PaginatorOptions, ParagraphAttrs, ParagraphBlock, ParagraphBorders, ParagraphFragment, ParagraphIndent, ParagraphMeasure, ParagraphSpacing, RenderedPageBreakRun, Run, RunFormatting, SdtGroup, SectionBreakBlock, SectionBreakMeasure, SectionLayoutConfig, SectionPageNumbering, type SectionState, TabAlignment, TabRun, TabStop, TableBlock, TableCell, TableCellMeasure, TableFragment, TableMeasure, TableRow, TableRowMeasure, TextBoxBlock, TextBoxFlowAttrs, TextBoxFragment, TextBoxMeasure, TextRun, applyContextualSpacing, applyPendingToActive, assertExhaustiveFlowBlock, calculateChainHeight, collectSectionConfigs, computeKeepNextChains, createInitialSectionState, createPaginator, findPageIndexContainingPmPos, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getEffectiveColumns, getEffectiveMargins, getEffectivePageSize, getHeaderRowsHeight, getMidChainIndices, getTableRowLeadingWidth, hasKeepLines, hasPageBreakBefore, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, layoutDocument, resolveSectionHeaderFooterRefs, resolveTableCellPadding, scheduleSectionBreak, tableColumnsArePinned };
|
|
45
|
+
export { BlockId, BorderStyle, type BreakDecision, CellBorderSpec, CellBorders, ColumnBreakBlock, ColumnBreakMeasure, ColumnLayout, DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, DocumentPosition, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, FieldRun, FloatingTablePosition, FlowBlock, FootnoteContent, Fragment, FragmentBase, HeaderFooterContent, HeaderFooterContentHeights, HeaderFooterLayout, HitTestResult, HyperlinkInfo, ImageBlock, ImageFragment, ImageMeasure, ImageRun, ImageRunPosition, type KeepNextChain, Layout, LayoutOptions, LineBreakRun, ListMarkerFormatting, ListNumPr, MathRun, Measure, MeasuredLine, Page, PageBreakBlock, PageBreakMeasure, PageHeaderFooterRefs, PageMargins, type PageState, type Paginator, type PaginatorOptions, ParagraphAttrs, ParagraphBlock, ParagraphBorders, ParagraphFragment, ParagraphIndent, ParagraphMeasure, ParagraphSpacing, RenderedPageBreakRun, Run, RunFormatting, SdtGroup, SectionBreakBlock, SectionBreakMeasure, SectionLayoutConfig, SectionPageNumbering, type SectionState, TabAlignment, TabRun, TabStop, TableBlock, TableCell, TableCellMeasure, TableFragment, TableMeasure, TableRow, TableRowMeasure, TextBoxBlock, TextBoxFlowAttrs, TextBoxFragment, TextBoxMeasure, TextRun, applyContextualSpacing, applyPendingToActive, assertExhaustiveFlowBlock, calculateChainHeight, collectSectionConfigs, computeKeepNextChains, createInitialSectionState, createPaginator, findPageIndexContainingPmPos, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getEffectiveColumns, getEffectiveMargins, getEffectivePageSize, getHeaderRowsHeight, getMidChainIndices, getTableRowLeadingWidth, hasKeepLines, hasPageBreakBefore, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, layoutDocument, resolveSectionHeaderFooterRefs, resolveTableCellPadding, resolveTableWidthPx, scheduleSectionBreak, tableColumnsArePinned };
|
|
@@ -14,7 +14,7 @@ import { applyPendingToActive, createInitialSectionState, getEffectiveColumns, g
|
|
|
14
14
|
import { applySectionVerticalAlignment } from "./sectionVerticalAlignment.js";
|
|
15
15
|
import { buildTableRowBreakInfo, getRowContinuationSkip, snapRowBreak } from "./tableRowBreak.js";
|
|
16
16
|
import { bandFragmentX, bandTopContentY, isPageFrameRelativeAnchor } from "./textBoxFlow.js";
|
|
17
|
-
import { DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, resolveTableCellPadding, tableColumnsArePinned } from "./types.js";
|
|
17
|
+
import { DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, resolveTableCellPadding, resolveTableWidthPx, tableColumnsArePinned } from "./types.js";
|
|
18
18
|
import { panic } from "better-result";
|
|
19
19
|
//#region src/layout-engine/index.ts
|
|
20
20
|
/**
|
|
@@ -1036,4 +1036,4 @@ function handleSectionBreak(_block, paginator, nextSectionConfig, nextSectionTyp
|
|
|
1036
1036
|
paginator.updateColumns(nextSectionConfig.columns ?? DEFAULT_COLUMNS);
|
|
1037
1037
|
}
|
|
1038
1038
|
//#endregion
|
|
1039
|
-
export { DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, applyContextualSpacing, applyPendingToActive, assertExhaustiveFlowBlock, calculateChainHeight, collectSectionConfigs, computeKeepNextChains, createInitialSectionState, createPaginator, findPageIndexContainingPmPos, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getEffectiveColumns, getEffectiveMargins, getEffectivePageSize, getHeaderRowsHeight, getMidChainIndices, getTableRowLeadingWidth, hasKeepLines, hasPageBreakBefore, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, layoutDocument, resolveSectionHeaderFooterRefs, resolveTableCellPadding, scheduleSectionBreak, tableColumnsArePinned };
|
|
1039
|
+
export { DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, applyContextualSpacing, applyPendingToActive, assertExhaustiveFlowBlock, calculateChainHeight, collectSectionConfigs, computeKeepNextChains, createInitialSectionState, createPaginator, findPageIndexContainingPmPos, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getEffectiveColumns, getEffectiveMargins, getEffectivePageSize, getHeaderRowsHeight, getMidChainIndices, getTableRowLeadingWidth, hasKeepLines, hasPageBreakBefore, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, layoutDocument, resolveSectionHeaderFooterRefs, resolveTableCellPadding, resolveTableWidthPx, scheduleSectionBreak, tableColumnsArePinned };
|
|
@@ -4,7 +4,7 @@ import { isParagraphFrameTextBox } from "../paragraphFrame.js";
|
|
|
4
4
|
import { normalizeSectionBreakType } from "../section-breaks.js";
|
|
5
5
|
import { bandFragmentX, bandTopContentY, isPageFrameRelativeAnchor } from "../textBoxFlow.js";
|
|
6
6
|
import { getTextBoxGroupId } from "../textBoxGroup.js";
|
|
7
|
-
import { DEFAULT_TEXTBOX_MARGINS, floatingTextBoxReservesBand, floatingTextBoxWrapsText, resolveTableCellPadding, tableColumnsArePinned } from "../types.js";
|
|
7
|
+
import { DEFAULT_TEXTBOX_MARGINS, floatingTextBoxReservesBand, floatingTextBoxWrapsText, resolveTableCellPadding, resolveTableWidthPx, tableColumnsArePinned } from "../types.js";
|
|
8
8
|
import { getCachedParagraphMeasure, setCachedParagraphMeasure } from "./cache.js";
|
|
9
9
|
import { resolveFloatingTablePageX } from "./floatingTablePosition.js";
|
|
10
10
|
import { findClearLineY, measureParagraph } from "./measureParagraph.js";
|
|
@@ -59,11 +59,6 @@ function emuToPixels(emu) {
|
|
|
59
59
|
if (emu === void 0) return 0;
|
|
60
60
|
return Math.round(emu * 96 / 914400);
|
|
61
61
|
}
|
|
62
|
-
function resolveTableWidthPx(width, widthType, contentWidth) {
|
|
63
|
-
if (!width) return;
|
|
64
|
-
if (widthType === "pct") return contentWidth * width / 5e3;
|
|
65
|
-
if (widthType === "dxa" || !widthType || widthType === "auto") return Math.round(width / 20 * 1.333);
|
|
66
|
-
}
|
|
67
62
|
function measureTableBlock(tableBlock, contentWidth, fieldValues) {
|
|
68
63
|
let columnWidths = tableBlock.columnWidths ?? [];
|
|
69
64
|
const explicitWidthPx = resolveTableWidthPx(tableBlock.width, tableBlock.widthType, contentWidth);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { OutlineStyleAttr } from "../types/documentEnumValues.js";
|
|
2
2
|
import { ImagePosition, ImageWrap, NumberFormat, SdtProperties, SdtType, ShapeTextBody, TableCellFormatting, TableWidthType, VerticalAlign } from "@stll/docx-core/model";
|
|
3
3
|
declare namespace types_d_exports {
|
|
4
|
-
export { BlockId, BorderStyle, CellBorderSpec, CellBorders, ColumnBreakBlock, ColumnBreakMeasure, ColumnLayout, DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, DocumentPosition, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, FieldRun, FloatingTablePosition, FlowBlock, FootnoteContent, Fragment, FragmentBase, HeaderFooterContent, HeaderFooterContentHeights, HeaderFooterLayout, HitTestResult, HyperlinkInfo, ImageBlock, ImageFragment, ImageMeasure, ImageRun, ImageRunPosition, Layout, LayoutOptions, LineBreakRun, ListMarkerFormatting, ListNumPr, MathRun, Measure, MeasuredLine, Page, PageBreakBlock, PageBreakMeasure, PageHeaderFooterRefs, PageMargins, ParagraphAttrs, ParagraphBlock, ParagraphBorders, ParagraphFragment, ParagraphIndent, ParagraphMeasure, ParagraphSpacing, RenderedPageBreakRun, Run, RunFormatting, SdtGroup, SectionBreakBlock, SectionBreakMeasure, SectionPageNumbering, TabAlignment, TabRun, TabStop, TableBlock, TableCell, TableCellMeasure, TableFragment, TableMeasure, TableRow, TableRowMeasure, TextBoxBlock, TextBoxFlowAttrs, TextBoxFragment, TextBoxMeasure, TextRun, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, resolveTableCellPadding, tableColumnsArePinned };
|
|
4
|
+
export { BlockId, BorderStyle, CellBorderSpec, CellBorders, ColumnBreakBlock, ColumnBreakMeasure, ColumnLayout, DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, DocumentPosition, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, FieldRun, FloatingTablePosition, FlowBlock, FootnoteContent, Fragment, FragmentBase, HeaderFooterContent, HeaderFooterContentHeights, HeaderFooterLayout, HitTestResult, HyperlinkInfo, ImageBlock, ImageFragment, ImageMeasure, ImageRun, ImageRunPosition, Layout, LayoutOptions, LineBreakRun, ListMarkerFormatting, ListNumPr, MathRun, Measure, MeasuredLine, Page, PageBreakBlock, PageBreakMeasure, PageHeaderFooterRefs, PageMargins, ParagraphAttrs, ParagraphBlock, ParagraphBorders, ParagraphFragment, ParagraphIndent, ParagraphMeasure, ParagraphSpacing, RenderedPageBreakRun, Run, RunFormatting, SdtGroup, SectionBreakBlock, SectionBreakMeasure, SectionPageNumbering, TabAlignment, TabRun, TabStop, TableBlock, TableCell, TableCellMeasure, TableFragment, TableMeasure, TableRow, TableRowMeasure, TextBoxBlock, TextBoxFlowAttrs, TextBoxFragment, TextBoxMeasure, TextRun, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, resolveTableCellPadding, resolveTableWidthPx, tableColumnsArePinned };
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
7
|
* Unique identifier for a block in the document.
|
|
@@ -1429,7 +1429,13 @@ declare function floatingTextBoxReservesBand(block: TextBoxFlowAttrs): boolean;
|
|
|
1429
1429
|
* and the painter both consult this so their line count and `white-space` agree.
|
|
1430
1430
|
*/
|
|
1431
1431
|
declare function tableColumnsArePinned(table: TableBlock): boolean;
|
|
1432
|
+
/**
|
|
1433
|
+
* Resolve a `w:tblW`/`w:tcW` pair to pixels. The single reader: measurement and
|
|
1434
|
+
* the footnote layout bridge both go through it so a table cannot be pinned in
|
|
1435
|
+
* one and autofitted in the other.
|
|
1436
|
+
*/
|
|
1437
|
+
declare function resolveTableWidthPx(width: number | undefined, widthType: TableWidthType | undefined, containerWidth: number): number | undefined;
|
|
1432
1438
|
/** Return the leading visual offset for a row with omitted grid columns. */
|
|
1433
1439
|
declare const getTableRowLeadingWidth: (row: TableRow, columnWidths: readonly number[]) => number;
|
|
1434
1440
|
//#endregion
|
|
1435
|
-
export { BlockId, BorderStyle, CellBorderSpec, CellBorders, ColumnBreakBlock, ColumnBreakMeasure, ColumnLayout, DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, DocumentPosition, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, FieldRun, FloatingTablePosition, FlowBlock, FootnoteContent, Fragment, FragmentBase, HeaderFooterContent, HeaderFooterContentHeights, HeaderFooterLayout, HitTestResult, HyperlinkInfo, ImageBlock, ImageFragment, ImageMeasure, ImageRun, ImageRunPosition, Layout, LayoutOptions, LineBreakRun, ListMarkerFormatting, ListNumPr, MathRun, Measure, MeasuredLine, Page, PageBreakBlock, PageBreakMeasure, PageHeaderFooterRefs, PageMargins, ParagraphAttrs, ParagraphBlock, ParagraphBorders, ParagraphFragment, ParagraphIndent, ParagraphMeasure, ParagraphSpacing, RenderedPageBreakRun, Run, RunFormatting, SdtGroup, SectionBreakBlock, SectionBreakMeasure, SectionPageNumbering, TabAlignment, TabRun, TabStop, TableBlock, TableCell, TableCellMeasure, TableFragment, TableMeasure, TableRow, TableRowMeasure, TextBoxBlock, TextBoxFlowAttrs, TextBoxFragment, TextBoxMeasure, TextRun, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, resolveTableCellPadding, tableColumnsArePinned, types_d_exports };
|
|
1441
|
+
export { BlockId, BorderStyle, CellBorderSpec, CellBorders, ColumnBreakBlock, ColumnBreakMeasure, ColumnLayout, DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, DocumentPosition, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, FieldRun, FloatingTablePosition, FlowBlock, FootnoteContent, Fragment, FragmentBase, HeaderFooterContent, HeaderFooterContentHeights, HeaderFooterLayout, HitTestResult, HyperlinkInfo, ImageBlock, ImageFragment, ImageMeasure, ImageRun, ImageRunPosition, Layout, LayoutOptions, LineBreakRun, ListMarkerFormatting, ListNumPr, MathRun, Measure, MeasuredLine, Page, PageBreakBlock, PageBreakMeasure, PageHeaderFooterRefs, PageMargins, ParagraphAttrs, ParagraphBlock, ParagraphBorders, ParagraphFragment, ParagraphIndent, ParagraphMeasure, ParagraphSpacing, RenderedPageBreakRun, Run, RunFormatting, SdtGroup, SectionBreakBlock, SectionBreakMeasure, SectionPageNumbering, TabAlignment, TabRun, TabStop, TableBlock, TableCell, TableCellMeasure, TableFragment, TableMeasure, TableRow, TableRowMeasure, TextBoxBlock, TextBoxFlowAttrs, TextBoxFragment, TextBoxMeasure, TextRun, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, resolveTableCellPadding, resolveTableWidthPx, tableColumnsArePinned, types_d_exports };
|
|
@@ -14,6 +14,7 @@ var types_exports = /* @__PURE__ */ __exportAll({
|
|
|
14
14
|
isFloatingTextBoxBlock: () => isFloatingTextBoxBlock,
|
|
15
15
|
isTextWrappingFloatingImageRun: () => isTextWrappingFloatingImageRun,
|
|
16
16
|
resolveTableCellPadding: () => resolveTableCellPadding,
|
|
17
|
+
resolveTableWidthPx: () => resolveTableWidthPx,
|
|
17
18
|
tableColumnsArePinned: () => tableColumnsArePinned
|
|
18
19
|
});
|
|
19
20
|
const DEFAULT_TABLE_CELL_PADDING = {
|
|
@@ -129,7 +130,39 @@ function floatingTextBoxReservesBand(block) {
|
|
|
129
130
|
*/
|
|
130
131
|
function tableColumnsArePinned(table) {
|
|
131
132
|
if (table.layout === "fixed") return true;
|
|
132
|
-
return table.widthType
|
|
133
|
+
return hasMeasuredTableWidth(table.widthType);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Whether `w:tblW`/`w:tcW`'s `w:w` is a measurement at all.
|
|
137
|
+
*
|
|
138
|
+
* Under `w:type="auto"` or `"nil"` (§17.18.87) the number is meaningless:
|
|
139
|
+
* `auto` asks the consumer to size the table to its content and `nil` declares
|
|
140
|
+
* no width, so both ignore `w:w` entirely. Word still writes a leftover value
|
|
141
|
+
* there, and reading it as twips pins a table that should autofit.
|
|
142
|
+
*/
|
|
143
|
+
function hasMeasuredTableWidth(widthType) {
|
|
144
|
+
switch (widthType) {
|
|
145
|
+
case "dxa":
|
|
146
|
+
case "pct": return true;
|
|
147
|
+
case "auto":
|
|
148
|
+
case "nil":
|
|
149
|
+
case void 0: return false;
|
|
150
|
+
default: return widthType;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
const TWIPS_PER_INCH = 1440;
|
|
154
|
+
const PIXELS_PER_INCH = 96;
|
|
155
|
+
/** `w:type="pct"` measures in fiftieths of a percent, so 5000 is 100 %. */
|
|
156
|
+
const PERCENT_DENOMINATOR = 5e3;
|
|
157
|
+
/**
|
|
158
|
+
* Resolve a `w:tblW`/`w:tcW` pair to pixels. The single reader: measurement and
|
|
159
|
+
* the footnote layout bridge both go through it so a table cannot be pinned in
|
|
160
|
+
* one and autofitted in the other.
|
|
161
|
+
*/
|
|
162
|
+
function resolveTableWidthPx(width, widthType, containerWidth) {
|
|
163
|
+
if (width === void 0 || width <= 0 || !hasMeasuredTableWidth(widthType)) return;
|
|
164
|
+
if (widthType === "pct") return width / PERCENT_DENOMINATOR * containerWidth;
|
|
165
|
+
return width / TWIPS_PER_INCH * PIXELS_PER_INCH;
|
|
133
166
|
}
|
|
134
167
|
const tableRowOwnsNestedGrid = (row) => {
|
|
135
168
|
const cell = row.cells.length === 1 ? row.cells.at(0) : void 0;
|
|
@@ -142,4 +175,4 @@ const getTableRowLeadingWidth = (row, columnWidths) => {
|
|
|
142
175
|
return columnWidths.slice(0, row.gridBefore ?? 0).reduce((sum, columnWidth) => sum + columnWidth, 0);
|
|
143
176
|
};
|
|
144
177
|
//#endregion
|
|
145
|
-
export { DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, resolveTableCellPadding, tableColumnsArePinned, types_exports };
|
|
178
|
+
export { DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, resolveTableCellPadding, resolveTableWidthPx, tableColumnsArePinned, types_exports };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { applySanitizedImageSrc } from "../utils/sanitizeImageSrc.js";
|
|
2
|
-
import { sanitizeExternalUrl } from "../utils/urlSecurity.js";
|
|
2
|
+
import { anchorTargetAttrs, sanitizeExternalUrl } from "../utils/urlSecurity.js";
|
|
3
3
|
//#region src/layout-painter/renderImage.ts
|
|
4
4
|
/**
|
|
5
5
|
* CSS class names for image elements
|
|
@@ -145,8 +145,9 @@ function renderImageFragment(fragment, block, _measure, _context, options = {})
|
|
|
145
145
|
if (hlinkHref) {
|
|
146
146
|
const linkEl = doc.createElement("a");
|
|
147
147
|
linkEl.href = hlinkHref;
|
|
148
|
-
|
|
149
|
-
linkEl.
|
|
148
|
+
const { target, rel } = anchorTargetAttrs(void 0);
|
|
149
|
+
linkEl.target = target;
|
|
150
|
+
linkEl.rel = rel;
|
|
150
151
|
linkEl.style.display = "block";
|
|
151
152
|
linkEl.style.width = "100%";
|
|
152
153
|
linkEl.style.height = "100%";
|
|
@@ -16,7 +16,7 @@ import { resolvePhysicalParagraphInlineLayout } from "../utils/paragraphInlineLa
|
|
|
16
16
|
import { inlineImageBoundingBox, parseRotationDegrees, rotatedBoundingBox } from "../utils/rotationBoundingBox.js";
|
|
17
17
|
import { sanitizeImageSrc } from "../utils/sanitizeImageSrc.js";
|
|
18
18
|
import { SCRIPT_CLASS, hasCjk, hasComplexScript, segmentByScript } from "../utils/scriptSegments.js";
|
|
19
|
-
import { sanitizeExternalUrl } from "../utils/urlSecurity.js";
|
|
19
|
+
import { anchorTargetAttrs, sanitizeExternalUrl } from "../utils/urlSecurity.js";
|
|
20
20
|
import { borderStrokeToCss, resolveParagraphBorderHorizontalOutsets } from "./borderStroke.js";
|
|
21
21
|
import { planCursiveJoiners, withCursiveJoiners } from "./cursiveJoiners.js";
|
|
22
22
|
import { getAutomaticTextColorForBackground, setAuthoredBackgroundColor, setAuthoredTextColor } from "./documentColors.js";
|
|
@@ -357,8 +357,9 @@ function renderTextRun(run, doc, options) {
|
|
|
357
357
|
anchor.href = hyperlinkHref;
|
|
358
358
|
if (options?.hyperlinkDirection || DISPLAYED_URL_PATTERN.test(paintedText.trim())) anchor.dir = LEFT_TO_RIGHT_DIRECTION;
|
|
359
359
|
if (!isBookmarkTarget) {
|
|
360
|
-
|
|
361
|
-
anchor.
|
|
360
|
+
const { target, rel } = anchorTargetAttrs(void 0);
|
|
361
|
+
anchor.target = target;
|
|
362
|
+
anchor.rel = rel;
|
|
362
363
|
}
|
|
363
364
|
if (run.hyperlink.tooltip) anchor.title = run.hyperlink.tooltip;
|
|
364
365
|
appendPaintedText({
|
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
import { validateFolioDocumentModel } from "../docx/modelValidation.js";
|
|
2
|
+
import { bytesToBase64 } from "../utils/base64.js";
|
|
2
3
|
//#region src/managers/autoSaveCodec.ts
|
|
3
4
|
const AUTOSAVE_FORMAT_VERSION = 2;
|
|
4
|
-
const BASE64_CHUNK_BYTES = 32768;
|
|
5
|
-
const encodeBase64 = (buffer) => {
|
|
6
|
-
const bytes = new Uint8Array(buffer);
|
|
7
|
-
const chunks = [];
|
|
8
|
-
for (let offset = 0; offset < bytes.length; offset += BASE64_CHUNK_BYTES) chunks.push(String.fromCharCode(...bytes.subarray(offset, offset + BASE64_CHUNK_BYTES)));
|
|
9
|
-
return btoa(chunks.join(""));
|
|
10
|
-
};
|
|
11
5
|
const decodeBase64 = (value) => {
|
|
12
6
|
const binary = atob(value);
|
|
13
7
|
const bytes = new Uint8Array(binary.length);
|
|
@@ -23,7 +17,7 @@ const encodeValue = (value) => {
|
|
|
23
17
|
};
|
|
24
18
|
if (value instanceof ArrayBuffer) return {
|
|
25
19
|
type: "arrayBuffer",
|
|
26
|
-
value:
|
|
20
|
+
value: bytesToBase64(new Uint8Array(value))
|
|
27
21
|
};
|
|
28
22
|
if (value instanceof Map) return {
|
|
29
23
|
type: "map",
|
package/dist/markdown/images.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { bytesToBase64 } from "../utils/base64.js";
|
|
1
2
|
//#region src/markdown/images.ts
|
|
2
3
|
const MIME_TO_EXT = {
|
|
3
4
|
"image/png": "png",
|
|
@@ -14,10 +15,6 @@ const MIME_TO_EXT = {
|
|
|
14
15
|
function extFor(mimeType, fallback) {
|
|
15
16
|
return MIME_TO_EXT[mimeType] ?? fallback;
|
|
16
17
|
}
|
|
17
|
-
function bytesToBase64(bytes) {
|
|
18
|
-
if (typeof Buffer !== "undefined") return Buffer.from(bytes).toString("base64");
|
|
19
|
-
return btoa(new TextDecoder("latin1").decode(bytes));
|
|
20
|
-
}
|
|
21
18
|
function toUint8(data) {
|
|
22
19
|
if (data instanceof Uint8Array) return data;
|
|
23
20
|
return new Uint8Array(data);
|
package/dist/markdown/index.js
CHANGED
|
@@ -19,7 +19,7 @@ function toMarkdownResult(doc, opts) {
|
|
|
19
19
|
return renderDocument(doc, opts);
|
|
20
20
|
}
|
|
21
21
|
function renderDocument(doc, opts = {}) {
|
|
22
|
-
const ctx = newContext(opts);
|
|
22
|
+
const ctx = newContext(opts, doc.package.styles);
|
|
23
23
|
const markdown = appendTrailers(ctx, doc, renderBlocks(ctx, doc.package, doc.package.document.content));
|
|
24
24
|
if (doc.warnings) ctx.warnings.unshift(...doc.warnings);
|
|
25
25
|
if (!markdown.trim()) ctx.warnings.push("document has no content");
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
import { document_d_exports } from "../types/document.js";
|
|
1
2
|
import { MarkdownOptions, RenderContext } from "./types.js";
|
|
2
3
|
//#region src/markdown/internals.d.ts
|
|
3
4
|
/**
|
|
4
5
|
* Build a fresh `RenderContext` from caller options, applying defaults. The
|
|
5
6
|
* `footnotes` default is `"keep"` (folio addition over upstream #595).
|
|
7
|
+
*
|
|
8
|
+
* The document's styles are indexed once here: every paragraph asks the index
|
|
9
|
+
* whether it is a heading or a quote, so rebuilding it per paragraph would
|
|
10
|
+
* make the render quadratic.
|
|
6
11
|
*/
|
|
7
|
-
declare function newContext(opts?: MarkdownOptions): RenderContext;
|
|
12
|
+
declare function newContext(opts?: MarkdownOptions, styles?: document_d_exports.StyleDefinitions | undefined): RenderContext;
|
|
8
13
|
/**
|
|
9
14
|
* Push a warning into the context, deduplicating against existing entries so
|
|
10
15
|
* recurring messages appear at most once.
|
|
@@ -1,10 +1,23 @@
|
|
|
1
|
+
import { createBuiltInStyleIndex } from "../docx/builtInStyles.js";
|
|
1
2
|
//#region src/markdown/internals.ts
|
|
2
3
|
/**
|
|
4
|
+
* Internal helpers shared by the markdown converter: context construction and
|
|
5
|
+
* warning dedupe. Kept free of renderer imports so the renderers can import
|
|
6
|
+
* `pushWarning` without forming an import cycle (trailer emission, which needs
|
|
7
|
+
* `renderBlock`, lives in `trailers.ts`). Ported from eigenpal/docx-editor
|
|
8
|
+
* PR #595, trimmed to the sync continuous path.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
3
11
|
* Build a fresh `RenderContext` from caller options, applying defaults. The
|
|
4
12
|
* `footnotes` default is `"keep"` (folio addition over upstream #595).
|
|
13
|
+
*
|
|
14
|
+
* The document's styles are indexed once here: every paragraph asks the index
|
|
15
|
+
* whether it is a heading or a quote, so rebuilding it per paragraph would
|
|
16
|
+
* make the render quadratic.
|
|
5
17
|
*/
|
|
6
|
-
function newContext(opts = {}) {
|
|
18
|
+
function newContext(opts = {}, styles) {
|
|
7
19
|
return {
|
|
20
|
+
builtInStyles: createBuiltInStyleIndex(styles?.styles ?? [], styles?.docDefaults),
|
|
8
21
|
opts: {
|
|
9
22
|
annotations: opts.annotations ?? "html",
|
|
10
23
|
trackedChanges: opts.trackedChanges ?? "annotate",
|