@stll/folio-core 0.11.0 → 0.13.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.d.ts +2 -1
- package/dist/ai-edits/apply.js +693 -63
- package/dist/ai-edits/block-identity.d.ts +4 -0
- package/dist/ai-edits/block-identity.js +9 -0
- package/dist/ai-edits/blockRange.d.ts +28 -1
- package/dist/ai-edits/blockRange.js +68 -2
- package/dist/ai-edits/clean-text.js +2 -1
- package/dist/ai-edits/headless.d.ts +4 -4
- package/dist/ai-edits/headless.js +9 -9
- package/dist/ai-edits/index.d.ts +2 -2
- package/dist/ai-edits/index.js +2 -2
- package/dist/ai-edits/read.d.ts +7 -7
- package/dist/ai-edits/read.js +110 -3
- package/dist/ai-edits/snapshot.js +21 -3
- package/dist/ai-edits/table-cell-mutations.d.ts +48 -0
- package/dist/ai-edits/table-cell-mutations.js +238 -0
- package/dist/ai-edits/table-mutation-plan.d.ts +38 -0
- package/dist/ai-edits/table-mutation-plan.js +90 -0
- package/dist/ai-edits/table-row-column-mutations.d.ts +108 -0
- package/dist/ai-edits/table-row-column-mutations.js +300 -0
- package/dist/ai-edits/table-targets.d.ts +32 -0
- package/dist/ai-edits/table-targets.js +70 -0
- package/dist/ai-edits/types.d.ts +62 -1
- package/dist/ai-edits/word-diff.js +21 -0
- package/dist/compat/eigenpal.d.ts +3 -3
- package/dist/compat/eigenpal.js +3 -3
- package/dist/content-controls/mutateContentControls.js +1 -1
- package/dist/controller/activeEditorStory.d.ts +36 -0
- package/dist/controller/activeEditorStory.js +30 -0
- package/dist/controller/contentControlWidgetController.d.ts +55 -0
- package/dist/controller/contentControlWidgetController.js +141 -0
- package/dist/controller/fontReadiness.js +2 -0
- package/dist/controller/headerFooterEditorManager.js +2 -2
- package/dist/controller/hiddenEditorApi.js +2 -2
- package/dist/controller/hiddenEditorManager.d.ts +12 -1
- package/dist/controller/hiddenEditorManager.js +44 -12
- package/dist/controller/layoutPipeline.d.ts +2 -0
- package/dist/controller/layoutPipeline.js +17 -2
- package/dist/controller/noteEditorManager.d.ts +36 -0
- package/dist/controller/noteEditorManager.js +210 -0
- package/dist/document-operations.d.ts +43 -11
- package/dist/document-operations.js +186 -18
- package/dist/docx/blockContentParser.js +21 -7
- package/dist/docx/commentParser.js +6 -1
- package/dist/docx/commentRangeIntegrity.d.ts +6 -0
- package/dist/docx/commentRangeIntegrity.js +186 -0
- package/dist/docx/conformance.js +62 -1
- package/dist/docx/documentGrid.d.ts +8 -0
- package/dist/docx/documentGrid.js +8 -0
- package/dist/docx/drawingUtils.js +1 -1
- package/dist/docx/encryption/agileDecryption.js +12 -2
- package/dist/docx/encryption/compoundFile.js +6 -1
- package/dist/docx/encryption/encryptionInfo.d.ts +9 -1
- package/dist/docx/encryption/encryptionInfo.js +18 -2
- package/dist/docx/encryption/openEncryptedDocx.js +1 -1
- package/dist/docx/ensureParaIds.js +8 -7
- package/dist/docx/fieldParser.js +1 -1
- package/dist/docx/groupDrawingParser.js +10 -5
- package/dist/docx/hyperlinkParser.js +1 -1
- package/dist/docx/imageParser.js +10 -6
- package/dist/docx/metadataPrivacy.js +17 -3
- package/dist/docx/notePropertiesParser.js +1 -1
- package/dist/docx/numberingParser.js +1 -1
- package/dist/docx/paragraphParser.js +70 -61
- package/dist/docx/paragraphTextBoxEnrichment.d.ts +2 -1
- package/dist/docx/paragraphTextBoxEnrichment.js +67 -13
- package/dist/docx/paragraphTraversal.js +1 -1
- package/dist/docx/parser.js +3 -3
- package/dist/docx/rezip.js +20 -9
- package/dist/docx/runParser.js +17 -6
- package/dist/docx/sdtProperties.js +1 -1
- package/dist/docx/sectionParser.js +18 -5
- package/dist/docx/selectiveSave.js +5 -1
- package/dist/docx/selectiveXmlPatch.d.ts +22 -1
- package/dist/docx/selectiveXmlPatch.js +61 -1
- package/dist/docx/serializer/blockSdtSerializer.js +3 -2
- package/dist/docx/serializer/commentSerializer.js +5 -6
- package/dist/docx/serializer/documentSerializer.js +2 -2
- package/dist/docx/serializer/headerFooterSerializer.js +2 -2
- package/dist/docx/serializer/noteSerializer.js +2 -2
- package/dist/docx/serializer/paragraphSerializer.js +23 -15
- package/dist/docx/serializer/runSerializer.js +25 -21
- package/dist/docx/serializer/sectionPropertiesSerializer.js +2 -1
- package/dist/docx/serializer/stylesSerializer.js +1 -1
- package/dist/docx/serializer/tableSerializer.d.ts +5 -4
- package/dist/docx/serializer/tableSerializer.js +26 -20
- package/dist/docx/serializer/xmlUtils.d.ts +13 -1
- package/dist/docx/serializer/xmlUtils.js +27 -1
- package/dist/docx/server/applyDocxXmlPatchProposal.d.ts +87 -0
- package/dist/docx/server/applyDocxXmlPatchProposal.js +204 -0
- package/dist/docx/server/boundedArchive.d.ts +14 -3
- package/dist/docx/server/boundedArchive.js +56 -11
- package/dist/docx/server/evaluateDocxXmlPatchProposal.d.ts +85 -0
- package/dist/docx/server/evaluateDocxXmlPatchProposal.js +361 -0
- package/dist/docx/server/extractDocxText.js +55 -8
- package/dist/docx/server/inspectDocxPackage.d.ts +70 -0
- package/dist/docx/server/inspectDocxPackage.js +217 -0
- package/dist/docx/server/validateDocxConformance.d.ts +41 -0
- package/dist/docx/server/validateDocxConformance.js +336 -0
- package/dist/docx/settingsParser.js +26 -3
- package/dist/docx/shapeParser.js +1 -1
- package/dist/docx/styleParser.js +4 -2
- package/dist/docx/tableParser.d.ts +8 -1
- package/dist/docx/tableParser.js +31 -10
- package/dist/docx/textBoxParser.d.ts +3 -3
- package/dist/docx/textBoxParser.js +16 -12
- package/dist/docx/unzip.js +1 -0
- package/dist/docx/vmlImageParser.js +11 -3
- package/dist/docx/xmlParser.js +11 -1
- package/dist/docx/xmlSafety.d.ts +5 -0
- package/dist/docx/xmlSafety.js +9 -0
- package/dist/fields/resolveFieldValues.js +1 -3
- package/dist/fonts/embeddedFonts.d.ts +33 -5
- package/dist/fonts/embeddedFonts.js +37 -8
- package/dist/i18n/messages/catalogs.gen.d.ts +17 -0
- package/dist/i18n/messages/catalogs.gen.js +17 -0
- package/dist/i18n/messages/messages.gen.d.ts +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/footnoteLayout.js +47 -40
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/headerFooterLayout.js +3 -0
- package/dist/layout-bridge/convert/templatePreviewFlow.js +3 -3
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +4 -2
- package/dist/layout-bridge/convert/toFlowBlocks.js +151 -20
- package/dist/layout-bridge/dom/noteStoryDom.d.ts +6 -0
- package/dist/layout-bridge/dom/noteStoryDom.js +17 -0
- package/dist/layout-bridge/engine/clickToPosition.js +2 -2
- package/dist/layout-engine/index.d.ts +2 -2
- package/dist/layout-engine/index.js +58 -30
- package/dist/layout-engine/justificationCompatibility.d.ts +6 -0
- package/dist/layout-engine/justificationCompatibility.js +8 -0
- package/dist/layout-engine/keep-together.js +11 -1
- package/dist/layout-engine/measure/cache.js +23 -5
- package/dist/layout-engine/measure/effectiveLineBreakPolicy.js +8 -2
- package/dist/layout-engine/measure/lineBreakProvider.d.ts +2 -2
- package/dist/layout-engine/measure/lineBreakProvider.js +56 -37
- package/dist/layout-engine/measure/measureBlocks.js +15 -4
- package/dist/layout-engine/measure/measureContainer.js +1 -1
- package/dist/layout-engine/measure/measureHelpers.d.ts +11 -2
- package/dist/layout-engine/measure/measureHelpers.js +15 -4
- package/dist/layout-engine/measure/measureParagraph.js +85 -25
- package/dist/layout-engine/measure/measureProvider.js +4 -3
- package/dist/layout-engine/measure/tableCellFlow.js +5 -2
- package/dist/layout-engine/measure/textBoxParagraphLayout.d.ts +9 -7
- package/dist/layout-engine/measure/textBoxParagraphLayout.js +22 -6
- package/dist/layout-engine/measure/textMeasurementPolicy.d.ts +3 -1
- package/dist/layout-engine/measure/textMeasurementPolicy.js +7 -1
- package/dist/layout-engine/paginator.js +5 -1
- package/dist/layout-engine/paragraphSpacing.d.ts +28 -4
- package/dist/layout-engine/paragraphSpacing.js +107 -13
- package/dist/layout-engine/renderedBreakReconciliation.js +1 -1
- package/dist/layout-engine/types.d.ts +48 -15
- package/dist/layout-painter/registry/modules/textBox.js +5 -1
- package/dist/layout-painter/renderImage.d.ts +12 -1
- package/dist/layout-painter/renderImage.js +21 -4
- package/dist/layout-painter/renderPage.d.ts +5 -2
- package/dist/layout-painter/renderPage.js +59 -14
- package/dist/layout-painter/renderParagraph.js +55 -15
- package/dist/layout-painter/renderTable.d.ts +5 -1
- package/dist/layout-painter/renderTable.js +7 -3
- package/dist/layout-painter/renderTextBox.d.ts +2 -1
- package/dist/layout-painter/renderTextBox.js +25 -14
- package/dist/layout-painter/renderWatermark.d.ts +1 -1
- package/dist/layout-painter/renderWatermark.js +2 -1
- package/dist/managers/DocumentLoaderManager.js +1 -1
- package/dist/markdown/fromMarkdown.js +1 -1
- package/dist/model.js +1 -1
- package/dist/prosemirror/attrs/index.d.ts +4 -2
- package/dist/prosemirror/attrs/index.js +175 -18
- package/dist/prosemirror/commands/comments.d.ts +79 -4
- package/dist/prosemirror/commands/comments.js +622 -13
- package/dist/prosemirror/commands/contentControls.js +1 -1
- package/dist/prosemirror/commands/hyperlink.js +15 -1
- package/dist/prosemirror/commands/image.js +7 -1
- package/dist/prosemirror/commands/index.d.ts +2 -2
- package/dist/prosemirror/commands/index.js +2 -2
- package/dist/prosemirror/commands/pageBreak.js +1 -1
- package/dist/prosemirror/commands/propertyChangeScope.d.ts +2 -2
- package/dist/prosemirror/commands/propertyChangeScope.js +3 -2
- package/dist/prosemirror/commands/tableCellMergeResolution.d.ts +9 -0
- package/dist/prosemirror/commands/tableCellMergeResolution.js +181 -0
- package/dist/prosemirror/commentIdAllocator.js +13 -3
- package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +404 -62
- package/dist/prosemirror/conversion/index.js +1 -1
- package/dist/prosemirror/conversion/sdtAttrs.d.ts +9 -0
- package/dist/prosemirror/conversion/sdtAttrs.js +49 -0
- package/dist/prosemirror/conversion/toProseDoc.d.ts +2 -1
- package/dist/prosemirror/conversion/toProseDoc.js +364 -103
- package/dist/prosemirror/extensions/ExtensionManager.js +1 -1
- package/dist/prosemirror/extensions/StarterKit.js +6 -1
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +6 -2
- package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +1 -0
- package/dist/prosemirror/extensions/features/ImagePasteExtension.js +10 -2
- package/dist/prosemirror/extensions/features/ListExtension.js +1 -1
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +10 -1
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +93 -2
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +2 -1
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +6 -2
- package/dist/prosemirror/extensions/features/pasteCleanup.js +15 -2
- package/dist/prosemirror/extensions/marks/CharacterSpacingExtension.js +1 -1
- package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +30 -4
- package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.d.ts +9 -1
- package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +70 -11
- package/dist/prosemirror/extensions/nodes/FieldExtension.js +1 -1
- package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.d.ts +7 -0
- package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.js +22 -0
- package/dist/prosemirror/extensions/nodes/TableExtension.d.ts +1 -1
- package/dist/prosemirror/extensions/nodes/TableExtension.js +14 -6
- package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.d.ts +13 -0
- package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.js +41 -0
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.d.ts +5 -2
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +4 -1
- package/dist/prosemirror/index.d.ts +1 -1
- package/dist/prosemirror/index.js +1 -1
- package/dist/prosemirror/plugins/contentControlWidgets.d.ts +36 -10
- package/dist/prosemirror/plugins/contentControlWidgets.js +128 -94
- package/dist/prosemirror/plugins/revisionIds.d.ts +23 -0
- package/dist/prosemirror/plugins/revisionIds.js +57 -0
- package/dist/prosemirror/plugins/selectionTracker.js +1 -0
- package/dist/prosemirror/plugins/suggestionMode.js +5 -4
- package/dist/prosemirror/runFormattingMarkNames.d.ts +14 -0
- package/dist/prosemirror/runFormattingMarkNames.js +40 -0
- package/dist/prosemirror/schema/index.d.ts +2 -2
- package/dist/prosemirror/schema/marks.d.ts +30 -3
- package/dist/prosemirror/schema/marks.js +15 -0
- package/dist/prosemirror/schema/nodes.d.ts +111 -6
- package/dist/prosemirror/selectionState.js +1 -0
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
- package/dist/prosemirror/tableCellMergeRevision.d.ts +9 -0
- package/dist/prosemirror/tableCellMergeRevision.js +22 -0
- package/dist/prosemirror/textBoxAnchorAttrs.d.ts +9 -0
- package/dist/prosemirror/textBoxAnchorAttrs.js +33 -0
- package/dist/prosemirror/utils/extractTrackedChanges.d.ts +1 -1
- package/dist/prosemirror/utils/extractTrackedChanges.js +62 -14
- package/dist/prosemirror/validation.js +9 -1
- package/dist/render-dom/RemoteSelectionOverlay.js +2 -2
- package/dist/server.d.ts +7 -3
- package/dist/server.js +7 -3
- package/dist/utils/clipboard.d.ts +10 -1
- package/dist/utils/clipboard.js +33 -6
- package/dist/utils/colorResolver.d.ts +8 -1
- package/dist/utils/colorResolver.js +35 -5
- package/dist/utils/fontFamilyMerge.js +9 -11
- package/dist/utils/fontLoader.js +3 -2
- package/dist/utils/fontResolver.d.ts +2 -1
- package/dist/utils/fontResolver.js +31 -7
- package/dist/utils/fontWeights.d.ts +1 -1
- package/dist/utils/fontWeights.js +1 -1
- package/dist/utils/hexId.d.ts +11 -1
- package/dist/utils/hexId.js +11 -1
- package/dist/utils/paragraphFormattingMerge.js +1 -0
- package/dist/utils/sanitizeImageSrc.d.ts +21 -0
- package/dist/utils/sanitizeImageSrc.js +30 -0
- package/dist/utils/stripXmlDeclarations.d.ts +11 -0
- package/dist/utils/stripXmlDeclarations.js +35 -0
- package/dist/version-comparison.d.ts +22 -2
- package/dist/version-comparison.js +41 -12
- package/dist/watermark/index.d.ts +11 -1
- package/dist/watermark/index.js +22 -1
- package/package.json +3 -2
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import { elementToXml, findChild, findChildren, getAttribute, getChildElements, mergeXmlnsDeclarations, parseBooleanElement, parseNumericAttribute } from "./xmlParser.js";
|
|
2
|
-
import { parseBookmarkEnd as parseBookmarkEnd$1, parseBookmarkStart as parseBookmarkStart$1 } from "./bookmarkParser.js";
|
|
3
1
|
import { BorderStyleSchema, FrameWrapSchema, FrameXAlignSchema, FrameYAlignSchema, LineSpacingRuleSchema, ParagraphAlignmentSchema, ShadingPatternSchema, TabLeaderSchema, TabStopAlignmentSchema, ThemeColorSlotSchema, narrowEnum } from "./parserEnums.js";
|
|
2
|
+
import { elementToXml, findChild, findChildren, getAttribute, getChildElements, mergeXmlnsDeclarations, parseBooleanElement, parseNumericAttribute } from "./xmlParser.js";
|
|
4
3
|
import { parseRun, parseRunProperties } from "./runParser.js";
|
|
5
4
|
import { parseFieldType } from "./fieldParser.js";
|
|
5
|
+
import { isValidHexId } from "../utils/hexId.js";
|
|
6
|
+
import { parseBookmarkEnd as parseBookmarkEnd$1, parseBookmarkStart as parseBookmarkStart$1 } from "./bookmarkParser.js";
|
|
6
7
|
import { parseHyperlink as parseHyperlink$1 } from "./hyperlinkParser.js";
|
|
7
8
|
import { consolidateParagraphContent } from "./runConsolidator.js";
|
|
8
9
|
import { parseSdtProperties } from "./sdtProperties.js";
|
|
9
10
|
import { parseSectionProperties } from "./sectionParser.js";
|
|
11
|
+
import { normalizeRevisionId } from "@stll/docx-core/model";
|
|
10
12
|
//#region src/docx/paragraphParser.ts
|
|
11
13
|
/**
|
|
12
14
|
* Extract plain text from a math element (recursive text content extraction)
|
|
@@ -191,6 +193,9 @@ function collectFirstParagraphPropertyChildren(pPr) {
|
|
|
191
193
|
case "shd":
|
|
192
194
|
children.shd ??= child;
|
|
193
195
|
break;
|
|
196
|
+
case "snapToGrid":
|
|
197
|
+
children.snapToGrid ??= child;
|
|
198
|
+
break;
|
|
194
199
|
case "spacing":
|
|
195
200
|
children.spacing ??= child;
|
|
196
201
|
break;
|
|
@@ -243,6 +248,8 @@ function parseParagraphProperties(pPr, theme, styles) {
|
|
|
243
248
|
}
|
|
244
249
|
const bidi = propertyChildren.bidi;
|
|
245
250
|
if (bidi) formatting.bidi = parseBooleanElement(bidi);
|
|
251
|
+
const snapToGrid = propertyChildren.snapToGrid;
|
|
252
|
+
if (snapToGrid) formatting.snapToGrid = parseBooleanElement(snapToGrid);
|
|
246
253
|
const spacing = propertyChildren.spacing;
|
|
247
254
|
if (spacing) {
|
|
248
255
|
const before = parseNumericAttribute(spacing, "w", "before");
|
|
@@ -369,64 +376,64 @@ function getLocalName(name) {
|
|
|
369
376
|
const colonIndex = name.indexOf(":");
|
|
370
377
|
return colonIndex !== -1 ? name.slice(colonIndex + 1) : name;
|
|
371
378
|
}
|
|
379
|
+
const RENDERED_BREAK_INLINE_WRAPPERS = /* @__PURE__ */ new Set([
|
|
380
|
+
"hyperlink",
|
|
381
|
+
"smartTag",
|
|
382
|
+
"sdt",
|
|
383
|
+
"sdtContent",
|
|
384
|
+
"fldSimple",
|
|
385
|
+
"customXml",
|
|
386
|
+
"ins",
|
|
387
|
+
"del",
|
|
388
|
+
"moveFrom",
|
|
389
|
+
"moveTo"
|
|
390
|
+
]);
|
|
391
|
+
const RENDERED_BREAK_NON_CONTENT_MARKERS = /* @__PURE__ */ new Set([
|
|
392
|
+
"pPr",
|
|
393
|
+
"proofErr",
|
|
394
|
+
"bookmarkStart",
|
|
395
|
+
"bookmarkEnd",
|
|
396
|
+
"commentRangeStart",
|
|
397
|
+
"commentRangeEnd",
|
|
398
|
+
"commentReference",
|
|
399
|
+
"permStart",
|
|
400
|
+
"permEnd",
|
|
401
|
+
"rsidR"
|
|
402
|
+
]);
|
|
403
|
+
const RENDERED_BREAK_VISIBLE_RUN_CONTENT = /* @__PURE__ */ new Set([
|
|
404
|
+
"t",
|
|
405
|
+
"tab",
|
|
406
|
+
"br",
|
|
407
|
+
"cr",
|
|
408
|
+
"sym",
|
|
409
|
+
"drawing",
|
|
410
|
+
"pict",
|
|
411
|
+
"object",
|
|
412
|
+
"softHyphen",
|
|
413
|
+
"noBreakHyphen",
|
|
414
|
+
"fldChar",
|
|
415
|
+
"instrText",
|
|
416
|
+
"pgNum",
|
|
417
|
+
"separator",
|
|
418
|
+
"continuationSeparator",
|
|
419
|
+
"footnoteRef",
|
|
420
|
+
"endnoteRef",
|
|
421
|
+
"footnoteReference",
|
|
422
|
+
"endnoteReference",
|
|
423
|
+
"ptab",
|
|
424
|
+
"monthShort",
|
|
425
|
+
"monthLong",
|
|
426
|
+
"yearShort",
|
|
427
|
+
"yearLong",
|
|
428
|
+
"dayShort",
|
|
429
|
+
"dayLong"
|
|
430
|
+
]);
|
|
372
431
|
function paragraphStartsWithRenderedPageBreak(node) {
|
|
373
|
-
const inlineWrappers = /* @__PURE__ */ new Set([
|
|
374
|
-
"hyperlink",
|
|
375
|
-
"smartTag",
|
|
376
|
-
"sdt",
|
|
377
|
-
"sdtContent",
|
|
378
|
-
"fldSimple",
|
|
379
|
-
"customXml",
|
|
380
|
-
"ins",
|
|
381
|
-
"del",
|
|
382
|
-
"moveFrom",
|
|
383
|
-
"moveTo"
|
|
384
|
-
]);
|
|
385
|
-
const nonContentMarkers = /* @__PURE__ */ new Set([
|
|
386
|
-
"pPr",
|
|
387
|
-
"proofErr",
|
|
388
|
-
"bookmarkStart",
|
|
389
|
-
"bookmarkEnd",
|
|
390
|
-
"commentRangeStart",
|
|
391
|
-
"commentRangeEnd",
|
|
392
|
-
"commentReference",
|
|
393
|
-
"permStart",
|
|
394
|
-
"permEnd",
|
|
395
|
-
"rsidR"
|
|
396
|
-
]);
|
|
397
|
-
const visibleRunContent = /* @__PURE__ */ new Set([
|
|
398
|
-
"t",
|
|
399
|
-
"tab",
|
|
400
|
-
"br",
|
|
401
|
-
"cr",
|
|
402
|
-
"sym",
|
|
403
|
-
"drawing",
|
|
404
|
-
"pict",
|
|
405
|
-
"object",
|
|
406
|
-
"softHyphen",
|
|
407
|
-
"noBreakHyphen",
|
|
408
|
-
"fldChar",
|
|
409
|
-
"instrText",
|
|
410
|
-
"pgNum",
|
|
411
|
-
"separator",
|
|
412
|
-
"continuationSeparator",
|
|
413
|
-
"footnoteRef",
|
|
414
|
-
"endnoteRef",
|
|
415
|
-
"footnoteReference",
|
|
416
|
-
"endnoteReference",
|
|
417
|
-
"ptab",
|
|
418
|
-
"monthShort",
|
|
419
|
-
"monthLong",
|
|
420
|
-
"yearShort",
|
|
421
|
-
"yearLong",
|
|
422
|
-
"dayShort",
|
|
423
|
-
"dayLong"
|
|
424
|
-
]);
|
|
425
432
|
let sawRenderedPageBreak = false;
|
|
426
433
|
const visit = (element) => {
|
|
427
434
|
for (const child of getChildElements(element)) {
|
|
428
435
|
const childName = getLocalName(child.name);
|
|
429
|
-
if (
|
|
436
|
+
if (RENDERED_BREAK_NON_CONTENT_MARKERS.has(childName)) continue;
|
|
430
437
|
if (childName === "lastRenderedPageBreak") {
|
|
431
438
|
sawRenderedPageBreak = true;
|
|
432
439
|
continue;
|
|
@@ -440,11 +447,11 @@ function paragraphStartsWithRenderedPageBreak(node) {
|
|
|
440
447
|
continue;
|
|
441
448
|
}
|
|
442
449
|
if (runChildName === "br" && getAttribute(runChild, "w", "type") === "page") return "forced";
|
|
443
|
-
if (
|
|
450
|
+
if (RENDERED_BREAK_VISIBLE_RUN_CONTENT.has(runChildName)) return "visible";
|
|
444
451
|
}
|
|
445
452
|
continue;
|
|
446
453
|
}
|
|
447
|
-
if (
|
|
454
|
+
if (RENDERED_BREAK_INLINE_WRAPPERS.has(childName)) {
|
|
448
455
|
const result = visit(child);
|
|
449
456
|
if (result !== "continue") return result;
|
|
450
457
|
continue;
|
|
@@ -481,11 +488,13 @@ function parseTrackedChangeInfo(node) {
|
|
|
481
488
|
const rawDate = getAttribute(node, "w", "date");
|
|
482
489
|
const author = rawAuthor?.trim() ?? "";
|
|
483
490
|
const date = rawDate?.trim() ?? "";
|
|
491
|
+
const initials = (getAttribute(node, "w", "initials") ?? "").trim();
|
|
484
492
|
const info = {
|
|
485
|
-
id:
|
|
493
|
+
id: normalizeRevisionId(parsedId),
|
|
486
494
|
author: author.length > 0 ? author : "Unknown"
|
|
487
495
|
};
|
|
488
496
|
if (date.length > 0) info.date = date;
|
|
497
|
+
if (initials.length > 0) info.initials = initials;
|
|
489
498
|
return info;
|
|
490
499
|
}
|
|
491
500
|
function parsePropertyChangeInfo(node) {
|
|
@@ -535,7 +544,7 @@ function isTrackedChangeWrapperChild(content) {
|
|
|
535
544
|
return content.type === "run" || content.type === "hyperlink";
|
|
536
545
|
}
|
|
537
546
|
function isInlineSdtContent(content) {
|
|
538
|
-
return content.type === "run" || content.type === "hyperlink" || content.type === "simpleField" || content.type === "complexField" || content.type === "inlineSdt" || content.type === "insertion" || content.type === "deletion" || content.type === "mathEquation";
|
|
547
|
+
return content.type === "run" || content.type === "hyperlink" || content.type === "simpleField" || content.type === "complexField" || content.type === "inlineSdt" || content.type === "insertion" || content.type === "deletion" || content.type === "moveFrom" || content.type === "moveTo" || content.type === "mathEquation";
|
|
539
548
|
}
|
|
540
549
|
function pushTrackedChangeWrapper({ contents, type, info, content, preserveEmpty = false }) {
|
|
541
550
|
if (content.length === 0 && !preserveEmpty) return;
|
|
@@ -934,9 +943,9 @@ function parseParagraph(node, styles, theme, numbering, rels = null, media = nul
|
|
|
934
943
|
content: []
|
|
935
944
|
};
|
|
936
945
|
const paraId = getAttribute(node, "w14", "paraId") ?? getAttribute(node, "w", "paraId");
|
|
937
|
-
if (paraId) paragraph.paraId = paraId;
|
|
946
|
+
if (paraId && isValidHexId(paraId)) paragraph.paraId = paraId;
|
|
938
947
|
const textId = getAttribute(node, "w14", "textId") ?? getAttribute(node, "w", "textId");
|
|
939
|
-
if (textId) paragraph.textId = textId;
|
|
948
|
+
if (textId && isValidHexId(textId)) paragraph.textId = textId;
|
|
940
949
|
if (!options?.inHeaderFooter && paragraphStartsWithRenderedPageBreak(node)) paragraph.renderedPageBreakBefore = true;
|
|
941
950
|
const pPr = findChild(node, "w", "pPr");
|
|
942
951
|
if (pPr) {
|
|
@@ -2,8 +2,9 @@ import { document_d_exports } from "../types/document.js";
|
|
|
2
2
|
import { NumberingMap } from "./numberingParser.js";
|
|
3
3
|
import { StyleMap } from "./styleParser.js";
|
|
4
4
|
import { XmlElement } from "./xmlParser.js";
|
|
5
|
+
import { TableParserFn } from "./textBoxParser.js";
|
|
5
6
|
|
|
6
7
|
//#region src/docx/paragraphTextBoxEnrichment.d.ts
|
|
7
|
-
declare const enrichParagraphTextBoxes: (paragraph: document_d_exports.Paragraph, paraXml: XmlElement, styles: StyleMap | null, theme: document_d_exports.Theme | null, numbering: NumberingMap | null, rels: document_d_exports.RelationshipMap | null, media: Map<string, document_d_exports.MediaFile> | null) => void;
|
|
8
|
+
declare const enrichParagraphTextBoxes: (paragraph: document_d_exports.Paragraph, paraXml: XmlElement, styles: StyleMap | null, theme: document_d_exports.Theme | null, numbering: NumberingMap | null, rels: document_d_exports.RelationshipMap | null, media: Map<string, document_d_exports.MediaFile> | null, parseTable: TableParserFn) => void;
|
|
8
9
|
//#endregion
|
|
9
10
|
export { enrichParagraphTextBoxes };
|
|
@@ -72,26 +72,80 @@ const vmlWrapType = (positioned, zIndex) => {
|
|
|
72
72
|
if (Number.isFinite(zIndex) && zIndex < 0) return "behind";
|
|
73
73
|
return "inFront";
|
|
74
74
|
};
|
|
75
|
-
const enrichParagraphTextBoxes = (paragraph, paraXml, styles, theme, numbering, rels, media) => {
|
|
76
|
-
|
|
75
|
+
const enrichParagraphTextBoxes = (paragraph, paraXml, styles, theme, numbering, rels, media, parseTable) => {
|
|
76
|
+
enrichTextBoxRuns({
|
|
77
|
+
content: paragraph.content,
|
|
78
|
+
xmlChildren: getChildElements(paraXml),
|
|
79
|
+
styles,
|
|
80
|
+
theme,
|
|
81
|
+
numbering,
|
|
82
|
+
rels,
|
|
83
|
+
media,
|
|
84
|
+
parseTable
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
const trackedChangeTypeFromXml = (localName) => {
|
|
88
|
+
if (localName === "ins") return "insertion";
|
|
89
|
+
if (localName === "del") return "deletion";
|
|
90
|
+
if (localName === "moveFrom" || localName === "moveTo") return localName;
|
|
91
|
+
};
|
|
92
|
+
const enrichTextBoxRuns = ({ content, xmlChildren, styles, theme, numbering, rels, media, parseTable }) => {
|
|
77
93
|
let parsedIndex = 0;
|
|
78
94
|
let lastConsumedRun;
|
|
79
95
|
for (const xmlChild of xmlChildren) {
|
|
80
|
-
|
|
81
|
-
|
|
96
|
+
const localName = getLocalName(xmlChild.name ?? "");
|
|
97
|
+
if (localName === "pPr") continue;
|
|
98
|
+
const trackedChangeType = trackedChangeTypeFromXml(localName);
|
|
99
|
+
const parsedContent = content[parsedIndex];
|
|
100
|
+
if (trackedChangeType && parsedContent?.type === trackedChangeType) enrichTextBoxRuns({
|
|
101
|
+
content: parsedContent.content,
|
|
102
|
+
xmlChildren: getChildElements(xmlChild),
|
|
103
|
+
styles,
|
|
104
|
+
theme,
|
|
105
|
+
numbering,
|
|
106
|
+
rels,
|
|
107
|
+
media,
|
|
108
|
+
parseTable
|
|
109
|
+
});
|
|
110
|
+
if (localName === "sdt" && parsedContent?.type === "inlineSdt") {
|
|
111
|
+
const properties = parsedContent.properties;
|
|
112
|
+
const nestedContent = [];
|
|
113
|
+
let lastSegmentIndex = parsedIndex;
|
|
114
|
+
for (let index = parsedIndex; index < content.length; index += 1) {
|
|
115
|
+
const candidate = content[index];
|
|
116
|
+
if (candidate?.type !== "inlineSdt" || candidate.properties !== properties) continue;
|
|
117
|
+
nestedContent.push(...candidate.content);
|
|
118
|
+
lastSegmentIndex = index;
|
|
119
|
+
}
|
|
120
|
+
const sdtContent = getChildElements(xmlChild).find((child) => getLocalName(child.name ?? "") === "sdtContent");
|
|
121
|
+
if (sdtContent) enrichTextBoxRuns({
|
|
122
|
+
content: nestedContent,
|
|
123
|
+
xmlChildren: getChildElements(sdtContent),
|
|
124
|
+
styles,
|
|
125
|
+
theme,
|
|
126
|
+
numbering,
|
|
127
|
+
rels,
|
|
128
|
+
media,
|
|
129
|
+
parseTable
|
|
130
|
+
});
|
|
131
|
+
parsedIndex = lastSegmentIndex + 1;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (localName !== "r") {
|
|
135
|
+
if (parsedIndex < content.length && parsedContent?.type !== "run") parsedIndex += 1;
|
|
82
136
|
continue;
|
|
83
137
|
}
|
|
84
138
|
const { textBoxDrawings, vmlTextBoxes, hasNonTextBoxContent } = scanRunForTextBoxDrawings(xmlChild);
|
|
85
|
-
const parsedContent = paragraph.content[parsedIndex];
|
|
86
139
|
const parsedRun = parsedContent?.type === "run" ? parsedContent : void 0;
|
|
87
140
|
const targetRun = parsedRun ?? (hasNonTextBoxContent ? lastConsumedRun : void 0);
|
|
141
|
+
const targetRunMatchesXml = targetRun !== void 0 && (hasNonTextBoxContent || parsedRun?.content.length === 0);
|
|
88
142
|
for (const runEl of textBoxDrawings) {
|
|
89
143
|
const textBox = parseTextBox(runEl);
|
|
90
144
|
if (!textBox) continue;
|
|
91
145
|
const wsp = findDeep(runEl, "wps", "wsp");
|
|
92
146
|
if (wsp) {
|
|
93
147
|
const txbxContentEl = getTextBoxContentElement(wsp);
|
|
94
|
-
if (txbxContentEl) textBox.content = parseTextBoxContent(txbxContentEl, parseParagraph,
|
|
148
|
+
if (txbxContentEl) textBox.content = parseTextBoxContent(txbxContentEl, parseParagraph, parseTable, styles, theme, numbering, rels, media);
|
|
95
149
|
}
|
|
96
150
|
const shape = {
|
|
97
151
|
type: "shape",
|
|
@@ -112,31 +166,31 @@ const enrichParagraphTextBoxes = (paragraph, paraXml, styles, theme, numbering,
|
|
|
112
166
|
type: "shape",
|
|
113
167
|
shape
|
|
114
168
|
};
|
|
115
|
-
if (
|
|
169
|
+
if (targetRunMatchesXml) targetRun.content.push(shapeContent);
|
|
116
170
|
else {
|
|
117
171
|
const newRun = {
|
|
118
172
|
type: "run",
|
|
119
173
|
content: [shapeContent]
|
|
120
174
|
};
|
|
121
|
-
|
|
175
|
+
content.splice(parsedIndex, 0, newRun);
|
|
122
176
|
lastConsumedRun = newRun;
|
|
123
177
|
parsedIndex += 1;
|
|
124
178
|
}
|
|
125
179
|
}
|
|
126
180
|
for (const pictEl of vmlTextBoxes) {
|
|
127
|
-
const shape = parseVmlTextBoxShape(pictEl, styles, theme, numbering, rels, media);
|
|
181
|
+
const shape = parseVmlTextBoxShape(pictEl, styles, theme, numbering, rels, media, parseTable);
|
|
128
182
|
if (!shape) continue;
|
|
129
183
|
const shapeContent = {
|
|
130
184
|
type: "shape",
|
|
131
185
|
shape
|
|
132
186
|
};
|
|
133
|
-
if (
|
|
187
|
+
if (targetRunMatchesXml) targetRun.content.push(shapeContent);
|
|
134
188
|
else {
|
|
135
189
|
const newRun = {
|
|
136
190
|
type: "run",
|
|
137
191
|
content: [shapeContent]
|
|
138
192
|
};
|
|
139
|
-
|
|
193
|
+
content.splice(parsedIndex, 0, newRun);
|
|
140
194
|
lastConsumedRun = newRun;
|
|
141
195
|
parsedIndex += 1;
|
|
142
196
|
}
|
|
@@ -196,7 +250,7 @@ const scanRunForTextBoxDrawings = (xmlRun) => {
|
|
|
196
250
|
hasNonTextBoxContent
|
|
197
251
|
};
|
|
198
252
|
};
|
|
199
|
-
const parseVmlTextBoxShape = (pictEl, styles, theme, numbering, rels, media) => {
|
|
253
|
+
const parseVmlTextBoxShape = (pictEl, styles, theme, numbering, rels, media, parseTable) => {
|
|
200
254
|
const shapeEl = findDeep(pictEl, "v", "shape");
|
|
201
255
|
const textBoxEl = shapeEl ? findDeep(shapeEl, "v", "textbox") : null;
|
|
202
256
|
const contentEl = textBoxEl ? findDeep(textBoxEl, "w", "txbxContent") : null;
|
|
@@ -221,7 +275,7 @@ const parseVmlTextBoxShape = (pictEl, styles, theme, numbering, rels, media) =>
|
|
|
221
275
|
...fill === void 0 ? {} : { fill },
|
|
222
276
|
wrap: { type: vmlWrapType(positioned, zIndex) },
|
|
223
277
|
textBody: {
|
|
224
|
-
content: parseTextBoxContent(contentEl, parseParagraph,
|
|
278
|
+
content: parseTextBoxContent(contentEl, parseParagraph, parseTable, styles, theme, numbering, rels, media),
|
|
225
279
|
...margins === void 0 ? {} : { margins }
|
|
226
280
|
}
|
|
227
281
|
};
|
|
@@ -10,7 +10,7 @@ const visitDocxParagraphs = ({ documentBody, headers, footers, footnotes, endnot
|
|
|
10
10
|
const visitRun = (run) => {
|
|
11
11
|
for (const content of run.content) {
|
|
12
12
|
if (content.type !== "shape" || !content.shape.textBody) continue;
|
|
13
|
-
for (const
|
|
13
|
+
for (const block of content.shape.textBody.content) visitBlock(block);
|
|
14
14
|
}
|
|
15
15
|
};
|
|
16
16
|
const visitHyperlink = (hyperlink) => {
|
package/dist/docx/parser.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
+
import { parseNumbering } from "./numberingParser.js";
|
|
2
|
+
import { RELATIONSHIP_TYPES, parseRelationships, resolveRelativePath } from "./relsParser.js";
|
|
3
|
+
import { applyThemeFontLang, parseTheme } from "./themeParser.js";
|
|
1
4
|
import { toArrayBuffer } from "../utils/docxInput.js";
|
|
2
5
|
import { loadFontsWithMapping } from "../utils/fontLoader.js";
|
|
3
6
|
import { convertTiffToPngDataUrl, isTiffMimeType } from "../utils/tiffConverter.js";
|
|
4
|
-
import { RELATIONSHIP_TYPES, parseRelationships, resolveRelativePath } from "./relsParser.js";
|
|
5
|
-
import { applyThemeFontLang, parseTheme } from "./themeParser.js";
|
|
6
7
|
import { parseComments } from "./commentParser.js";
|
|
7
8
|
import { normalizeCommentReferences } from "./commentReferenceNormalization.js";
|
|
8
9
|
import { detectDocxConformanceClass } from "./conformance.js";
|
|
9
10
|
import { parseCoreProperties } from "./corePropertiesParser.js";
|
|
10
|
-
import { parseNumbering } from "./numberingParser.js";
|
|
11
11
|
import { extractAllTemplateVariables, parseDocumentBody } from "./documentParser.js";
|
|
12
12
|
import { parseEndnotes, parseFootnotes } from "./footnoteParser.js";
|
|
13
13
|
import { parseFooter, parseHeader } from "./headerFooterParser.js";
|
package/dist/docx/rezip.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { RELATIONSHIP_TYPES, parseRelationships, resolveRelativePath } from "./relsParser.js";
|
|
2
1
|
import { parseNumbering } from "./numberingParser.js";
|
|
2
|
+
import { RELATIONSHIP_TYPES, parseRelationships, resolveRelativePath } from "./relsParser.js";
|
|
3
3
|
import { parseEndnotes, parseFootnotes } from "./footnoteParser.js";
|
|
4
4
|
import { assertValidFolioDocumentModel } from "./modelValidation.js";
|
|
5
5
|
import { isPreservableDocxEntry } from "./unzip.js";
|
|
6
6
|
import { applyReplyThreadMarkers } from "./commentReplyMarkers.js";
|
|
7
|
-
import {
|
|
7
|
+
import { withoutOrphanCommentRanges } from "./commentRangeIntegrity.js";
|
|
8
|
+
import { buildParagraphOffsetIndex, buildPatchedNoteXml, buildPatchedNumberingXml, collectChangedNumberingDefs, collectParaIds } from "./selectiveXmlPatch.js";
|
|
8
9
|
import { escapeXml } from "./serializer/xmlUtils.js";
|
|
9
10
|
import { ensureThreadedCommentParaIds, serializeComments, serializeCommentsExtended } from "./serializer/commentSerializer.js";
|
|
10
11
|
import { serializeDocument } from "./serializer/documentSerializer.js";
|
|
@@ -15,6 +16,7 @@ import { serializeFontTableXml } from "./serializer/fontTableSerializer.js";
|
|
|
15
16
|
import { serializeSettingsXml } from "./serializer/settingsSerializer.js";
|
|
16
17
|
import { serializeStylesXml } from "./serializer/stylesSerializer.js";
|
|
17
18
|
import { serializeThemeXml } from "./serializer/themeSerializer.js";
|
|
19
|
+
import { isAllowedExternalWatermarkImageUrl } from "../watermark/index.js";
|
|
18
20
|
import { panic } from "better-result";
|
|
19
21
|
import JSZip from "jszip";
|
|
20
22
|
//#region src/docx/rezip.ts
|
|
@@ -369,7 +371,7 @@ async function processNewHyperlinks(newHyperlinks, zip, compressionLevel) {
|
|
|
369
371
|
async function repackDocx(doc, options = {}) {
|
|
370
372
|
if (!doc.originalBuffer) panic("Cannot repack document: no original buffer for round-trip. Use createDocx() for new documents.");
|
|
371
373
|
const { compressionLevel = 6, updateModifiedDate = true, modifiedBy } = options;
|
|
372
|
-
const exportDocument = doc;
|
|
374
|
+
const exportDocument = withoutOrphanCommentRanges(doc);
|
|
373
375
|
const originalZip = await JSZip.loadAsync(doc.originalBuffer);
|
|
374
376
|
const newZip = new JSZip();
|
|
375
377
|
for (const [path, file] of Object.entries(originalZip.files)) {
|
|
@@ -431,7 +433,7 @@ async function repackDocx(doc, options = {}) {
|
|
|
431
433
|
*/
|
|
432
434
|
async function repackDocxFromRaw(doc, rawContent, options = {}) {
|
|
433
435
|
const { compressionLevel = 6, updateModifiedDate = true, modifiedBy } = options;
|
|
434
|
-
const exportDocument = doc;
|
|
436
|
+
const exportDocument = withoutOrphanCommentRanges(doc);
|
|
435
437
|
const newZip = new JSZip();
|
|
436
438
|
for (const [path, file] of Object.entries(rawContent.originalZip.files)) {
|
|
437
439
|
if (file.dir) {
|
|
@@ -854,10 +856,11 @@ async function rebindWatermarkRelIds(doc, zip, compressionLevel) {
|
|
|
854
856
|
const changedPaths = /* @__PURE__ */ new Set();
|
|
855
857
|
for (const { watermark, relsPath, partPath } of pending) {
|
|
856
858
|
let canonical;
|
|
857
|
-
if (watermark.imageTarget !== void 0) canonical = watermark.
|
|
859
|
+
if (watermark.imageTarget !== void 0) if (watermark.imageTargetExternal) canonical = isAllowedExternalWatermarkImageUrl(watermark.imageTarget) ? {
|
|
858
860
|
mode: "external",
|
|
859
861
|
url: watermark.imageTarget
|
|
860
|
-
} :
|
|
862
|
+
} : resolveCanonical(watermark.imageRId);
|
|
863
|
+
else canonical = {
|
|
861
864
|
mode: "internal",
|
|
862
865
|
absolute: watermark.imageTarget
|
|
863
866
|
};
|
|
@@ -1000,15 +1003,23 @@ async function patchNotePartIntoZip(conventionalLowerPath, currentXml, baselineF
|
|
|
1000
1003
|
* (re-parsed original) serialization — i.e. the ones actually edited. A
|
|
1001
1004
|
* paragraph is only considered when its `paraId` resolves uniquely in both,
|
|
1002
1005
|
* so it can be spliced safely.
|
|
1006
|
+
*
|
|
1007
|
+
* Builds one {@link buildParagraphOffsetIndex} per side (a single linear scan
|
|
1008
|
+
* each) instead of calling `extractParagraphXml` per candidate id, which
|
|
1009
|
+
* re-scanned the whole XML per id — O(note count * XML size) for a document
|
|
1010
|
+
* with many footnotes/endnotes. The index turns each lookup below into O(1).
|
|
1003
1011
|
*/
|
|
1004
1012
|
function collectChangedNoteParaIds(baselineXml, currentXml) {
|
|
1005
1013
|
const changed = /* @__PURE__ */ new Set();
|
|
1006
1014
|
const baselineIds = collectParaIds(baselineXml);
|
|
1015
|
+
const baselineOffsets = buildParagraphOffsetIndex(baselineXml);
|
|
1016
|
+
const currentOffsets = buildParagraphOffsetIndex(currentXml);
|
|
1007
1017
|
for (const [id, count] of collectParaIds(currentXml)) {
|
|
1008
1018
|
if (count !== 1 || baselineIds.get(id) !== 1) continue;
|
|
1009
|
-
const
|
|
1010
|
-
const
|
|
1011
|
-
if (
|
|
1019
|
+
const beforeRange = baselineOffsets.get(id);
|
|
1020
|
+
const afterRange = currentOffsets.get(id);
|
|
1021
|
+
if (!beforeRange || !afterRange) continue;
|
|
1022
|
+
if (baselineXml.slice(beforeRange.start, beforeRange.end) !== currentXml.slice(afterRange.start, afterRange.end)) changed.add(id);
|
|
1012
1023
|
}
|
|
1013
1024
|
return changed;
|
|
1014
1025
|
}
|
package/dist/docx/runParser.js
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
|
-
import { cloneWithXmlnsDeclarations, elementToXml, findAllDeep, findChild, findChildren, getAttribute, getChildElements, getTextContent, mergeXmlnsDeclarations, parseBooleanElement, parseNumericAttribute } from "./xmlParser.js";
|
|
2
1
|
import { EmphasisMarkSchema, FontThemeSchema, HighlightColorSchema, ShadingPatternSchema, TextEffectSchema, ThemeColorSlotSchema, UnderlineStyleSchema, narrowEnum } from "./parserEnums.js";
|
|
2
|
+
import { cloneWithXmlnsDeclarations, elementToXml, findAllDeep, findChild, findChildren, getAttribute, getChildElements, getTextContent, mergeXmlnsDeclarations, parseBooleanElement, parseNumericAttribute } from "./xmlParser.js";
|
|
3
3
|
import { parseImage } from "./imageParser.js";
|
|
4
4
|
import { parseGroupDrawing } from "./groupDrawingParser.js";
|
|
5
5
|
import { parseShapeFromDrawing, shouldPreserveRawShapeDrawing } from "./shapeParser.js";
|
|
6
6
|
import { parseVmlImageContent } from "./vmlImageParser.js";
|
|
7
7
|
import { resolveThemeFontRef } from "./themeParser.js";
|
|
8
|
+
import { normalizeRevisionId } from "@stll/docx-core/model";
|
|
8
9
|
//#region src/docx/runParser.ts
|
|
9
10
|
/**
|
|
11
|
+
* Sanity cap on `w:lang` `@w:val`/`@w:eastAsia`/`@w:bidi` tag length. BCP-47
|
|
12
|
+
* tags top out well under this; a hostile/corrupt tag here would drive the
|
|
13
|
+
* hyphenation dictionary lookup and segmenter cache keying with an
|
|
14
|
+
* attacker-sized string per run.
|
|
15
|
+
*/
|
|
16
|
+
const MAX_LANGUAGE_TAG_LENGTH = 35;
|
|
17
|
+
const truncateLanguageTag = (value) => value === void 0 ? void 0 : value.slice(0, MAX_LANGUAGE_TAG_LENGTH);
|
|
18
|
+
/**
|
|
10
19
|
* Parse color value from attributes
|
|
11
20
|
*/
|
|
12
21
|
function parseColorValue(rgb, themeColor, themeTint, themeShade) {
|
|
@@ -267,9 +276,9 @@ function parseRunProperties(rPr, theme, _styles) {
|
|
|
267
276
|
}
|
|
268
277
|
const lang = propertyChildren.lang;
|
|
269
278
|
if (lang) {
|
|
270
|
-
const val = getAttribute(lang, "w", "val") || void 0;
|
|
271
|
-
const eastAsia = getAttribute(lang, "w", "eastAsia") || void 0;
|
|
272
|
-
const bidi = getAttribute(lang, "w", "bidi") || void 0;
|
|
279
|
+
const val = truncateLanguageTag(getAttribute(lang, "w", "val") || void 0);
|
|
280
|
+
const eastAsia = truncateLanguageTag(getAttribute(lang, "w", "eastAsia") || void 0);
|
|
281
|
+
const bidi = truncateLanguageTag(getAttribute(lang, "w", "bidi") || void 0);
|
|
273
282
|
if (val || eastAsia || bidi) formatting.language = {
|
|
274
283
|
...val ? { val } : {},
|
|
275
284
|
...eastAsia ? { eastAsia } : {},
|
|
@@ -332,7 +341,7 @@ function parsePropertyChangeInfo(changeElement) {
|
|
|
332
341
|
const date = (getAttribute(changeElement, "w", "date") ?? "").trim();
|
|
333
342
|
const rsid = (getAttribute(changeElement, "w", "rsid") ?? "").trim();
|
|
334
343
|
const info = {
|
|
335
|
-
id:
|
|
344
|
+
id: normalizeRevisionId(parsedId),
|
|
336
345
|
author: author.length > 0 ? author : "Unknown"
|
|
337
346
|
};
|
|
338
347
|
if (date.length > 0) info.date = date;
|
|
@@ -551,7 +560,9 @@ function parseRunContents(runElement, rels, media, rootXmlns = {}) {
|
|
|
551
560
|
break;
|
|
552
561
|
}
|
|
553
562
|
case "rPr": break;
|
|
554
|
-
case "lastRenderedPageBreak":
|
|
563
|
+
case "lastRenderedPageBreak":
|
|
564
|
+
contents.push({ type: "renderedPageBreak" });
|
|
565
|
+
break;
|
|
555
566
|
case "cr":
|
|
556
567
|
contents.push({
|
|
557
568
|
type: "break",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { elementToXml, findChild, getAttributeAnyPrefix, getLocalName, parseBooleanElement } from "./xmlParser.js";
|
|
2
1
|
import { SdtLockSchema, narrowEnum } from "./parserEnums.js";
|
|
2
|
+
import { elementToXml, findChild, getAttributeAnyPrefix, getLocalName, parseBooleanElement } from "./xmlParser.js";
|
|
3
3
|
//#region src/docx/sdtProperties.ts
|
|
4
4
|
function parseListItems(el) {
|
|
5
5
|
const items = [];
|
|
@@ -1,8 +1,21 @@
|
|
|
1
|
-
import { findChild, findChildren, getAttribute, getChildElements, getLocalName, parseBooleanElement, parseNumericAttribute } from "./xmlParser.js";
|
|
2
1
|
import { BorderStyleSchema, ThemeColorSlotSchema, narrowEnum } from "./parserEnums.js";
|
|
2
|
+
import { findChild, findChildren, getAttribute, getChildElements, getLocalName, parseBooleanElement, parseNumericAttribute } from "./xmlParser.js";
|
|
3
3
|
import { parseFooterReference, parseHeaderReference } from "./headerFooterRefParser.js";
|
|
4
4
|
import { parseEndnoteProperties, parseFootnoteProperties } from "./notePropertiesParser.js";
|
|
5
|
+
import { normalizeRevisionId } from "@stll/docx-core/model";
|
|
5
6
|
//#region src/docx/sectionParser.ts
|
|
7
|
+
/**
|
|
8
|
+
* Sanity cap on `w:cols/@w:num`. Word's column picker tops out well below
|
|
9
|
+
* this; a hostile/corrupt value here would force the layout engine to
|
|
10
|
+
* generate a proportional band per column.
|
|
11
|
+
*/
|
|
12
|
+
const MAX_SECTION_COLUMNS = 45;
|
|
13
|
+
/**
|
|
14
|
+
* Sanity cap on `w:pgSz` `@w:w`/`@w:h`, in twips (~22in). Matches the
|
|
15
|
+
* existing `w:defaultTabStop` cap (`settingsParser.ts`) and bounds the
|
|
16
|
+
* ruler tick generators, which are sized off the page dimensions.
|
|
17
|
+
*/
|
|
18
|
+
const MAX_PAGE_DIMENSION_TWIPS = 31680;
|
|
6
19
|
const serializedSectionPropertyChildNames = /* @__PURE__ */ new Set([
|
|
7
20
|
"headerReference",
|
|
8
21
|
"footerReference",
|
|
@@ -55,7 +68,7 @@ function parsePropertyChangeInfo(node) {
|
|
|
55
68
|
const date = (getAttribute(node, "w", "date") ?? "").trim();
|
|
56
69
|
const rsid = (getAttribute(node, "w", "rsid") ?? "").trim();
|
|
57
70
|
const info = {
|
|
58
|
-
id:
|
|
71
|
+
id: normalizeRevisionId(parsedId),
|
|
59
72
|
author: author.length > 0 ? author : "Unknown"
|
|
60
73
|
};
|
|
61
74
|
if (date.length > 0) info.date = date;
|
|
@@ -170,9 +183,9 @@ function parseSectionProperties(sectPr) {
|
|
|
170
183
|
const pgSz = findChild(sectPr, "w", "pgSz");
|
|
171
184
|
if (pgSz) {
|
|
172
185
|
const w = parseNumericAttribute(pgSz, "w", "w");
|
|
173
|
-
if (w !== void 0) props.pageWidth = w;
|
|
186
|
+
if (w !== void 0) props.pageWidth = Math.min(w, MAX_PAGE_DIMENSION_TWIPS);
|
|
174
187
|
const h = parseNumericAttribute(pgSz, "w", "h");
|
|
175
|
-
if (h !== void 0) props.pageHeight = h;
|
|
188
|
+
if (h !== void 0) props.pageHeight = Math.min(h, MAX_PAGE_DIMENSION_TWIPS);
|
|
176
189
|
const orientation = parseOrientation(getAttribute(pgSz, "w", "orient"));
|
|
177
190
|
if (orientation) props.orientation = orientation;
|
|
178
191
|
}
|
|
@@ -196,7 +209,7 @@ function parseSectionProperties(sectPr) {
|
|
|
196
209
|
const cols = findChild(sectPr, "w", "cols");
|
|
197
210
|
if (cols) {
|
|
198
211
|
const num = parseNumericAttribute(cols, "w", "num");
|
|
199
|
-
if (num !== void 0) props.columnCount = num;
|
|
212
|
+
if (num !== void 0) props.columnCount = Math.min(num, MAX_SECTION_COLUMNS);
|
|
200
213
|
const space = parseNumericAttribute(cols, "w", "space");
|
|
201
214
|
if (space !== void 0) props.columnSpace = space;
|
|
202
215
|
const equalWidth = getAttribute(cols, "w", "equalWidth");
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { parseNumbering } from "./numberingParser.js";
|
|
1
2
|
import { RELATIONSHIP_TYPES } from "./relsParser.js";
|
|
2
3
|
import { parseCommentsExtended } from "./commentParser.js";
|
|
3
|
-
import { parseNumbering } from "./numberingParser.js";
|
|
4
4
|
import { validateFolioDocumentModel } from "./modelValidation.js";
|
|
5
|
+
import { isPreservableDocxEntry } from "./unzip.js";
|
|
5
6
|
import { hasUnsynthesizedReplyRanges } from "./commentReplyMarkers.js";
|
|
7
|
+
import { withoutOrphanCommentRanges } from "./commentRangeIntegrity.js";
|
|
6
8
|
import { buildPatchedDocumentXml, buildPatchedNoteXml, buildPatchedNumberingXml, collectChangedNumberingDefs, collectParaIds } from "./selectiveXmlPatch.js";
|
|
7
9
|
import { ensureThreadedCommentParaIds, serializeComments, serializeCommentsExtended } from "./serializer/commentSerializer.js";
|
|
8
10
|
import { serializeDocument } from "./serializer/documentSerializer.js";
|
|
@@ -182,6 +184,7 @@ async function attemptSelectiveSave(doc, originalBuffer, options) {
|
|
|
182
184
|
if (hasNewImagesOrHyperlinks(content)) return null;
|
|
183
185
|
if (hasUnmaterializedHeaderFooter(doc)) return null;
|
|
184
186
|
if (hasModelDrivenPictureWatermark(doc)) return null;
|
|
187
|
+
if (withoutOrphanCommentRanges(doc) !== doc) return null;
|
|
185
188
|
if (hasUnsynthesizedReplyRanges(doc)) return null;
|
|
186
189
|
if (!validateFolioDocumentModel(doc).valid) return null;
|
|
187
190
|
const comments = doc.package.document.comments ?? [];
|
|
@@ -189,6 +192,7 @@ async function attemptSelectiveSave(doc, originalBuffer, options) {
|
|
|
189
192
|
const headerFooterUpdates = collectHeaderFooterUpdates(doc);
|
|
190
193
|
try {
|
|
191
194
|
const zip = await (await import("jszip")).default.loadAsync(originalBuffer);
|
|
195
|
+
for (const [path, file] of Object.entries(zip.files)) if (!file.dir && !isPreservableDocxEntry(path)) return null;
|
|
192
196
|
const updates = /* @__PURE__ */ new Map();
|
|
193
197
|
if (changedParaIds.size > 0) {
|
|
194
198
|
const docXmlFile = zip.file("word/document.xml");
|
|
@@ -33,6 +33,27 @@ declare function findParagraphOffsets(xml: string, paraId: string): {
|
|
|
33
33
|
* from a fully serialized document.xml string.
|
|
34
34
|
*/
|
|
35
35
|
declare function extractParagraphXml(serializedXml: string, paraId: string): string | null;
|
|
36
|
+
type ParagraphOffsets = {
|
|
37
|
+
start: number;
|
|
38
|
+
end: number;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Single linear-scan index of every `<w:p>` element's start/end offsets,
|
|
42
|
+
* keyed by `w14:paraId`. Generalizes {@link findParagraphOffsets} (one
|
|
43
|
+
* regex-scan-plus-depth-walk per lookup) to build every paragraph's offsets
|
|
44
|
+
* in a single pass, so a caller that needs many paragraphs from the same XML
|
|
45
|
+
* (e.g. `collectChangedNoteParaIds` in rezip.ts, walking every note paraId)
|
|
46
|
+
* does O(1) map lookups afterward instead of re-scanning the whole XML once
|
|
47
|
+
* per id — O(ids * XML length) collapses to O(XML length).
|
|
48
|
+
*
|
|
49
|
+
* A `<w:p>` nested inside another (e.g. inside `mc:AlternateContent`) is
|
|
50
|
+
* indexed too via a depth stack, matching every element `findParagraphOffsets`
|
|
51
|
+
* can resolve. A paraId that appears on more than one element is ambiguous —
|
|
52
|
+
* mirroring {@link findParagraphOffsets}'s single-match requirement — and is
|
|
53
|
+
* omitted from the index, so a lookup misses exactly where the per-id
|
|
54
|
+
* function would return null.
|
|
55
|
+
*/
|
|
56
|
+
declare function buildParagraphOffsetIndex(xml: string): Map<string, ParagraphOffsets>;
|
|
36
57
|
/**
|
|
37
58
|
* Count <w:p> elements in an XML string (top-level paragraph count).
|
|
38
59
|
* Counts opening <w:p tags that are NOT self-closing.
|
|
@@ -109,4 +130,4 @@ declare function collectChangedNumberingDefs(baselineXml: string, currentXml: st
|
|
|
109
130
|
*/
|
|
110
131
|
declare function buildPatchedNumberingXml(originalXml: string, currentXml: string, changed: ChangedNumberingDefs): string | null;
|
|
111
132
|
//#endregion
|
|
112
|
-
export { ChangedNumberingDefs, PatchSafetyOptions, PatchValidationResult, buildPatchedDocumentXml, buildPatchedNoteXml, buildPatchedNumberingXml, collectChangedNumberingDefs, collectParaIds, countParagraphElements, extractParagraphXml, findParagraphOffsets, isXmlNameBoundary, validatePatchSafety };
|
|
133
|
+
export { ChangedNumberingDefs, ParagraphOffsets, PatchSafetyOptions, PatchValidationResult, buildParagraphOffsetIndex, buildPatchedDocumentXml, buildPatchedNoteXml, buildPatchedNumberingXml, collectChangedNumberingDefs, collectParaIds, countParagraphElements, extractParagraphXml, findParagraphOffsets, isXmlNameBoundary, validatePatchSafety };
|