@stll/folio-core 0.45.0 → 0.46.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/apply.js +59 -19
- package/dist/ai-edits/headless.js +1 -1
- package/dist/compare/compare.js +2 -5
- package/dist/compare/scenario.js +2 -5
- package/dist/compare/types.d.ts +9 -1
- package/dist/compare/types.js +12 -1
- package/dist/compat/eigenpal.d.ts +2 -1
- package/dist/compat/eigenpal.js +2 -1
- package/dist/content-controls/checkboxDisplay.d.ts +11 -0
- package/dist/content-controls/checkboxDisplay.js +40 -0
- package/dist/content-controls/findContentControls.js +3 -1
- package/dist/content-controls/mutateContentControls.js +17 -2
- package/dist/controller/contentControlWidgetController.d.ts +1 -0
- package/dist/controller/contentControlWidgetController.js +3 -0
- package/dist/controller/hiddenEditorApi.js +3 -1
- package/dist/controller/hiddenEditorManager.d.ts +1 -1
- package/dist/controller/hiddenEditorManager.js +6 -3
- package/dist/display-list/build/buildDisplayList.js +20 -1
- package/dist/display-list/build/imagePrimitives.d.ts +1 -1
- package/dist/display-list/build/imagePrimitives.js +3 -1
- package/dist/display-list/build/paragraphPrimitives.js +21 -2
- package/dist/display-list/dom/renderDisplayListToDom.js +10 -2
- package/dist/display-list/types.d.ts +17 -0
- package/dist/docx/attributeRemainder.d.ts +43 -0
- package/dist/docx/attributeRemainder.js +65 -0
- package/dist/docx/blockContentParser.d.ts +1 -1
- package/dist/docx/blockContentParser.js +87 -63
- package/dist/docx/blockPlainText.d.ts +3 -4
- package/dist/docx/blockPlainText.js +1 -0
- package/dist/docx/bookmarkPlacement.js +2 -0
- package/dist/docx/commentAnchorIndex.d.ts +30 -0
- package/dist/docx/commentAnchorIndex.js +50 -0
- package/dist/docx/commentParser.d.ts +1 -1
- package/dist/docx/commentParser.js +54 -37
- package/dist/docx/commentRangeIntegrity.d.ts +16 -1
- package/dist/docx/commentRangeIntegrity.js +42 -1
- package/dist/docx/commentRangeJoin.d.ts +9 -0
- package/dist/docx/commentRangeJoin.js +33 -0
- package/dist/docx/commentReferenceCompletion.d.ts +9 -0
- package/dist/docx/commentReferenceCompletion.js +47 -0
- package/dist/docx/commentReferenceNormalization.js +1 -0
- package/dist/docx/commentReplyMarkers.js +11 -19
- package/dist/docx/compatibility.js +1 -0
- package/dist/docx/containerChildren.d.ts +111 -0
- package/dist/docx/containerChildren.gen.d.ts +28 -0
- package/dist/docx/containerChildren.gen.js +246 -0
- package/dist/docx/containerChildren.js +103 -0
- package/dist/docx/documentParser.d.ts +1 -1
- package/dist/docx/documentParser.js +3 -3
- package/dist/docx/ensureParaIds.js +17 -7
- package/dist/docx/fieldParser.d.ts +1 -1
- package/dist/docx/fieldParser.js +4 -4
- package/dist/docx/fieldState.d.ts +26 -0
- package/dist/docx/fieldState.js +53 -0
- package/dist/docx/footnoteParser.d.ts +1 -1
- package/dist/docx/graphicFrameLocks.d.ts +16 -4
- package/dist/docx/graphicFrameLocks.js +19 -6
- package/dist/docx/headerFooterParser.js +1 -1
- package/dist/docx/headerFooterReferenceNormalization.js +1 -0
- package/dist/docx/hyperlinkParser.d.ts +27 -8
- package/dist/docx/hyperlinkParser.js +76 -18
- package/dist/docx/imageParser.js +33 -8
- package/dist/docx/inlineWrapperContent.d.ts +85 -0
- package/dist/docx/inlineWrapperContent.js +84 -0
- package/dist/docx/normalizeBaseDirection.js +10 -1
- package/dist/docx/paraIdAttribute.d.ts +21 -0
- package/dist/docx/paraIdAttribute.js +64 -0
- package/dist/docx/paragraphParser.d.ts +1 -1
- package/dist/docx/paragraphParser.js +277 -168
- package/dist/docx/paragraphPropertySource.js +5 -1
- package/dist/docx/paragraphTextBoxEnrichment.d.ts +1 -1
- package/dist/docx/paragraphTextBoxEnrichment.js +6 -52
- package/dist/docx/paragraphTraversal.js +7 -4
- package/dist/docx/parseWarningMessage.js +2 -1
- package/dist/docx/preservedRunContent.d.ts +32 -0
- package/dist/docx/preservedRunContent.js +86 -0
- package/dist/docx/renderedPageBreakNormalization.js +2 -4
- package/dist/docx/rezip.js +74 -18
- package/dist/docx/runParser.d.ts +1 -1
- package/dist/docx/runParser.js +16 -12
- package/dist/docx/sectionParser.js +8 -1
- package/dist/docx/selectiveXmlPatch.d.ts +46 -2
- package/dist/docx/selectiveXmlPatch.js +86 -39
- package/dist/docx/serializer/borderSerializer.js +2 -2
- package/dist/docx/serializer/commentSerializer.js +5 -7
- package/dist/docx/serializer/documentSerializer.js +8 -11
- package/dist/docx/serializer/headerFooterSerializer.js +7 -9
- package/dist/docx/serializer/noteSerializer.js +8 -8
- package/dist/docx/serializer/paragraphSerializer.js +76 -56
- package/dist/docx/serializer/runSerializer.js +25 -16
- package/dist/docx/serializer/sectionPropertiesSerializer.js +8 -4
- package/dist/docx/serializer/tableSerializer.js +18 -8
- package/dist/docx/server/createBilingualDocument.js +3 -1
- package/dist/docx/server/materializeYjsDocx.d.ts +1 -1
- package/dist/docx/server/materializeYjsDocx.js +9 -1
- package/dist/docx/server/migrateYjsAttrSchema.d.ts +55 -0
- package/dist/docx/server/migrateYjsAttrSchema.js +95 -0
- package/dist/docx/shapeParser.js +5 -5
- package/dist/docx/tableParser.d.ts +1 -1
- package/dist/docx/tableParser.js +206 -85
- package/dist/docx/textBoxParser.d.ts +25 -2
- package/dist/docx/textBoxParser.js +52 -2
- package/dist/docx/unzip.js +5 -4
- package/dist/docx/vmlImageParser.d.ts +17 -1
- package/dist/docx/vmlImageParser.js +17 -1
- package/dist/docx/xmlEncoding.d.ts +5 -0
- package/dist/docx/xmlEncoding.js +12 -0
- package/dist/docx/xmlParser.d.ts +10 -1
- package/dist/docx/xmlParser.js +14 -1
- package/dist/headless-layout.js +10 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/internal/pageBreakRunSourceDescendantIndex.js +5 -2
- package/dist/layout-bridge/convert/toFlowBlocks.js +102 -12
- package/dist/layout-engine/measure/tableCellFloating.d.ts +2 -0
- package/dist/layout-engine/measure/tableCellFloating.js +2 -0
- package/dist/layout-engine/types.d.ts +23 -1
- package/dist/layout-painter/renderImage.d.ts +5 -1
- package/dist/layout-painter/renderImage.js +10 -3
- package/dist/layout-painter/renderPage.d.ts +2 -0
- package/dist/layout-painter/renderPage.js +4 -0
- package/dist/layout-painter/renderParagraph.d.ts +13 -1
- package/dist/layout-painter/renderParagraph.js +22 -3
- package/dist/managers/autoSaveCodec.d.ts +9 -1
- package/dist/managers/autoSaveCodec.js +12 -4
- package/dist/markdown/renderBlock.js +1 -0
- package/dist/markdown/renderRuns.d.ts +1 -1
- package/dist/markdown/renderRuns.js +28 -5
- package/dist/markdown/renderTable.js +22 -5
- package/dist/markdown/trailers.js +4 -1
- package/dist/pdf/images.js +142 -6
- package/dist/prosemirror/attrs/index.d.ts +14 -3
- package/dist/prosemirror/attrs/index.js +155 -2
- package/dist/prosemirror/authoredTransformAttrs.d.ts +28 -0
- package/dist/prosemirror/authoredTransformAttrs.js +64 -0
- package/dist/prosemirror/commands/contentControls.js +10 -2
- package/dist/prosemirror/commands/image.d.ts +9 -2
- package/dist/prosemirror/commands/image.js +42 -28
- package/dist/prosemirror/commands/pageBreak.js +1 -1
- package/dist/prosemirror/commentReferenceAttrs.d.ts +8 -0
- package/dist/prosemirror/commentReferenceAttrs.js +33 -0
- package/dist/prosemirror/commentReferenceIntegrity.d.ts +47 -0
- package/dist/prosemirror/commentReferenceIntegrity.js +43 -0
- package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -13
- package/dist/prosemirror/conversion/fromProseDoc.js +269 -70
- package/dist/prosemirror/conversion/index.d.ts +2 -2
- package/dist/prosemirror/conversion/toProseDoc.d.ts +7 -9
- package/dist/prosemirror/conversion/toProseDoc.js +468 -308
- package/dist/prosemirror/extensions/StarterKit.js +8 -58
- package/dist/prosemirror/extensions/core/DocExtension.js +1 -1
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +2 -1
- package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +45 -27
- package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +3 -1
- package/dist/prosemirror/extensions/features/ImagePasteExtension.js +5 -3
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +1 -0
- package/dist/prosemirror/extensions/markRegistry.d.ts +41 -0
- package/dist/prosemirror/extensions/markRegistry.js +75 -0
- package/dist/prosemirror/extensions/marks/InlineWrapperExtension.d.ts +18 -0
- package/dist/prosemirror/extensions/marks/InlineWrapperExtension.js +63 -0
- package/dist/prosemirror/extensions/marks/markUtils.d.ts +2 -1
- package/dist/prosemirror/extensions/marks/markUtils.js +47 -4
- package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.d.ts +11 -0
- package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.js +87 -0
- package/dist/prosemirror/extensions/nodes/FieldExtension.js +9 -7
- package/dist/prosemirror/extensions/nodes/ImageExtension.js +16 -0
- package/dist/prosemirror/extensions/nodes/PreservedBlockExtension.d.ts +32 -0
- package/dist/prosemirror/extensions/nodes/PreservedBlockExtension.js +67 -0
- package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.d.ts +16 -0
- package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.js +60 -0
- package/dist/prosemirror/extensions/nodes/ShapeExtension.js +3 -0
- package/dist/prosemirror/extensions/nodes/TableExtension.js +3 -2
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +5 -1
- package/dist/prosemirror/inlineWrapperStack.d.ts +39 -0
- package/dist/prosemirror/inlineWrapperStack.js +75 -0
- package/dist/prosemirror/pageBreakRunProjection.d.ts +17 -7
- package/dist/prosemirror/pageBreakRunProjection.js +19 -9
- package/dist/prosemirror/replacedAnnotations.d.ts +59 -0
- package/dist/prosemirror/replacedAnnotations.js +165 -0
- package/dist/prosemirror/runFormattingInlineCarriers.d.ts +3 -1
- package/dist/prosemirror/runFormattingInlineCarriers.js +5 -1
- package/dist/prosemirror/schema/index.d.ts +3 -3
- package/dist/prosemirror/schema/marks.d.ts +25 -1
- package/dist/prosemirror/schema/nodes.d.ts +90 -3
- package/dist/prosemirror/schema/nodes.js +16 -1
- package/dist/prosemirror/trackedRunInlineAtoms.d.ts +2 -0
- package/dist/prosemirror/trackedRunInlineAtoms.js +2 -0
- package/dist/prosemirror/validation.js +16 -2
- package/dist/prosemirror/yjsDocumentMetadata.d.ts +73 -0
- package/dist/prosemirror/yjsDocumentMetadata.js +171 -0
- package/dist/prosemirror/zeroWidthAnchors.js +2 -0
- package/dist/render-dom/commentAnchorAttributes.d.ts +37 -0
- package/dist/render-dom/commentAnchorAttributes.js +54 -0
- package/dist/server.d.ts +3 -1
- package/dist/server.js +3 -1
- package/dist/types/content.d.ts +2 -2
- package/dist/utils/clipboard.d.ts +9 -1
- package/dist/utils/clipboard.js +27 -1
- package/dist/utils/findReplace.js +1 -1
- package/dist/utils/imageLuminance.d.ts +15 -0
- package/dist/utils/imageLuminance.js +32 -0
- package/dist/utils/mergeDocumentContent.js +7 -17
- package/dist/utils/replaceText.js +1 -0
- package/package.json +2 -2
- package/dist/docx/blockRangeMarkers.d.ts +0 -36
- package/dist/docx/blockRangeMarkers.js +0 -59
- package/dist/prosemirror/yjsParagraphSourceContract.d.ts +0 -9
- package/dist/prosemirror/yjsParagraphSourceContract.js +0 -26
package/dist/docx/tableParser.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { NO_MODELLED_ATTRIBUTES, attributeRemainder } from "./attributeRemainder.js";
|
|
2
2
|
import { parseBookmarkEnd, parseBookmarkStart } from "./bookmarkParser.js";
|
|
3
3
|
import { appendBookmarkMarkerToLastParagraphInBlocks, appendBookmarkMarkerToLastParagraphInCells, prependBookmarkMarkersToFirstParagraphInBlocks, prependBookmarkMarkersToFirstParagraphInCell } from "./bookmarkPlacement.js";
|
|
4
4
|
import { parseBorderSpec } from "./borderParser.js";
|
|
5
|
+
import { CAPTURE, OWNED_ELSEWHERE, dispatchChildren, withPreservedChildren } from "./containerChildren.js";
|
|
5
6
|
import { parseParagraph } from "./paragraphParser.js";
|
|
6
7
|
import { enrichParagraphTextBoxes } from "./paragraphTextBoxEnrichment.js";
|
|
7
8
|
import { FloatingTableXSpecSchema, FloatingTableYSpecSchema, TableCellTextDirectionSchema, narrowEnum } from "./parserEnums.js";
|
|
@@ -10,7 +11,7 @@ import { TABLE_LOOK_FLAGS } from "./tableLook.js";
|
|
|
10
11
|
import { parsePropertyChangeInfo, parseTrackedChangeInfo } from "./trackedChangeInfo.js";
|
|
11
12
|
import { percentageSpelling, transitionalSlotEncoding } from "./transitionalSpelling.js";
|
|
12
13
|
import { captureVerbatimXml } from "./verbatimCapture.js";
|
|
13
|
-
import { cloneElement, findChild, findChildByLocalName, findChildren, getAttribute,
|
|
14
|
+
import { cloneElement, findChild, findChildByLocalName, findChildren, getAttribute, getLocalName, mergeXmlnsDeclarations, parseBooleanElement, parseNumericAttribute, parseOnOffAttribute, parseTableMeasurementValue, selectAlternateContentBranch } from "./xmlParser.js";
|
|
14
15
|
//#region src/docx/tableParser.ts
|
|
15
16
|
/**
|
|
16
17
|
* Sanity cap on `w:gridSpan` (and the derived table column count). Word's
|
|
@@ -472,59 +473,87 @@ function withContainerXmlns(options, element) {
|
|
|
472
473
|
};
|
|
473
474
|
}
|
|
474
475
|
function parseCellContent(tcElement, styles, theme, numbering, rels, media, options) {
|
|
475
|
-
const
|
|
476
|
+
const modelled = [];
|
|
476
477
|
const pendingBookmarkMarkers = [];
|
|
477
|
-
const
|
|
478
|
-
const
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
478
|
+
const captured = [];
|
|
479
|
+
const dispatchCellChildren = (element, childOptions) => {
|
|
480
|
+
const preserved = dispatchChildren({
|
|
481
|
+
element,
|
|
482
|
+
container: "block-content",
|
|
483
|
+
modelledCount: () => modelled.length,
|
|
484
|
+
undeclared: { AlternateContent: (child) => {
|
|
485
|
+
const selectedBranch = selectAlternateContentBranch(child);
|
|
486
|
+
if (!selectedBranch) return;
|
|
487
|
+
dispatchCellChildren(selectedBranch, withContainerXmlns(withContainerXmlns(childOptions, child), selectedBranch));
|
|
488
|
+
} },
|
|
489
|
+
handlers: {
|
|
490
|
+
p: (child) => {
|
|
491
|
+
const para = parseParagraph(child, styles, theme, numbering, rels, media, childOptions);
|
|
492
|
+
enrichParagraphTextBoxes(para, child, styles, theme, numbering, rels, media, parseTable);
|
|
493
|
+
prependPendingBookmarkMarkers(para, pendingBookmarkMarkers);
|
|
494
|
+
modelled.push(para);
|
|
495
|
+
},
|
|
496
|
+
tbl: (child) => {
|
|
497
|
+
const table = parseTable(child, styles, theme, numbering, rels, media, childOptions);
|
|
498
|
+
if (!table) return;
|
|
499
|
+
if (prependBookmarkMarkersToFirstParagraphInBlocks([table], pendingBookmarkMarkers)) pendingBookmarkMarkers.length = 0;
|
|
500
|
+
modelled.push(table);
|
|
501
|
+
},
|
|
502
|
+
sdt: (child) => {
|
|
503
|
+
const sdtContent = findChildByLocalName(child, "sdtContent");
|
|
504
|
+
if (!sdtContent) return;
|
|
505
|
+
dispatchCellChildren(sdtContent, withContainerXmlns(withContainerXmlns(childOptions, child), sdtContent));
|
|
506
|
+
},
|
|
507
|
+
bookmarkStart: (child) => {
|
|
508
|
+
collectCellBookmarkMarker(child, "bookmarkStart", modelled, pendingBookmarkMarkers);
|
|
509
|
+
},
|
|
510
|
+
bookmarkEnd: (child) => {
|
|
511
|
+
collectCellBookmarkMarker(child, "bookmarkEnd", modelled, pendingBookmarkMarkers);
|
|
512
|
+
},
|
|
513
|
+
tcPr: OWNED_ELSEWHERE,
|
|
514
|
+
sectPr: CAPTURE,
|
|
515
|
+
altChunk: CAPTURE,
|
|
516
|
+
commentRangeEnd: CAPTURE,
|
|
517
|
+
commentRangeStart: CAPTURE,
|
|
518
|
+
customXml: CAPTURE,
|
|
519
|
+
customXmlDelRangeEnd: CAPTURE,
|
|
520
|
+
customXmlDelRangeStart: CAPTURE,
|
|
521
|
+
customXmlInsRangeEnd: CAPTURE,
|
|
522
|
+
customXmlInsRangeStart: CAPTURE,
|
|
523
|
+
customXmlMoveFromRangeEnd: CAPTURE,
|
|
524
|
+
customXmlMoveFromRangeStart: CAPTURE,
|
|
525
|
+
customXmlMoveToRangeEnd: CAPTURE,
|
|
526
|
+
customXmlMoveToRangeStart: CAPTURE,
|
|
527
|
+
del: CAPTURE,
|
|
528
|
+
ins: CAPTURE,
|
|
529
|
+
moveFrom: CAPTURE,
|
|
530
|
+
moveFromRangeEnd: CAPTURE,
|
|
531
|
+
moveFromRangeStart: CAPTURE,
|
|
532
|
+
moveTo: CAPTURE,
|
|
533
|
+
moveToRangeEnd: CAPTURE,
|
|
534
|
+
moveToRangeStart: CAPTURE,
|
|
535
|
+
permEnd: CAPTURE,
|
|
536
|
+
permStart: CAPTURE,
|
|
537
|
+
proofErr: CAPTURE
|
|
538
|
+
}
|
|
539
|
+
});
|
|
540
|
+
if (preserved?.children) captured.push(...preserved.children);
|
|
518
541
|
};
|
|
519
|
-
|
|
520
|
-
if (
|
|
542
|
+
dispatchCellChildren(tcElement, options);
|
|
543
|
+
if (modelled.length === 0) modelled.push({
|
|
521
544
|
type: "paragraph",
|
|
522
545
|
content: [...pendingBookmarkMarkers]
|
|
523
546
|
});
|
|
524
|
-
else if (pendingBookmarkMarkers.length > 0) appendBookmarkMarkersToLastParagraphInBlocks(
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
547
|
+
else if (pendingBookmarkMarkers.length > 0) appendBookmarkMarkersToLastParagraphInBlocks(modelled, pendingBookmarkMarkers);
|
|
548
|
+
return withPreservedChildren(modelled, { children: captured }, (xml) => ({
|
|
549
|
+
type: "preservedBlock",
|
|
550
|
+
xml
|
|
551
|
+
}));
|
|
552
|
+
}
|
|
553
|
+
const collectCellBookmarkMarker = (child, localName, content, pending) => {
|
|
554
|
+
const marker = parseBookmarkMarker(child, localName);
|
|
555
|
+
if (!appendBookmarkMarkerToLastParagraphInBlocks(content, marker)) pending.push(marker);
|
|
556
|
+
};
|
|
528
557
|
/**
|
|
529
558
|
* Parse a table cell (w:tc)
|
|
530
559
|
*
|
|
@@ -576,29 +605,79 @@ function parseTableRow(trElement, styles, theme, numbering, rels, media, options
|
|
|
576
605
|
if (rowStructChange !== void 0) row.structuralChange = rowStructChange;
|
|
577
606
|
const rowOptions = withContainerXmlns(options, trElement);
|
|
578
607
|
const pendingBookmarkMarkers = [];
|
|
579
|
-
const
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
608
|
+
const preservedChildren = [];
|
|
609
|
+
/**
|
|
610
|
+
* One row's children, or a row-level content control's.
|
|
611
|
+
*
|
|
612
|
+
* folio unwraps `w:sdt` here and splices its rows' content into the row, so
|
|
613
|
+
* the recursion walks the control's content with the same map; the sink is
|
|
614
|
+
* the row's either way, because the control keeps no wrapper to hold one.
|
|
615
|
+
*/
|
|
616
|
+
const dispatchRowChildren = (element, childOptions) => {
|
|
617
|
+
const captured = dispatchChildren({
|
|
618
|
+
element,
|
|
619
|
+
container: "row-content",
|
|
620
|
+
modelledCount: () => row.cells.length,
|
|
621
|
+
handlers: {
|
|
622
|
+
tc: (child) => {
|
|
623
|
+
const cell = parseTableCell(child, styles, theme, numbering, rels, media, childOptions);
|
|
624
|
+
if (pendingBookmarkMarkers.length > 0) {
|
|
625
|
+
prependBookmarkMarkersToFirstParagraphInCell(cell, pendingBookmarkMarkers);
|
|
626
|
+
pendingBookmarkMarkers.length = 0;
|
|
627
|
+
}
|
|
628
|
+
row.cells.push(cell);
|
|
629
|
+
},
|
|
630
|
+
sdt: (child) => {
|
|
631
|
+
const sdtContent = findChildByLocalName(child, "sdtContent");
|
|
632
|
+
if (!sdtContent) return;
|
|
633
|
+
const sdtOptions = withContainerXmlns(childOptions, child);
|
|
634
|
+
dispatchRowChildren(sdtContent, withContainerXmlns(sdtOptions, sdtContent));
|
|
635
|
+
},
|
|
636
|
+
bookmarkStart: (child) => {
|
|
637
|
+
placeBookmarkMarker(parseBookmarkStart(child));
|
|
638
|
+
},
|
|
639
|
+
bookmarkEnd: (child) => {
|
|
640
|
+
placeBookmarkMarker(parseBookmarkEnd(child));
|
|
641
|
+
},
|
|
642
|
+
trPr: OWNED_ELSEWHERE,
|
|
643
|
+
tblPrEx: OWNED_ELSEWHERE,
|
|
644
|
+
commentRangeEnd: CAPTURE,
|
|
645
|
+
commentRangeStart: CAPTURE,
|
|
646
|
+
customXml: CAPTURE,
|
|
647
|
+
customXmlDelRangeEnd: CAPTURE,
|
|
648
|
+
customXmlDelRangeStart: CAPTURE,
|
|
649
|
+
customXmlInsRangeEnd: CAPTURE,
|
|
650
|
+
customXmlInsRangeStart: CAPTURE,
|
|
651
|
+
customXmlMoveFromRangeEnd: CAPTURE,
|
|
652
|
+
customXmlMoveFromRangeStart: CAPTURE,
|
|
653
|
+
customXmlMoveToRangeEnd: CAPTURE,
|
|
654
|
+
customXmlMoveToRangeStart: CAPTURE,
|
|
655
|
+
del: CAPTURE,
|
|
656
|
+
ins: CAPTURE,
|
|
657
|
+
moveFrom: CAPTURE,
|
|
658
|
+
moveFromRangeEnd: CAPTURE,
|
|
659
|
+
moveFromRangeStart: CAPTURE,
|
|
660
|
+
moveTo: CAPTURE,
|
|
661
|
+
moveToRangeEnd: CAPTURE,
|
|
662
|
+
moveToRangeStart: CAPTURE,
|
|
663
|
+
permEnd: CAPTURE,
|
|
664
|
+
permStart: CAPTURE,
|
|
665
|
+
proofErr: CAPTURE,
|
|
666
|
+
tr: CAPTURE
|
|
586
667
|
}
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
const sdtContent = findChildByLocalName(child, "sdtContent");
|
|
592
|
-
if (!sdtContent) return;
|
|
593
|
-
const sdtContentOptions = withContainerXmlns(withContainerXmlns(childOptions, child), sdtContent);
|
|
594
|
-
for (const sdtChild of getChildElements(sdtContent)) parseRowChild(sdtChild, sdtContentOptions);
|
|
595
|
-
return;
|
|
596
|
-
}
|
|
597
|
-
if (localName !== "bookmarkStart" && localName !== "bookmarkEnd") return;
|
|
598
|
-
const marker = parseBookmarkMarker(child, localName);
|
|
668
|
+
});
|
|
669
|
+
if (captured?.children) preservedChildren.push(...captured.children);
|
|
670
|
+
};
|
|
671
|
+
const placeBookmarkMarker = (marker) => {
|
|
599
672
|
if (!appendBookmarkMarkerToLastParagraphInCells(row.cells, marker)) pendingBookmarkMarkers.push(marker);
|
|
600
673
|
};
|
|
601
|
-
|
|
674
|
+
dispatchRowChildren(trElement, rowOptions);
|
|
675
|
+
if (preservedChildren.length > 0) row.preserved = { children: preservedChildren };
|
|
676
|
+
const remainingAttributes = attributeRemainder({
|
|
677
|
+
element: trElement,
|
|
678
|
+
modelled: NO_MODELLED_ATTRIBUTES
|
|
679
|
+
});
|
|
680
|
+
if (remainingAttributes) row.preservedAttributes = remainingAttributes;
|
|
602
681
|
if (pendingBookmarkMarkers.length > 0) appendBookmarkMarkersToLastCell(row, pendingBookmarkMarkers);
|
|
603
682
|
return row;
|
|
604
683
|
}
|
|
@@ -707,23 +786,65 @@ function parseTable(tblElement, styles, theme, numbering, rels, media, options)
|
|
|
707
786
|
}
|
|
708
787
|
const tableOptions = withContainerXmlns(options, tblElement);
|
|
709
788
|
const rowsWithGridOffsets = /* @__PURE__ */ new Set();
|
|
710
|
-
const
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
789
|
+
const preservedChildren = [];
|
|
790
|
+
/**
|
|
791
|
+
* One table's children, or a row-level content control's.
|
|
792
|
+
*
|
|
793
|
+
* folio unwraps `w:sdt` here and splices its rows into the table, so the
|
|
794
|
+
* recursion walks the control's content with the same map; the sink is the
|
|
795
|
+
* table's either way, because the control keeps no wrapper to hold one.
|
|
796
|
+
*/
|
|
797
|
+
const dispatchTableChildren = (element, childOptions) => {
|
|
798
|
+
const captured = dispatchChildren({
|
|
799
|
+
element,
|
|
800
|
+
container: "table-content",
|
|
801
|
+
modelledCount: () => table.rows.length,
|
|
802
|
+
handlers: {
|
|
803
|
+
tr: (child) => {
|
|
804
|
+
const rowIndex = table.rows.length;
|
|
805
|
+
table.rows.push(parseTableRow(child, styles, theme, numbering, rels, media, childOptions));
|
|
806
|
+
if (hasRowGridOffsets(child)) rowsWithGridOffsets.add(rowIndex);
|
|
807
|
+
},
|
|
808
|
+
sdt: (child) => {
|
|
809
|
+
const sdtContent = findChildByLocalName(child, "sdtContent");
|
|
810
|
+
if (!sdtContent) return;
|
|
811
|
+
const sdtOptions = withContainerXmlns(childOptions, child);
|
|
812
|
+
dispatchTableChildren(sdtContent, withContainerXmlns(sdtOptions, sdtContent));
|
|
813
|
+
},
|
|
814
|
+
tblPr: OWNED_ELSEWHERE,
|
|
815
|
+
tblGrid: OWNED_ELSEWHERE,
|
|
816
|
+
bookmarkEnd: CAPTURE,
|
|
817
|
+
bookmarkStart: CAPTURE,
|
|
818
|
+
commentRangeEnd: CAPTURE,
|
|
819
|
+
commentRangeStart: CAPTURE,
|
|
820
|
+
customXml: CAPTURE,
|
|
821
|
+
customXmlPr: CAPTURE,
|
|
822
|
+
customXmlDelRangeEnd: CAPTURE,
|
|
823
|
+
customXmlDelRangeStart: CAPTURE,
|
|
824
|
+
customXmlInsRangeEnd: CAPTURE,
|
|
825
|
+
customXmlInsRangeStart: CAPTURE,
|
|
826
|
+
customXmlMoveFromRangeEnd: CAPTURE,
|
|
827
|
+
customXmlMoveFromRangeStart: CAPTURE,
|
|
828
|
+
customXmlMoveToRangeEnd: CAPTURE,
|
|
829
|
+
customXmlMoveToRangeStart: CAPTURE,
|
|
830
|
+
del: CAPTURE,
|
|
831
|
+
ins: CAPTURE,
|
|
832
|
+
moveFrom: CAPTURE,
|
|
833
|
+
moveFromRangeEnd: CAPTURE,
|
|
834
|
+
moveFromRangeStart: CAPTURE,
|
|
835
|
+
moveTo: CAPTURE,
|
|
836
|
+
moveToRangeEnd: CAPTURE,
|
|
837
|
+
moveToRangeStart: CAPTURE,
|
|
838
|
+
permEnd: CAPTURE,
|
|
839
|
+
permStart: CAPTURE,
|
|
840
|
+
proofErr: CAPTURE
|
|
841
|
+
}
|
|
842
|
+
});
|
|
843
|
+
if (captured?.children) preservedChildren.push(...captured.children);
|
|
724
844
|
};
|
|
725
|
-
|
|
845
|
+
dispatchTableChildren(tblElement, tableOptions);
|
|
726
846
|
if (table.rows.length === 0) return;
|
|
847
|
+
if (preservedChildren.length > 0) table.preserved = { children: preservedChildren };
|
|
727
848
|
inferImplicitSingleCellRowSpans(table, rowsWithGridOffsets);
|
|
728
849
|
return table;
|
|
729
850
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { document_d_exports } from "../types/document.js";
|
|
2
2
|
import { NumberingMap } from "./numberingParser.js";
|
|
3
|
-
import { StyleMap } from "./styleParser.js";
|
|
4
3
|
import { XmlElement } from "./xmlParser.js";
|
|
4
|
+
import { StyleMap } from "./styleParser.js";
|
|
5
5
|
//#region src/docx/textBoxParser.d.ts
|
|
6
6
|
/**
|
|
7
7
|
* Extract raw paragraph elements from w:txbxContent
|
|
@@ -112,5 +112,28 @@ declare function resolveTextBoxOutlineColor(textBox: document_d_exports.TextBox)
|
|
|
112
112
|
* Get outline width in pixels
|
|
113
113
|
*/
|
|
114
114
|
declare function getTextBoxOutlineWidthPx(textBox: document_d_exports.TextBox): number;
|
|
115
|
+
type TextBoxRunScan = {
|
|
116
|
+
textBoxDrawings: XmlElement[];
|
|
117
|
+
vmlTextBoxes: XmlElement[];
|
|
118
|
+
hasNonTextBoxContent: boolean;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* What a run's markup holds for the text-box pass, by kind.
|
|
122
|
+
*
|
|
123
|
+
* Two readers need this answer and they must not drift: the enrichment pass
|
|
124
|
+
* claims these elements, and `parseParagraphContents` has to keep the run they
|
|
125
|
+
* sit in even though the run parses to nothing until the pass fills it. It
|
|
126
|
+
* lives here, with `isTextBoxDrawing` and `parseTextBox`, so there is one.
|
|
127
|
+
*/
|
|
128
|
+
type ScanRunForTextBoxDrawingsOptions = {
|
|
129
|
+
xmlRun: XmlElement;
|
|
130
|
+
/**
|
|
131
|
+
* `isVmlPictParsedByRunParser`, passed rather than imported: the run parser
|
|
132
|
+
* reaches this module through the image parsers, so reading it from here
|
|
133
|
+
* would close a cycle.
|
|
134
|
+
*/
|
|
135
|
+
claimedByRunParser: (pictElement: XmlElement) => boolean;
|
|
136
|
+
};
|
|
137
|
+
declare const scanRunForTextBoxDrawings: ({ xmlRun, claimedByRunParser }: ScanRunForTextBoxDrawingsOptions) => TextBoxRunScan;
|
|
115
138
|
//#endregion
|
|
116
|
-
export { ParagraphParserFn, TableParserFn, extractTextBoxContentElements, getTextBoxContentElement, getTextBoxDimensionsPx, getTextBoxHeightPx, getTextBoxMarginsPx, getTextBoxOutlineWidthPx, getTextBoxText, getTextBoxWidthPx, hasTextBoxContent, hasTextBoxFill, hasTextBoxOutline, isFloatingTextBox, isShapeTextBox, isTextBoxDrawing, parseTextBox, parseTextBoxContent, parseTextBoxFromShape, resolveTextBoxFillColor, resolveTextBoxOutlineColor };
|
|
139
|
+
export { ParagraphParserFn, ScanRunForTextBoxDrawingsOptions, TableParserFn, TextBoxRunScan, extractTextBoxContentElements, getTextBoxContentElement, getTextBoxDimensionsPx, getTextBoxHeightPx, getTextBoxMarginsPx, getTextBoxOutlineWidthPx, getTextBoxText, getTextBoxWidthPx, hasTextBoxContent, hasTextBoxFill, hasTextBoxOutline, isFloatingTextBox, isShapeTextBox, isTextBoxDrawing, parseTextBox, parseTextBoxContent, parseTextBoxFromShape, resolveTextBoxFillColor, resolveTextBoxOutlineColor, scanRunForTextBoxDrawings };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { emuToPixels } from "../utils/units.js";
|
|
2
2
|
import { parseAnchorPosition, parseAnchorWrap, parseFill, parseOutline, resolveColorValueToHex } from "./drawingUtils.js";
|
|
3
3
|
import { parseNonVisualDrawingNames } from "./nonVisualDrawingProps.js";
|
|
4
|
-
import { findByFullName, findChildByLocalName, findChildByNamespaceUri, findChildrenByLocalName, findChildrenByNamespaceUri, getAttribute, getChildElements, parseNumericAttribute, parseOnOffAttribute } from "./xmlParser.js";
|
|
4
|
+
import { findByFullName, findChildByLocalName, findChildByNamespaceUri, findChildrenByLocalName, findChildrenByNamespaceUri, findDeep, getAttribute, getChildElements, getLocalName, parseNumericAttribute, parseOnOffAttribute } from "./xmlParser.js";
|
|
5
5
|
//#region src/docx/textBoxParser.ts
|
|
6
6
|
const DRAWINGML_MAIN_NAMESPACE_URIS = /* @__PURE__ */ new Set(["http://schemas.openxmlformats.org/drawingml/2006/main", "http://purl.oclc.org/ooxml/drawingml/main"]);
|
|
7
7
|
const WORDPROCESSING_SHAPE_NAMESPACE_URIS = /* @__PURE__ */ new Set(["http://schemas.microsoft.com/office/word/2010/wordprocessingShape"]);
|
|
@@ -290,6 +290,7 @@ const getTextBoxBlockText = (block) => {
|
|
|
290
290
|
return runTexts.join("");
|
|
291
291
|
}
|
|
292
292
|
if (block.type === "table") return block.rows.map((row) => row.cells.map((cell) => cell.content.map(getTextBoxBlockText).join("\n")).join(" ")).join("\n");
|
|
293
|
+
if (block.type === "preservedBlock") return "";
|
|
293
294
|
return block.content.map(getTextBoxBlockText).join("\n");
|
|
294
295
|
};
|
|
295
296
|
/**
|
|
@@ -313,5 +314,54 @@ function getTextBoxOutlineWidthPx(textBox) {
|
|
|
313
314
|
if (!textBox.outline?.width) return 0;
|
|
314
315
|
return emuToPixels(textBox.outline.width);
|
|
315
316
|
}
|
|
317
|
+
const scanRunForTextBoxDrawings = ({ xmlRun, claimedByRunParser }) => {
|
|
318
|
+
const textBoxDrawings = [];
|
|
319
|
+
const vmlTextBoxes = [];
|
|
320
|
+
let hasNonTextBoxContent = false;
|
|
321
|
+
const visitDrawing = (drawingEl) => {
|
|
322
|
+
if (isTextBoxDrawing(drawingEl)) {
|
|
323
|
+
textBoxDrawings.push(drawingEl);
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
hasNonTextBoxContent = true;
|
|
327
|
+
};
|
|
328
|
+
for (const el of getChildElements(xmlRun)) {
|
|
329
|
+
const name = getLocalName(el.name ?? "");
|
|
330
|
+
if (name === "rPr") continue;
|
|
331
|
+
if (name === "drawing") {
|
|
332
|
+
visitDrawing(el);
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
if (name === "pict") {
|
|
336
|
+
if (findDeep(el, "v", "textbox") && !claimedByRunParser(el)) vmlTextBoxes.push(el);
|
|
337
|
+
else hasNonTextBoxContent = true;
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
if (name === "AlternateContent") {
|
|
341
|
+
const branches = getChildElements(el);
|
|
342
|
+
const choice = branches.find((branch) => getLocalName(branch.name ?? "") === "Choice");
|
|
343
|
+
const fallback = branches.find((branch) => getLocalName(branch.name ?? "") === "Fallback");
|
|
344
|
+
const tryBranch = (branch) => {
|
|
345
|
+
if (!branch) return false;
|
|
346
|
+
let found = false;
|
|
347
|
+
for (const innerEl of getChildElements(branch)) if (getLocalName(innerEl.name ?? "") === "drawing") {
|
|
348
|
+
visitDrawing(innerEl);
|
|
349
|
+
found = true;
|
|
350
|
+
}
|
|
351
|
+
return found;
|
|
352
|
+
};
|
|
353
|
+
let foundInBranch = tryBranch(choice);
|
|
354
|
+
if (!foundInBranch) foundInBranch = tryBranch(fallback);
|
|
355
|
+
if (!foundInBranch) hasNonTextBoxContent = true;
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
hasNonTextBoxContent = true;
|
|
359
|
+
}
|
|
360
|
+
return {
|
|
361
|
+
textBoxDrawings,
|
|
362
|
+
vmlTextBoxes,
|
|
363
|
+
hasNonTextBoxContent
|
|
364
|
+
};
|
|
365
|
+
};
|
|
316
366
|
//#endregion
|
|
317
|
-
export { extractTextBoxContentElements, getTextBoxContentElement, getTextBoxDimensionsPx, getTextBoxHeightPx, getTextBoxMarginsPx, getTextBoxOutlineWidthPx, getTextBoxText, getTextBoxWidthPx, hasTextBoxContent, hasTextBoxFill, hasTextBoxOutline, isFloatingTextBox, isShapeTextBox, isTextBoxDrawing, parseTextBox, parseTextBoxContent, parseTextBoxFromShape, resolveTextBoxFillColor, resolveTextBoxOutlineColor };
|
|
367
|
+
export { extractTextBoxContentElements, getTextBoxContentElement, getTextBoxDimensionsPx, getTextBoxHeightPx, getTextBoxMarginsPx, getTextBoxOutlineWidthPx, getTextBoxText, getTextBoxWidthPx, hasTextBoxContent, hasTextBoxFill, hasTextBoxOutline, isFloatingTextBox, isShapeTextBox, isTextBoxDrawing, parseTextBox, parseTextBoxContent, parseTextBoxFromShape, resolveTextBoxFillColor, resolveTextBoxOutlineColor, scanRunForTextBoxDrawings };
|
package/dist/docx/unzip.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { bytesToDataUrl } from "../utils/base64.js";
|
|
2
2
|
import { DOCX_CONTAINER_TYPES, detectDocxContainerType } from "./encryption/containerFormat.js";
|
|
3
3
|
import { openDocxBuffer } from "./encryption/openEncryptedDocx.js";
|
|
4
|
+
import { decodeXmlBytes } from "./xmlEncoding.js";
|
|
4
5
|
import { FOLIO_XML_RESOURCE_LIMITS, assertXmlResourceLimits, createXmlPackageBudget } from "./xmlResourceLimits.js";
|
|
5
6
|
import JSZip from "jszip";
|
|
6
7
|
//#region src/docx/unzip.ts
|
|
@@ -161,13 +162,13 @@ async function unzipDocx(buffer, options = {}) {
|
|
|
161
162
|
if (lowerPath.endsWith(".xml") || lowerPath.endsWith(".rels")) {
|
|
162
163
|
assertEntrySize(path, declaredSize, limits.maxXmlBytes);
|
|
163
164
|
if (options.extractAllXml === false && !shouldExtractXmlPart(lowerPath)) continue;
|
|
164
|
-
extractionTasks.push(() => file.async("
|
|
165
|
-
assertExtractedSize(path,
|
|
165
|
+
extractionTasks.push(() => file.async("uint8array").then((xmlBytes) => {
|
|
166
|
+
assertExtractedSize(path, xmlBytes.byteLength, limits.maxXmlBytes);
|
|
166
167
|
return {
|
|
167
168
|
type: "xml",
|
|
168
169
|
path,
|
|
169
170
|
lowerPath,
|
|
170
|
-
content:
|
|
171
|
+
content: decodeXmlBytes(xmlBytes)
|
|
171
172
|
};
|
|
172
173
|
}));
|
|
173
174
|
} else if (lowerPath.startsWith("word/media/")) {
|
|
@@ -456,7 +457,7 @@ function extractFile(content, path) {
|
|
|
456
457
|
const file = content.originalZip.file(path);
|
|
457
458
|
if (!file || !isParsedDocxEntry(path)) return Promise.resolve(null);
|
|
458
459
|
const lowerPath = path.toLowerCase();
|
|
459
|
-
if (lowerPath.endsWith(".xml") || lowerPath.endsWith(".rels")) return file.async("
|
|
460
|
+
if (lowerPath.endsWith(".xml") || lowerPath.endsWith(".rels")) return file.async("uint8array").then(decodeXmlBytes);
|
|
460
461
|
return file.async("arraybuffer");
|
|
461
462
|
}
|
|
462
463
|
/**
|
|
@@ -11,6 +11,22 @@ import { XmlElement } from "./xmlParser.js";
|
|
|
11
11
|
* same artwork twice.
|
|
12
12
|
*/
|
|
13
13
|
declare function shouldPreserveRawVmlPict(pictElement: XmlElement): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Whether the run parser turns this `w:pict` into run content of its own.
|
|
16
|
+
*
|
|
17
|
+
* Exactly one owner may represent a `w:pict`: the run parser, whose drawing
|
|
18
|
+
* carries the whole element as captured XML, or the text-box enrichment pass,
|
|
19
|
+
* which rebuilds one `v:textbox` as an editable shape. Two owners write the
|
|
20
|
+
* same artwork twice, and when the pict holds text, the saved document says it
|
|
21
|
+
* twice.
|
|
22
|
+
*
|
|
23
|
+
* The enrichment asks this rather than re-deriving the answer from the markup:
|
|
24
|
+
* its own reading (`v:imagedata` present) named only the picture path, so a
|
|
25
|
+
* `v:group` claimed by the preview path was represented by both owners. The
|
|
26
|
+
* result is a pure function of the element, so asking it a second time costs
|
|
27
|
+
* only the work the run parser already did.
|
|
28
|
+
*/
|
|
29
|
+
declare const isVmlPictParsedByRunParser: (pictElement: XmlElement, rels: document_d_exports.RelationshipMap | null, media: Map<string, document_d_exports.MediaFile> | null) => boolean;
|
|
14
30
|
/**
|
|
15
31
|
* Parse a `w:pict` element into an inline image, or null when it carries no
|
|
16
32
|
* ordinary VML picture (no resolvable `<v:imagedata>`, or a watermark shape).
|
|
@@ -22,4 +38,4 @@ declare function shouldPreserveRawVmlPict(pictElement: XmlElement): boolean;
|
|
|
22
38
|
*/
|
|
23
39
|
declare function parseVmlImageContent(pictElement: XmlElement, rels: document_d_exports.RelationshipMap | null, media: Map<string, document_d_exports.MediaFile> | null, rootXmlns?: Record<string, string>): document_d_exports.DrawingContent | null;
|
|
24
40
|
//#endregion
|
|
25
|
-
export { parseVmlImageContent, shouldPreserveRawVmlPict };
|
|
41
|
+
export { isVmlPictParsedByRunParser, parseVmlImageContent, shouldPreserveRawVmlPict };
|
|
@@ -131,6 +131,22 @@ function shouldPreserveRawVmlPict(pictElement) {
|
|
|
131
131
|
return shapes.length > 0 && !shapes.some((shape) => isWatermarkShape(shape));
|
|
132
132
|
}
|
|
133
133
|
/**
|
|
134
|
+
* Whether the run parser turns this `w:pict` into run content of its own.
|
|
135
|
+
*
|
|
136
|
+
* Exactly one owner may represent a `w:pict`: the run parser, whose drawing
|
|
137
|
+
* carries the whole element as captured XML, or the text-box enrichment pass,
|
|
138
|
+
* which rebuilds one `v:textbox` as an editable shape. Two owners write the
|
|
139
|
+
* same artwork twice, and when the pict holds text, the saved document says it
|
|
140
|
+
* twice.
|
|
141
|
+
*
|
|
142
|
+
* The enrichment asks this rather than re-deriving the answer from the markup:
|
|
143
|
+
* its own reading (`v:imagedata` present) named only the picture path, so a
|
|
144
|
+
* `v:group` claimed by the preview path was represented by both owners. The
|
|
145
|
+
* result is a pure function of the element, so asking it a second time costs
|
|
146
|
+
* only the work the run parser already did.
|
|
147
|
+
*/
|
|
148
|
+
const isVmlPictParsedByRunParser = (pictElement, rels, media) => parseVmlImageContent(pictElement, rels, media) !== null || shouldPreserveRawVmlPict(pictElement);
|
|
149
|
+
/**
|
|
134
150
|
* Read the relationship id off a `v:imagedata` element. Word writes `r:id`;
|
|
135
151
|
* some legacy / third-party generators use `r:embed` or the office-namespace
|
|
136
152
|
* `o:relid` instead, so fall back through those before the bare `id`.
|
|
@@ -201,4 +217,4 @@ function parseVmlImageContent(pictElement, rels, media, rootXmlns = {}) {
|
|
|
201
217
|
return null;
|
|
202
218
|
}
|
|
203
219
|
//#endregion
|
|
204
|
-
export { parseVmlImageContent, shouldPreserveRawVmlPict };
|
|
220
|
+
export { isVmlPictParsedByRunParser, parseVmlImageContent, shouldPreserveRawVmlPict };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/docx/xmlEncoding.ts
|
|
2
|
+
/** Decode the UTF-8 and UTF-16 encodings XML processors must recognize. */
|
|
3
|
+
const decodeXmlBytes = (bytes) => {
|
|
4
|
+
if (bytes[0] === 255 && bytes[1] === 254) return new TextDecoder("utf-16le").decode(bytes.subarray(2));
|
|
5
|
+
if (bytes[0] === 254 && bytes[1] === 255) return new TextDecoder("utf-16be").decode(bytes.subarray(2));
|
|
6
|
+
if (bytes[0] === 60 && bytes[1] === 0 && bytes[2] === 63 && bytes[3] === 0) return new TextDecoder("utf-16le").decode(bytes);
|
|
7
|
+
if (bytes[0] === 0 && bytes[1] === 60 && bytes[2] === 0 && bytes[3] === 63) return new TextDecoder("utf-16be").decode(bytes);
|
|
8
|
+
const utf8Offset = bytes[0] === 239 && bytes[1] === 187 && bytes[2] === 191 ? 3 : 0;
|
|
9
|
+
return new TextDecoder("utf-8").decode(bytes.subarray(utf8Offset));
|
|
10
|
+
};
|
|
11
|
+
//#endregion
|
|
12
|
+
export { decodeXmlBytes };
|
package/dist/docx/xmlParser.d.ts
CHANGED
|
@@ -105,6 +105,15 @@ declare function getLocalName(name: string | undefined): string;
|
|
|
105
105
|
declare function getNamespacePrefix(name: string): string | null;
|
|
106
106
|
/** Namespace URI resolved from the element's in-scope XML declarations. */
|
|
107
107
|
declare const getNamespaceUri: (element: XmlElement) => string | undefined;
|
|
108
|
+
/**
|
|
109
|
+
* Namespace URI of one of the element's attributes, by its source spelling.
|
|
110
|
+
*
|
|
111
|
+
* An unprefixed attribute has no namespace — it is not in the element's,
|
|
112
|
+
* which is why this is not {@link getNamespaceUri} with a different argument —
|
|
113
|
+
* and `undefined` is that answer as well as "the prefix resolves to nothing".
|
|
114
|
+
* A caller that must tell the two apart checks the spelling for a colon.
|
|
115
|
+
*/
|
|
116
|
+
declare const resolveAttributeNamespaceUri: (element: XmlElement, attributeName: string) => string | undefined;
|
|
108
117
|
/** WordprocessingML main namespace, Transitional and Strict (ECMA-376 Parts 1 and 4). */
|
|
109
118
|
declare const WORDPROCESSINGML_NAMESPACE_URIS: ReadonlySet<string>;
|
|
110
119
|
/** Office document relationship attributes, Transitional and Strict. */
|
|
@@ -383,4 +392,4 @@ declare function cloneWithXmlnsDeclarations(element: XmlElement, xmlnsDecls: Rec
|
|
|
383
392
|
*/
|
|
384
393
|
declare function cloneElement(element: XmlElement, overrides: Partial<XmlElement>): XmlElement;
|
|
385
394
|
//#endregion
|
|
386
|
-
export { NAMESPACES, OFFICE_RELATIONSHIP_NAMESPACE_URIS, OOXML_NAMESPACE_SCOPE, WORDPROCESSINGML_NAMESPACE_URIS, XmlAttributeMatch, XmlElement, XmlNamespaceScope, attachXmlNamespaceContext, cloneElement, cloneWithXmlnsDeclarations, collectXmlnsDeclarations, elementToXml, findAllDeep, findAttributeByNamespaceUri, findByFullName, findChild, findChildByLocalName, findChildByNamespaceUri, findChildren, findChildrenByLocalName, findChildrenByNamespaceUri, findDeep, getAttribute, getAttributeAny, getAttributeAnyPrefix, getAttributeByNamespaceUri, getAttributes, getChildElements, getLocalName, getNamespacePrefix, getNamespaceUri, getTextContent, hasChild, matchesName, mergeXmlnsDeclarations, parseBooleanElement, parseColorElement, parseNumberingLevelAttribute, parseNumericAttribute, parseOnOffAttribute, parseOnOffValue, parseTableMeasurementValue, parseXml, parseXmlDocument, selectAlternateContentBranch };
|
|
395
|
+
export { NAMESPACES, OFFICE_RELATIONSHIP_NAMESPACE_URIS, OOXML_NAMESPACE_SCOPE, WORDPROCESSINGML_NAMESPACE_URIS, XmlAttributeMatch, XmlElement, XmlNamespaceScope, attachXmlNamespaceContext, cloneElement, cloneWithXmlnsDeclarations, collectXmlnsDeclarations, elementToXml, findAllDeep, findAttributeByNamespaceUri, findByFullName, findChild, findChildByLocalName, findChildByNamespaceUri, findChildren, findChildrenByLocalName, findChildrenByNamespaceUri, findDeep, getAttribute, getAttributeAny, getAttributeAnyPrefix, getAttributeByNamespaceUri, getAttributes, getChildElements, getLocalName, getNamespacePrefix, getNamespaceUri, getTextContent, hasChild, matchesName, mergeXmlnsDeclarations, parseBooleanElement, parseColorElement, parseNumberingLevelAttribute, parseNumericAttribute, parseOnOffAttribute, parseOnOffValue, parseTableMeasurementValue, parseXml, parseXmlDocument, resolveAttributeNamespaceUri, selectAlternateContentBranch };
|
package/dist/docx/xmlParser.js
CHANGED
|
@@ -246,6 +246,19 @@ function getNamespacePrefix(name) {
|
|
|
246
246
|
}
|
|
247
247
|
/** Namespace URI resolved from the element's in-scope XML declarations. */
|
|
248
248
|
const getNamespaceUri = (element) => element.namespaceUri;
|
|
249
|
+
/**
|
|
250
|
+
* Namespace URI of one of the element's attributes, by its source spelling.
|
|
251
|
+
*
|
|
252
|
+
* An unprefixed attribute has no namespace — it is not in the element's,
|
|
253
|
+
* which is why this is not {@link getNamespaceUri} with a different argument —
|
|
254
|
+
* and `undefined` is that answer as well as "the prefix resolves to nothing".
|
|
255
|
+
* A caller that must tell the two apart checks the spelling for a colon.
|
|
256
|
+
*/
|
|
257
|
+
const resolveAttributeNamespaceUri = (element, attributeName) => {
|
|
258
|
+
const colonIndex = attributeName.indexOf(":");
|
|
259
|
+
if (colonIndex === -1) return;
|
|
260
|
+
return resolveNamespaceUri(element.namespaceScope, attributeName.slice(0, colonIndex));
|
|
261
|
+
};
|
|
249
262
|
/** WordprocessingML main namespace, Transitional and Strict (ECMA-376 Parts 1 and 4). */
|
|
250
263
|
const WORDPROCESSINGML_NAMESPACE_URIS = /* @__PURE__ */ new Set([NAMESPACES.w, "http://purl.oclc.org/ooxml/wordprocessingml/main"]);
|
|
251
264
|
/** Office document relationship attributes, Transitional and Strict. */
|
|
@@ -855,4 +868,4 @@ function cloneElement(element, overrides) {
|
|
|
855
868
|
return clone;
|
|
856
869
|
}
|
|
857
870
|
//#endregion
|
|
858
|
-
export { NAMESPACES, OFFICE_RELATIONSHIP_NAMESPACE_URIS, OOXML_NAMESPACE_SCOPE, WORDPROCESSINGML_NAMESPACE_URIS, attachXmlNamespaceContext, cloneElement, cloneWithXmlnsDeclarations, collectXmlnsDeclarations, elementToXml, findAllDeep, findAttributeByNamespaceUri, findByFullName, findChild, findChildByLocalName, findChildByNamespaceUri, findChildren, findChildrenByLocalName, findChildrenByNamespaceUri, findDeep, getAttribute, getAttributeAny, getAttributeAnyPrefix, getAttributeByNamespaceUri, getAttributes, getChildElements, getLocalName, getNamespacePrefix, getNamespaceUri, getTextContent, hasChild, matchesName, mergeXmlnsDeclarations, parseBooleanElement, parseColorElement, parseNumberingLevelAttribute, parseNumericAttribute, parseOnOffAttribute, parseOnOffValue, parseTableMeasurementValue, parseXml, parseXmlDocument, selectAlternateContentBranch };
|
|
871
|
+
export { NAMESPACES, OFFICE_RELATIONSHIP_NAMESPACE_URIS, OOXML_NAMESPACE_SCOPE, WORDPROCESSINGML_NAMESPACE_URIS, attachXmlNamespaceContext, cloneElement, cloneWithXmlnsDeclarations, collectXmlnsDeclarations, elementToXml, findAllDeep, findAttributeByNamespaceUri, findByFullName, findChild, findChildByLocalName, findChildByNamespaceUri, findChildren, findChildrenByLocalName, findChildrenByNamespaceUri, findDeep, getAttribute, getAttributeAny, getAttributeAnyPrefix, getAttributeByNamespaceUri, getAttributes, getChildElements, getLocalName, getNamespacePrefix, getNamespaceUri, getTextContent, hasChild, matchesName, mergeXmlnsDeclarations, parseBooleanElement, parseColorElement, parseNumberingLevelAttribute, parseNumericAttribute, parseOnOffAttribute, parseOnOffValue, parseTableMeasurementValue, parseXml, parseXmlDocument, resolveAttributeNamespaceUri, selectAlternateContentBranch };
|
package/dist/headless-layout.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { resolveDocumentGridLinePitch } from "./docx/documentGrid.js";
|
|
2
2
|
import { formatOoxmlCounter } from "./docx/ooxmlCounterFormatter.js";
|
|
3
|
+
import { createParseWarningCollector } from "./docx/parseContext.js";
|
|
4
|
+
import { formatParseWarnings } from "./docx/parseWarningMessage.js";
|
|
3
5
|
import { parseDocx } from "./docx/parser.js";
|
|
4
6
|
import { buildHeaderFooterFieldValues } from "./fields/resolveFieldValues.js";
|
|
5
7
|
import { extractEmbeddedFonts } from "./fonts/embeddedFonts.js";
|
|
@@ -209,14 +211,21 @@ const layoutDocxHeadless = async (input, options = {}) => {
|
|
|
209
211
|
});
|
|
210
212
|
if (parsed.isErr()) return Result.err(parsed.error);
|
|
211
213
|
const document = parsed.value;
|
|
214
|
+
const { context: projectionContext, warnings: projectionWarnings } = createParseWarningCollector("word/document.xml");
|
|
212
215
|
const projected = Result.try(() => toProseDoc(document, {
|
|
213
216
|
...document.package.styles ? { styles: document.package.styles } : {},
|
|
214
|
-
...document.package.theme ? { theme: document.package.theme } : {}
|
|
217
|
+
...document.package.theme ? { theme: document.package.theme } : {},
|
|
218
|
+
warn: projectionContext.warn
|
|
215
219
|
}));
|
|
216
220
|
if (projected.isErr()) return Result.err(new HeadlessLayoutError({
|
|
217
221
|
message: "The document could not be projected to the editable model.",
|
|
218
222
|
cause: projected.error
|
|
219
223
|
}));
|
|
224
|
+
const recorded = projectionWarnings();
|
|
225
|
+
if (recorded.length > 0) {
|
|
226
|
+
document.parseWarnings = [...document.parseWarnings ?? [], ...recorded];
|
|
227
|
+
document.warnings = [...document.warnings ?? [], ...formatParseWarnings(recorded)];
|
|
228
|
+
}
|
|
220
229
|
if (packageNeedsShaping(document.package)) {
|
|
221
230
|
const loaded = await Result.tryPromise({
|
|
222
231
|
try: () => getShaper(),
|