@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
package/dist/docx/styleParser.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { findChild, findChildren, getAttribute, getLocalName, parseBooleanElement, parseNumericAttribute, parseTableMeasurementValue, parseXmlDocument } from "./xmlParser.js";
|
|
2
1
|
import { BorderStyleSchema, ConditionalStyleTypeSchema, EmphasisMarkSchema, FontThemeSchema, HighlightColorSchema, LineSpacingRuleSchema, ParagraphAlignmentSchema, ShadingPatternSchema, StyleTypeSchema, TabLeaderSchema, TabStopAlignmentSchema, TableCellTextDirectionSchema, TableRowHeightRuleSchema, TableWidthTypeSchema, TextEffectSchema, ThemeColorSlotSchema, UnderlineStyleSchema, narrowEnum } from "./parserEnums.js";
|
|
3
|
-
import {
|
|
2
|
+
import { findChild, findChildren, getAttribute, getLocalName, parseBooleanElement, parseNumericAttribute, parseTableMeasurementValue, parseXmlDocument } from "./xmlParser.js";
|
|
4
3
|
import { mergeTextFormatting } from "../utils/textFormattingMerge.js";
|
|
5
4
|
import { mergeParagraphFormatting } from "../utils/paragraphFormattingMerge.js";
|
|
5
|
+
import { resolveThemeFontRef } from "./themeParser.js";
|
|
6
6
|
//#region src/docx/styleParser.ts
|
|
7
7
|
/**
|
|
8
8
|
* Parse text formatting properties (w:rPr)
|
|
@@ -263,6 +263,8 @@ function parseParagraphProperties(pPr, theme) {
|
|
|
263
263
|
}
|
|
264
264
|
const bidi = findChild(pPr, "w", "bidi");
|
|
265
265
|
if (bidi) formatting.bidi = parseBooleanElement(bidi);
|
|
266
|
+
const snapToGrid = findChild(pPr, "w", "snapToGrid");
|
|
267
|
+
if (snapToGrid) formatting.snapToGrid = parseBooleanElement(snapToGrid);
|
|
266
268
|
const spacing = findChild(pPr, "w", "spacing");
|
|
267
269
|
if (spacing) {
|
|
268
270
|
const before = parseNumericAttribute(spacing, "w", "before");
|
|
@@ -4,6 +4,13 @@ import { StyleMap } from "./styleParser.js";
|
|
|
4
4
|
import { XmlElement } from "./xmlParser.js";
|
|
5
5
|
|
|
6
6
|
//#region src/docx/tableParser.d.ts
|
|
7
|
+
/**
|
|
8
|
+
* Sanity cap on `w:gridSpan` (and the derived table column count). Word's
|
|
9
|
+
* practical column limit is 63; a hostile/corrupt value here would blow up
|
|
10
|
+
* every downstream structure sized by column count (TableMap, border grids,
|
|
11
|
+
* cell-grid arrays).
|
|
12
|
+
*/
|
|
13
|
+
declare const MAX_TABLE_COLUMNS = 63;
|
|
7
14
|
/**
|
|
8
15
|
* Parse a table measurement (width, height, etc.)
|
|
9
16
|
*
|
|
@@ -199,4 +206,4 @@ declare function getHeaderRows(table: document_d_exports.Table): document_d_expo
|
|
|
199
206
|
*/
|
|
200
207
|
declare function isFloatingTable(table: document_d_exports.Table): boolean;
|
|
201
208
|
//#endregion
|
|
202
|
-
export { getHeaderRows, getTableColumnCount, getTableRowCount, getTableText, hasHeaderRow, isCellHorizontallyMerged, isCellMergeContinuation, isCellMergeStart, isFloatingTable, parseBorderSpec, parseCellMargins, parseConditionalFormatStyle, parseFloatingTableProperties, parseShading, parseTable, parseTableBorders, parseTableCell, parseTableCellProperties, parseTableGrid, parseTableLook, parseTableMeasurement, parseTableProperties, parseTableRow, parseTableRowProperties };
|
|
209
|
+
export { MAX_TABLE_COLUMNS, getHeaderRows, getTableColumnCount, getTableRowCount, getTableText, hasHeaderRow, isCellHorizontallyMerged, isCellMergeContinuation, isCellMergeStart, isFloatingTable, parseBorderSpec, parseCellMargins, parseConditionalFormatStyle, parseFloatingTableProperties, parseShading, parseTable, parseTableBorders, parseTableCell, parseTableCellProperties, parseTableGrid, parseTableLook, parseTableMeasurement, parseTableProperties, parseTableRow, parseTableRowProperties };
|
package/dist/docx/tableParser.js
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
|
+
import { BorderStyleSchema, FloatingTableXSpecSchema, FloatingTableYSpecSchema, ShadingPatternSchema, TableCellTextDirectionSchema, ThemeColorSlotSchema, narrowEnum } from "./parserEnums.js";
|
|
1
2
|
import { findChild, findChildByLocalName, findChildren, getAttribute, getChildElements, mergeXmlnsDeclarations, parseBooleanElement, parseNumericAttribute, parseTableMeasurementValue } from "./xmlParser.js";
|
|
2
3
|
import { parseBookmarkEnd, parseBookmarkStart } from "./bookmarkParser.js";
|
|
3
|
-
import { BorderStyleSchema, FloatingTableXSpecSchema, FloatingTableYSpecSchema, ShadingPatternSchema, TableCellTextDirectionSchema, ThemeColorSlotSchema, narrowEnum } from "./parserEnums.js";
|
|
4
4
|
import { parseParagraph } from "./paragraphParser.js";
|
|
5
5
|
import { appendBookmarkMarkerToLastParagraphInBlocks, appendBookmarkMarkerToLastParagraphInCells, prependBookmarkMarkersToFirstParagraphInBlocks, prependBookmarkMarkersToFirstParagraphInCell } from "./bookmarkPlacement.js";
|
|
6
6
|
import { enrichParagraphTextBoxes } from "./paragraphTextBoxEnrichment.js";
|
|
7
|
+
import { normalizeRevisionId } from "@stll/docx-core/model";
|
|
7
8
|
//#region src/docx/tableParser.ts
|
|
8
9
|
/**
|
|
10
|
+
* Sanity cap on `w:gridSpan` (and the derived table column count). Word's
|
|
11
|
+
* practical column limit is 63; a hostile/corrupt value here would blow up
|
|
12
|
+
* every downstream structure sized by column count (TableMap, border grids,
|
|
13
|
+
* cell-grid arrays).
|
|
14
|
+
*/
|
|
15
|
+
const MAX_TABLE_COLUMNS = 63;
|
|
16
|
+
/**
|
|
9
17
|
* Parse a table measurement (width, height, etc.)
|
|
10
18
|
*
|
|
11
19
|
* @param element - Element with w:w and w:type attributes
|
|
@@ -32,11 +40,13 @@ function parseTrackedChangeInfo(node) {
|
|
|
32
40
|
const parsedId = rawId ? Number.parseInt(rawId, 10) : 0;
|
|
33
41
|
const author = (getAttribute(node, "w", "author") ?? "").trim();
|
|
34
42
|
const date = (getAttribute(node, "w", "date") ?? "").trim();
|
|
43
|
+
const initials = (getAttribute(node, "w", "initials") ?? "").trim();
|
|
35
44
|
const info = {
|
|
36
|
-
id:
|
|
45
|
+
id: normalizeRevisionId(parsedId),
|
|
37
46
|
author: author.length > 0 ? author : "Unknown"
|
|
38
47
|
};
|
|
39
48
|
if (date.length > 0) info.date = date;
|
|
49
|
+
if (initials.length > 0) info.initials = initials;
|
|
40
50
|
return info;
|
|
41
51
|
}
|
|
42
52
|
function parsePropertyChangeInfo(node) {
|
|
@@ -349,10 +359,20 @@ function parseTableCellStructuralChange(tcPrElement) {
|
|
|
349
359
|
info: parseTrackedChangeInfo(deletion)
|
|
350
360
|
};
|
|
351
361
|
const merge = findChild(tcPrElement, "w", "cellMerge");
|
|
352
|
-
if (merge)
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
362
|
+
if (merge) {
|
|
363
|
+
const verticalMerge = parseTableCellVerticalMergeRevisionValue(getAttribute(merge, "w", "vMerge"));
|
|
364
|
+
const verticalMergeOriginal = parseTableCellVerticalMergeRevisionValue(getAttribute(merge, "w", "vMergeOrig"));
|
|
365
|
+
return {
|
|
366
|
+
type: "tableCellMerge",
|
|
367
|
+
info: parseTrackedChangeInfo(merge),
|
|
368
|
+
...verticalMerge !== void 0 ? { verticalMerge } : {},
|
|
369
|
+
...verticalMergeOriginal !== void 0 ? { verticalMergeOriginal } : {}
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
function parseTableCellVerticalMergeRevisionValue(value) {
|
|
374
|
+
if (value === "cont") return "continue";
|
|
375
|
+
if (value === "rest") return "rest";
|
|
356
376
|
}
|
|
357
377
|
/**
|
|
358
378
|
* Parse table row properties (w:trPr)
|
|
@@ -475,14 +495,15 @@ function parseTableCellProperties(tcPrElement) {
|
|
|
475
495
|
const gridSpanElement = findChild(tcPrElement, "w", "gridSpan");
|
|
476
496
|
if (gridSpanElement) {
|
|
477
497
|
const gridSpan = parseNumericAttribute(gridSpanElement, "w", "val");
|
|
478
|
-
if (gridSpan !== void 0 && gridSpan > 1) formatting.gridSpan = gridSpan;
|
|
498
|
+
if (gridSpan !== void 0 && gridSpan > 1) formatting.gridSpan = Math.min(gridSpan, 63);
|
|
479
499
|
}
|
|
480
500
|
const vMergeElement = findChild(tcPrElement, "w", "vMerge");
|
|
481
501
|
if (vMergeElement) if (getAttribute(vMergeElement, "w", "val") === "restart") formatting.vMerge = "restart";
|
|
482
502
|
else formatting.vMerge = "continue";
|
|
483
503
|
if (parseBooleanElement(findChild(tcPrElement, "w", "tcFitText"))) formatting.fitText = true;
|
|
484
504
|
if (parseBooleanElement(findChild(tcPrElement, "w", "noWrap"))) formatting.noWrap = true;
|
|
485
|
-
|
|
505
|
+
const hideMark = parseBooleanElement(findChild(tcPrElement, "w", "hideMark"));
|
|
506
|
+
if (hideMark !== void 0) formatting.hideMark = hideMark;
|
|
486
507
|
const conditionalFormat = parseConditionalFormatStyle(findChild(tcPrElement, "w", "cnfStyle"));
|
|
487
508
|
if (conditionalFormat) formatting.conditionalFormat = conditionalFormat;
|
|
488
509
|
if (Object.keys(formatting).length === 0) return;
|
|
@@ -508,7 +529,7 @@ function parseCellContent(tcElement, styles, theme, numbering, rels, media, opti
|
|
|
508
529
|
const localName = getLocalName(child.name);
|
|
509
530
|
if (localName === "p") {
|
|
510
531
|
const para = parseParagraph(child, styles, theme, numbering, rels, media, options);
|
|
511
|
-
enrichParagraphTextBoxes(para, child, styles, theme, numbering, rels, media);
|
|
532
|
+
enrichParagraphTextBoxes(para, child, styles, theme, numbering, rels, media, parseTable);
|
|
512
533
|
prependPendingBookmarkMarkers(para, pendingBookmarkMarkers);
|
|
513
534
|
content.push(para);
|
|
514
535
|
} else if (localName === "tbl") {
|
|
@@ -827,4 +848,4 @@ function isFloatingTable(table) {
|
|
|
827
848
|
return table.formatting?.floating !== void 0;
|
|
828
849
|
}
|
|
829
850
|
//#endregion
|
|
830
|
-
export { getHeaderRows, getTableColumnCount, getTableRowCount, getTableText, hasHeaderRow, isCellHorizontallyMerged, isCellMergeContinuation, isCellMergeStart, isFloatingTable, parseBorderSpec, parseCellMargins, parseConditionalFormatStyle, parseFloatingTableProperties, parseShading, parseTable, parseTableBorders, parseTableCell, parseTableCellProperties, parseTableGrid, parseTableLook, parseTableMeasurement, parseTableProperties, parseTableRow, parseTableRowProperties };
|
|
851
|
+
export { MAX_TABLE_COLUMNS, getHeaderRows, getTableColumnCount, getTableRowCount, getTableText, hasHeaderRow, isCellHorizontallyMerged, isCellMergeContinuation, isCellMergeStart, isFloatingTable, parseBorderSpec, parseCellMargins, parseConditionalFormatStyle, parseFloatingTableProperties, parseShading, parseTable, parseTableBorders, parseTableCell, parseTableCellProperties, parseTableGrid, parseTableLook, parseTableMeasurement, parseTableProperties, parseTableRow, parseTableRowProperties };
|
|
@@ -15,16 +15,16 @@ declare function extractTextBoxContentElements(txbxContent: XmlElement | null):
|
|
|
15
15
|
/**
|
|
16
16
|
* Type for the paragraph parser function to avoid circular imports
|
|
17
17
|
*/
|
|
18
|
-
type ParagraphParserFn = (node: XmlElement, styles: StyleMap | null, theme: document_d_exports.Theme | null, numbering: NumberingMap | null, rels
|
|
18
|
+
type ParagraphParserFn = (node: 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) => document_d_exports.Paragraph;
|
|
19
19
|
/**
|
|
20
20
|
* Type for the table parser function to avoid circular imports
|
|
21
21
|
*/
|
|
22
|
-
type TableParserFn = (node: XmlElement, styles: StyleMap | null, theme: document_d_exports.Theme | null, numbering: NumberingMap | null, rels
|
|
22
|
+
type TableParserFn = (node: 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) => document_d_exports.Table;
|
|
23
23
|
/**
|
|
24
24
|
* Parse text box content with provided parser functions
|
|
25
25
|
* This avoids circular dependencies by accepting parser functions as parameters
|
|
26
26
|
*/
|
|
27
|
-
declare function parseTextBoxContent(txbxContent: XmlElement | null, parseParagraph: ParagraphParserFn, parseTable: TableParserFn | null, styles: StyleMap | null, theme: document_d_exports.Theme | null, numbering: NumberingMap | null, rels
|
|
27
|
+
declare function parseTextBoxContent(txbxContent: XmlElement | null, parseParagraph: ParagraphParserFn, parseTable: TableParserFn | null, 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): (document_d_exports.Paragraph | document_d_exports.Table)[];
|
|
28
28
|
/**
|
|
29
29
|
* Check if a drawing element contains a text box
|
|
30
30
|
* Text boxes are shapes with wps:txbx content
|
|
@@ -44,20 +44,20 @@ function extractTextBoxContentElements(txbxContent) {
|
|
|
44
44
|
* Parse text box content with provided parser functions
|
|
45
45
|
* This avoids circular dependencies by accepting parser functions as parameters
|
|
46
46
|
*/
|
|
47
|
-
function parseTextBoxContent(txbxContent, parseParagraph, parseTable, styles, theme, numbering, rels,
|
|
47
|
+
function parseTextBoxContent(txbxContent, parseParagraph, parseTable, styles, theme, numbering, rels, media) {
|
|
48
48
|
if (!txbxContent) return [];
|
|
49
|
-
const
|
|
49
|
+
const blocks = [];
|
|
50
50
|
const children = getChildElements(txbxContent);
|
|
51
51
|
for (const child of children) {
|
|
52
52
|
const name = child.name || "";
|
|
53
53
|
const colonIdx = name.indexOf(":");
|
|
54
54
|
const localName = colonIdx !== -1 ? name.slice(colonIdx + 1) : name;
|
|
55
55
|
if (localName === "p") {
|
|
56
|
-
const paragraph = parseParagraph(child, styles, theme, numbering, rels);
|
|
57
|
-
|
|
58
|
-
} else if (localName === "tbl" && parseTable)
|
|
56
|
+
const paragraph = parseParagraph(child, styles, theme, numbering, rels, media);
|
|
57
|
+
blocks.push(paragraph);
|
|
58
|
+
} else if (localName === "tbl" && parseTable) blocks.push(parseTable(child, styles, theme, numbering, rels, media));
|
|
59
59
|
}
|
|
60
|
-
return
|
|
60
|
+
return blocks;
|
|
61
61
|
}
|
|
62
62
|
/**
|
|
63
63
|
* Check if a drawing element contains a text box
|
|
@@ -232,16 +232,20 @@ function hasTextBoxContent(textBox) {
|
|
|
232
232
|
* Get plain text from text box (helper for search/indexing)
|
|
233
233
|
*/
|
|
234
234
|
function getTextBoxText(textBox) {
|
|
235
|
-
|
|
236
|
-
|
|
235
|
+
return textBox.content.map(getTextBoxBlockText).join("\n");
|
|
236
|
+
}
|
|
237
|
+
const getTextBoxBlockText = (block) => {
|
|
238
|
+
if (block.type === "paragraph") {
|
|
237
239
|
const runTexts = [];
|
|
238
|
-
for (const item of
|
|
240
|
+
for (const item of block.content) {
|
|
241
|
+
if (item.type !== "run") continue;
|
|
239
242
|
for (const content of item.content) if (content.type === "text") runTexts.push(content.text);
|
|
240
243
|
}
|
|
241
|
-
|
|
244
|
+
return runTexts.join("");
|
|
242
245
|
}
|
|
243
|
-
return
|
|
244
|
-
|
|
246
|
+
if (block.type === "table") return block.rows.map((row) => row.cells.map((cell) => cell.content.map(getTextBoxBlockText).join("\n")).join(" ")).join("\n");
|
|
247
|
+
return block.content.map(getTextBoxBlockText).join("\n");
|
|
248
|
+
};
|
|
245
249
|
/**
|
|
246
250
|
* Resolve fill color to CSS color string
|
|
247
251
|
*/
|
package/dist/docx/unzip.js
CHANGED
|
@@ -261,6 +261,7 @@ function isPreservableDocxEntry(path) {
|
|
|
261
261
|
if (!isSafeDocxPath(path)) return false;
|
|
262
262
|
const lowerPath = path.toLowerCase();
|
|
263
263
|
if (lowerPath.startsWith("word/media/")) return PRESERVABLE_MEDIA_MIME_TYPES.has(getMediaMimeType(path));
|
|
264
|
+
if (lowerPath.startsWith("docprops/thumbnail.")) return PRESERVABLE_MEDIA_MIME_TYPES.has(getMediaMimeType(path));
|
|
264
265
|
if (lowerPath.startsWith("word/fonts/")) return true;
|
|
265
266
|
if (!(lowerPath.endsWith(".xml") || lowerPath.endsWith(".rels"))) return false;
|
|
266
267
|
return lowerPath === "[content_types].xml" || lowerPath.startsWith("_rels/") || lowerPath.startsWith("docprops/") || lowerPath.startsWith("word/") || lowerPath.startsWith("customxml/");
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { cloneWithXmlnsDeclarations, elementToXml, findAllDeep, findChild, getAttribute, getChildElements, getLocalName } from "./xmlParser.js";
|
|
2
2
|
import { pixelsToEmu } from "../utils/units.js";
|
|
3
|
+
import { sanitizeImageSrc } from "../utils/sanitizeImageSrc.js";
|
|
3
4
|
import { resolveImageData } from "./imageParser.js";
|
|
4
5
|
import { isWatermarkShape } from "./watermarkParser.js";
|
|
5
6
|
//#region src/docx/vmlImageParser.ts
|
|
@@ -49,16 +50,22 @@ function cssLengthToPx(raw) {
|
|
|
49
50
|
default: return;
|
|
50
51
|
}
|
|
51
52
|
}
|
|
53
|
+
const PROTOTYPE_POLLUTION_KEYS = /* @__PURE__ */ new Set([
|
|
54
|
+
"__proto__",
|
|
55
|
+
"constructor",
|
|
56
|
+
"prototype"
|
|
57
|
+
]);
|
|
52
58
|
/** Read a `style="k1:v1;k2:v2"` attribute into a lowercased key/value record. */
|
|
53
59
|
function parseStyleAttr(style) {
|
|
54
|
-
const out =
|
|
60
|
+
const out = Object.create(null);
|
|
55
61
|
if (!style) return out;
|
|
56
62
|
for (const decl of style.split(";")) {
|
|
57
63
|
const colon = decl.indexOf(":");
|
|
58
64
|
if (colon < 0) continue;
|
|
59
65
|
const key = decl.slice(0, colon).trim().toLowerCase();
|
|
60
66
|
const value = decl.slice(colon + 1).trim();
|
|
61
|
-
if (key
|
|
67
|
+
if (!key || PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
|
|
68
|
+
out[key] = value;
|
|
62
69
|
}
|
|
63
70
|
return out;
|
|
64
71
|
}
|
|
@@ -216,7 +223,8 @@ function parseVmlImageContent(pictElement, rels, media, rootXmlns = {}) {
|
|
|
216
223
|
},
|
|
217
224
|
wrap: { type: "inline" }
|
|
218
225
|
};
|
|
219
|
-
|
|
226
|
+
const safeSrc = sanitizeImageSrc(src);
|
|
227
|
+
if (safeSrc) image.src = safeSrc;
|
|
220
228
|
if (mimeType) image.mimeType = mimeType;
|
|
221
229
|
if (filename) image.filename = filename;
|
|
222
230
|
const title = getAttribute(imagedata, "o", "title");
|
package/dist/docx/xmlParser.js
CHANGED
|
@@ -500,6 +500,13 @@ function findAllDeep(root, namespace, localName) {
|
|
|
500
500
|
return results;
|
|
501
501
|
}
|
|
502
502
|
/**
|
|
503
|
+
* Sanity cap on distinct `xmlns:*` declarations collected per element. Real
|
|
504
|
+
* documents declare a handful; a hostile element with thousands of unique
|
|
505
|
+
* prefixes would otherwise get replayed onto every captured `w:pict` rawXml
|
|
506
|
+
* subtree that inherits from it.
|
|
507
|
+
*/
|
|
508
|
+
const MAX_XMLNS_DECLARATIONS_PER_ELEMENT = 64;
|
|
509
|
+
/**
|
|
503
510
|
* Collect every `xmlns` / `xmlns:*` declaration from an element's attributes.
|
|
504
511
|
*
|
|
505
512
|
* The serializer's hard-coded root namespaces only cover canonical prefixes
|
|
@@ -512,7 +519,10 @@ function collectXmlnsDeclarations(element) {
|
|
|
512
519
|
const out = {};
|
|
513
520
|
const attrs = element.attributes;
|
|
514
521
|
if (!attrs) return out;
|
|
515
|
-
for (const [key, value] of Object.entries(attrs))
|
|
522
|
+
for (const [key, value] of Object.entries(attrs)) {
|
|
523
|
+
if (Object.keys(out).length >= MAX_XMLNS_DECLARATIONS_PER_ELEMENT) break;
|
|
524
|
+
if ((key === "xmlns" || key.startsWith("xmlns:")) && value !== void 0) out[key] = String(value);
|
|
525
|
+
}
|
|
516
526
|
return out;
|
|
517
527
|
}
|
|
518
528
|
/**
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { XMLValidator } from "fast-xml-parser";
|
|
2
|
+
//#region src/docx/xmlSafety.ts
|
|
3
|
+
const DOCTYPE_PATTERN = /<!DOCTYPE(?:\s|>)/iu;
|
|
4
|
+
const getDocxXmlSafetyIssue = (xml) => {
|
|
5
|
+
if (DOCTYPE_PATTERN.test(xml)) return "doctype-forbidden";
|
|
6
|
+
return XMLValidator.validate(xml) === true ? null : "not-well-formed";
|
|
7
|
+
};
|
|
8
|
+
//#endregion
|
|
9
|
+
export { getDocxXmlSafetyIssue };
|
|
@@ -196,9 +196,7 @@ function collectFieldRuns(block, out) {
|
|
|
196
196
|
if (block.kind === "paragraph") {
|
|
197
197
|
for (const run of block.runs) if (run.kind === "field") out.push(run);
|
|
198
198
|
} else if (block.kind === "table") for (const row of block.rows) for (const cell of row.cells) for (const cellBlock of cell.blocks) collectFieldRuns(cellBlock, out);
|
|
199
|
-
else if (block.kind === "textBox")
|
|
200
|
-
for (const paragraph of block.content) for (const run of paragraph.runs) if (run.kind === "field") out.push(run);
|
|
201
|
-
}
|
|
199
|
+
else if (block.kind === "textBox") for (const child of block.content) collectFieldRuns(child, out);
|
|
202
200
|
}
|
|
203
201
|
//#endregion
|
|
204
202
|
export { buildHeaderFooterFieldValues, fieldValuesEqual, resolveFieldValues };
|
|
@@ -15,9 +15,24 @@
|
|
|
15
15
|
*
|
|
16
16
|
* Ported from eigenpal/docx-editor (see NOTICE.md).
|
|
17
17
|
*/
|
|
18
|
+
/**
|
|
19
|
+
* Build the per-document scoped family name an embedded face registers
|
|
20
|
+
* under. `docNonce` is fresh per document load (see {@link getEmbeddedFontFaces}),
|
|
21
|
+
* so the same original name in two different documents (or two loads of the
|
|
22
|
+
* same document) never collides.
|
|
23
|
+
*/
|
|
24
|
+
declare function scopeEmbeddedFontFamily(docNonce: string, originalFamily: string): string;
|
|
18
25
|
/** A single de-obfuscated embedded font face, ready to register as `@font-face`. */
|
|
19
26
|
type EmbeddedFont = {
|
|
20
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* Family name to register the face under (`@font-face`/`FontFace`).
|
|
29
|
+
* Always a per-document SCOPED name (see {@link scopeEmbeddedFontFamily}) —
|
|
30
|
+
* never the raw `w:font w:name` from the DOCX. Use `originalFamily` (and
|
|
31
|
+
* {@link buildEmbeddedFontFamilyMap}) to resolve document runs, which
|
|
32
|
+
* still reference the font by its original DOCX name, to this family.
|
|
33
|
+
*/
|
|
34
|
+
family: string; /** Original Word font name (`w:font w:name`), before scoping. */
|
|
35
|
+
originalFamily: string; /** CSS `font-style` the face maps to (`embed*Italic` → `italic`). */
|
|
21
36
|
style: "normal" | "italic"; /** CSS `font-weight` the face maps to (`embedBold*` → `700`). */
|
|
22
37
|
weight: 400 | 700; /** De-obfuscated OpenType/TrueType bytes (backed by a fresh, non-shared buffer). */
|
|
23
38
|
bytes: Uint8Array<ArrayBuffer>; /** Whether the source face was subsetted (`w:subsetted`). */
|
|
@@ -33,14 +48,27 @@ type EmbeddedFontParts = {
|
|
|
33
48
|
* Resolve and de-obfuscate every embedded font face declared in a font table.
|
|
34
49
|
* Pure and DOM-free. Faces whose relationship or binary is missing are skipped,
|
|
35
50
|
* so the result only contains faces that produced usable bytes.
|
|
51
|
+
*
|
|
52
|
+
* `docNonce` scopes every face's registered family to one document load (see
|
|
53
|
+
* {@link scopeEmbeddedFontFamily}); defaults to a fresh random id so callers
|
|
54
|
+
* that don't care about a specific value still get per-call isolation. Pass
|
|
55
|
+
* an explicit value for deterministic tests.
|
|
56
|
+
*/
|
|
57
|
+
declare function getEmbeddedFontFaces(parts: EmbeddedFontParts, docNonce?: string): EmbeddedFont[];
|
|
58
|
+
/**
|
|
59
|
+
* Build the original DOCX font name → scoped registered family map for a set
|
|
60
|
+
* of resolved embedded faces. Callers thread this into font resolution (see
|
|
61
|
+
* `utils/fontResolver.ts`'s `setEmbeddedFontFamilyMap`) so the document's own
|
|
62
|
+
* runs — which still carry the original name — keep resolving to the scoped
|
|
63
|
+
* face that was actually registered on `document.fonts`.
|
|
36
64
|
*/
|
|
37
|
-
declare function
|
|
65
|
+
declare function buildEmbeddedFontFamilyMap(faces: readonly EmbeddedFont[]): Map<string, string>;
|
|
38
66
|
/**
|
|
39
67
|
* Extract every embedded font face from a raw `.docx` buffer. Unzips the
|
|
40
68
|
* package, then resolves + de-obfuscates the faces via
|
|
41
69
|
* {@link getEmbeddedFontFaces}. Returns an empty list for documents with no
|
|
42
|
-
* embedded fonts.
|
|
70
|
+
* embedded fonts. See {@link getEmbeddedFontFaces} for `docNonce`.
|
|
43
71
|
*/
|
|
44
|
-
declare function extractEmbeddedFonts(buffer: ArrayBuffer): Promise<EmbeddedFont[]>;
|
|
72
|
+
declare function extractEmbeddedFonts(buffer: ArrayBuffer, docNonce?: string): Promise<EmbeddedFont[]>;
|
|
45
73
|
//#endregion
|
|
46
|
-
export { EmbeddedFont, EmbeddedFontParts, extractEmbeddedFonts, getEmbeddedFontFaces };
|
|
74
|
+
export { EmbeddedFont, EmbeddedFontParts, buildEmbeddedFontFamilyMap, extractEmbeddedFonts, getEmbeddedFontFaces, scopeEmbeddedFontFamily };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { parseRelationships, resolveRelativePath } from "../docx/relsParser.js";
|
|
2
|
+
import { generateHexId } from "../utils/hexId.js";
|
|
2
3
|
import { unzipDocx } from "../docx/unzip.js";
|
|
3
4
|
import { deobfuscateFont, isValidFontKey } from "./fontDeobfuscation.js";
|
|
4
5
|
import { parseEmbeddedFontTable } from "./embeddedFontTable.js";
|
|
@@ -19,6 +20,16 @@ import { parseEmbeddedFontTable } from "./embeddedFontTable.js";
|
|
|
19
20
|
*
|
|
20
21
|
* Ported from eigenpal/docx-editor (see NOTICE.md).
|
|
21
22
|
*/
|
|
23
|
+
const SCOPED_FAMILY_PREFIX = "folio-embedded";
|
|
24
|
+
/**
|
|
25
|
+
* Build the per-document scoped family name an embedded face registers
|
|
26
|
+
* under. `docNonce` is fresh per document load (see {@link getEmbeddedFontFaces}),
|
|
27
|
+
* so the same original name in two different documents (or two loads of the
|
|
28
|
+
* same document) never collides.
|
|
29
|
+
*/
|
|
30
|
+
function scopeEmbeddedFontFamily(docNonce, originalFamily) {
|
|
31
|
+
return `${SCOPED_FAMILY_PREFIX}-${docNonce}-${originalFamily}`;
|
|
32
|
+
}
|
|
22
33
|
/** Pairs each embed field with the CSS weight/style it renders as. */
|
|
23
34
|
const EMBED_KINDS = [
|
|
24
35
|
{
|
|
@@ -57,7 +68,7 @@ function lookupFontData(resolvedPath, fonts) {
|
|
|
57
68
|
const wanted = normalizePackagePath(resolvedPath);
|
|
58
69
|
for (const [path, data] of fonts) if (normalizePackagePath(path) === wanted) return data;
|
|
59
70
|
}
|
|
60
|
-
function resolveFace(
|
|
71
|
+
function resolveFace(originalFamily, ref, kind, fonts, rels, docNonce) {
|
|
61
72
|
const target = rels.get(ref.relId)?.target;
|
|
62
73
|
if (!target) return null;
|
|
63
74
|
const raw = lookupFontData(resolveRelativePath(FONTTABLE_RELS_BASE_PATH, target), fonts);
|
|
@@ -65,7 +76,8 @@ function resolveFace(family, ref, kind, fonts, rels) {
|
|
|
65
76
|
const bytes = new Uint8Array(raw);
|
|
66
77
|
const data = ref.fontKey && isValidFontKey(ref.fontKey) ? deobfuscateFont(bytes, ref.fontKey) : bytes;
|
|
67
78
|
return {
|
|
68
|
-
family,
|
|
79
|
+
family: scopeEmbeddedFontFamily(docNonce, originalFamily),
|
|
80
|
+
originalFamily,
|
|
69
81
|
style: kind.style,
|
|
70
82
|
weight: kind.weight,
|
|
71
83
|
bytes: data,
|
|
@@ -76,8 +88,13 @@ function resolveFace(family, ref, kind, fonts, rels) {
|
|
|
76
88
|
* Resolve and de-obfuscate every embedded font face declared in a font table.
|
|
77
89
|
* Pure and DOM-free. Faces whose relationship or binary is missing are skipped,
|
|
78
90
|
* so the result only contains faces that produced usable bytes.
|
|
91
|
+
*
|
|
92
|
+
* `docNonce` scopes every face's registered family to one document load (see
|
|
93
|
+
* {@link scopeEmbeddedFontFamily}); defaults to a fresh random id so callers
|
|
94
|
+
* that don't care about a specific value still get per-call isolation. Pass
|
|
95
|
+
* an explicit value for deterministic tests.
|
|
79
96
|
*/
|
|
80
|
-
function getEmbeddedFontFaces(parts) {
|
|
97
|
+
function getEmbeddedFontFaces(parts, docNonce = generateHexId()) {
|
|
81
98
|
const entries = parseEmbeddedFontTable(parts.fontTableXml);
|
|
82
99
|
if (entries.length === 0) return [];
|
|
83
100
|
if (!parts.fontTableRelsXml || parts.fonts.size === 0) return [];
|
|
@@ -86,11 +103,23 @@ function getEmbeddedFontFaces(parts) {
|
|
|
86
103
|
for (const entry of entries) for (const kind of EMBED_KINDS) {
|
|
87
104
|
const ref = entry[kind.ref];
|
|
88
105
|
if (!ref) continue;
|
|
89
|
-
const face = resolveFace(entry.name, ref, kind, parts.fonts, rels);
|
|
106
|
+
const face = resolveFace(entry.name, ref, kind, parts.fonts, rels, docNonce);
|
|
90
107
|
if (face) faces.push(face);
|
|
91
108
|
}
|
|
92
109
|
return faces;
|
|
93
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* Build the original DOCX font name → scoped registered family map for a set
|
|
113
|
+
* of resolved embedded faces. Callers thread this into font resolution (see
|
|
114
|
+
* `utils/fontResolver.ts`'s `setEmbeddedFontFamilyMap`) so the document's own
|
|
115
|
+
* runs — which still carry the original name — keep resolving to the scoped
|
|
116
|
+
* face that was actually registered on `document.fonts`.
|
|
117
|
+
*/
|
|
118
|
+
function buildEmbeddedFontFamilyMap(faces) {
|
|
119
|
+
const map = /* @__PURE__ */ new Map();
|
|
120
|
+
for (const face of faces) map.set(face.originalFamily, face.family);
|
|
121
|
+
return map;
|
|
122
|
+
}
|
|
94
123
|
function findFontTableRels(allXml) {
|
|
95
124
|
for (const [path, xml] of allXml) if (normalizePackagePath(path) === FONTTABLE_RELS_PATH) return xml;
|
|
96
125
|
}
|
|
@@ -98,15 +127,15 @@ function findFontTableRels(allXml) {
|
|
|
98
127
|
* Extract every embedded font face from a raw `.docx` buffer. Unzips the
|
|
99
128
|
* package, then resolves + de-obfuscates the faces via
|
|
100
129
|
* {@link getEmbeddedFontFaces}. Returns an empty list for documents with no
|
|
101
|
-
* embedded fonts.
|
|
130
|
+
* embedded fonts. See {@link getEmbeddedFontFaces} for `docNonce`.
|
|
102
131
|
*/
|
|
103
|
-
async function extractEmbeddedFonts(buffer) {
|
|
132
|
+
async function extractEmbeddedFonts(buffer, docNonce = generateHexId()) {
|
|
104
133
|
const raw = await unzipDocx(buffer);
|
|
105
134
|
return getEmbeddedFontFaces({
|
|
106
135
|
fontTableXml: raw.fontTableXml,
|
|
107
136
|
fontTableRelsXml: findFontTableRels(raw.allXml),
|
|
108
137
|
fonts: raw.fonts
|
|
109
|
-
});
|
|
138
|
+
}, docNonce);
|
|
110
139
|
}
|
|
111
140
|
//#endregion
|
|
112
|
-
export { extractEmbeddedFonts, getEmbeddedFontFaces };
|
|
141
|
+
export { buildEmbeddedFontFamilyMap, extractEmbeddedFonts, getEmbeddedFontFaces, scopeEmbeddedFontFamily };
|
|
@@ -493,6 +493,7 @@ declare const CATALOGS: {
|
|
|
493
493
|
readonly rowDeleted: "Row deleted";
|
|
494
494
|
readonly rowInserted: "Row inserted";
|
|
495
495
|
readonly rowPropertiesChanged: "Row formatting changed";
|
|
496
|
+
readonly runPropertiesChanged: "Text formatting changed";
|
|
496
497
|
readonly tableDeleted: "Table deleted";
|
|
497
498
|
readonly tableInserted: "Table inserted";
|
|
498
499
|
readonly tablePropertiesChanged: "Table formatting changed";
|
|
@@ -1135,6 +1136,7 @@ declare const CATALOGS: {
|
|
|
1135
1136
|
readonly rowDeleted: "Zeile gelöscht";
|
|
1136
1137
|
readonly rowInserted: "Zeile eingefügt";
|
|
1137
1138
|
readonly rowPropertiesChanged: "Zeilenformatierung geändert";
|
|
1139
|
+
readonly runPropertiesChanged: "Textformatierung geändert";
|
|
1138
1140
|
readonly tableDeleted: "Tabelle gelöscht";
|
|
1139
1141
|
readonly tableInserted: "Tabelle eingefügt";
|
|
1140
1142
|
readonly tablePropertiesChanged: "Tabellenformatierung geändert";
|
|
@@ -1777,6 +1779,7 @@ declare const CATALOGS: {
|
|
|
1777
1779
|
readonly rowDeleted: "Ligne supprimée";
|
|
1778
1780
|
readonly rowInserted: "Ligne insérée";
|
|
1779
1781
|
readonly rowPropertiesChanged: "Mise en forme de ligne modifiée";
|
|
1782
|
+
readonly runPropertiesChanged: "Mise en forme du texte modifiée";
|
|
1780
1783
|
readonly tableDeleted: "Tableau supprimé";
|
|
1781
1784
|
readonly tableInserted: "Tableau inséré";
|
|
1782
1785
|
readonly tablePropertiesChanged: "Mise en forme de tableau modifiée";
|
|
@@ -2419,6 +2422,7 @@ declare const CATALOGS: {
|
|
|
2419
2422
|
readonly rowDeleted: "Fila eliminada";
|
|
2420
2423
|
readonly rowInserted: "Fila insertada";
|
|
2421
2424
|
readonly rowPropertiesChanged: "Formato de fila cambiado";
|
|
2425
|
+
readonly runPropertiesChanged: "Formato de texto cambiado";
|
|
2422
2426
|
readonly tableDeleted: "Tabla eliminada";
|
|
2423
2427
|
readonly tableInserted: "Tabla insertada";
|
|
2424
2428
|
readonly tablePropertiesChanged: "Formato de tabla cambiado";
|
|
@@ -3061,6 +3065,7 @@ declare const CATALOGS: {
|
|
|
3061
3065
|
readonly rowDeleted: "Řádek odstraněn";
|
|
3062
3066
|
readonly rowInserted: "Řádek vložen";
|
|
3063
3067
|
readonly rowPropertiesChanged: "Formátování řádku změněno";
|
|
3068
|
+
readonly runPropertiesChanged: "Formátování textu změněno";
|
|
3064
3069
|
readonly tableDeleted: "Tabulka odstraněna";
|
|
3065
3070
|
readonly tableInserted: "Tabulka vložena";
|
|
3066
3071
|
readonly tablePropertiesChanged: "Formátování tabulky změněno";
|
|
@@ -3703,6 +3708,7 @@ declare const CATALOGS: {
|
|
|
3703
3708
|
readonly rowDeleted: "تم حذف الصف";
|
|
3704
3709
|
readonly rowInserted: "تم إدراج الصف";
|
|
3705
3710
|
readonly rowPropertiesChanged: "تم تغيير تنسيق الصف";
|
|
3711
|
+
readonly runPropertiesChanged: "تم تغيير تنسيق النص";
|
|
3706
3712
|
readonly tableDeleted: "تم حذف الجدول";
|
|
3707
3713
|
readonly tableInserted: "تم إدراج الجدول";
|
|
3708
3714
|
readonly tablePropertiesChanged: "تم تغيير تنسيق الجدول";
|
|
@@ -4345,6 +4351,7 @@ declare const CATALOGS: {
|
|
|
4345
4351
|
readonly rowDeleted: "Rida kustutatud";
|
|
4346
4352
|
readonly rowInserted: "Rida lisatud";
|
|
4347
4353
|
readonly rowPropertiesChanged: "Rea vormingut muudeti";
|
|
4354
|
+
readonly runPropertiesChanged: "Teksti vormingut muudeti";
|
|
4348
4355
|
readonly tableDeleted: "Tabel kustutatud";
|
|
4349
4356
|
readonly tableInserted: "Tabel lisatud";
|
|
4350
4357
|
readonly tablePropertiesChanged: "Tabeli vormingut muudeti";
|
|
@@ -4987,6 +4994,7 @@ declare const CATALOGS: {
|
|
|
4987
4994
|
readonly rowDeleted: "השורה נמחקה";
|
|
4988
4995
|
readonly rowInserted: "השורה נוספה";
|
|
4989
4996
|
readonly rowPropertiesChanged: "עיצוב השורה השתנה";
|
|
4997
|
+
readonly runPropertiesChanged: "עיצוב הטקסט השתנה";
|
|
4990
4998
|
readonly tableDeleted: "הטבלה נמחקה";
|
|
4991
4999
|
readonly tableInserted: "הטבלה נוספה";
|
|
4992
5000
|
readonly tablePropertiesChanged: "עיצוב הטבלה השתנה";
|
|
@@ -5629,6 +5637,7 @@ declare const CATALOGS: {
|
|
|
5629
5637
|
readonly rowDeleted: "पंक्ति हटाई गई";
|
|
5630
5638
|
readonly rowInserted: "पंक्ति सम्मिलित की गई";
|
|
5631
5639
|
readonly rowPropertiesChanged: "पंक्ति प्रारूपण बदला गया";
|
|
5640
|
+
readonly runPropertiesChanged: "पाठ स्वरूपण बदला गया";
|
|
5632
5641
|
readonly tableDeleted: "तालिका हटाई गई";
|
|
5633
5642
|
readonly tableInserted: "तालिका सम्मिलित की गई";
|
|
5634
5643
|
readonly tablePropertiesChanged: "तालिका प्रारूपण बदला गया";
|
|
@@ -6271,6 +6280,7 @@ declare const CATALOGS: {
|
|
|
6271
6280
|
readonly rowDeleted: "Sor törölve";
|
|
6272
6281
|
readonly rowInserted: "Sor beszúrva";
|
|
6273
6282
|
readonly rowPropertiesChanged: "Sorformázás megváltozott";
|
|
6283
|
+
readonly runPropertiesChanged: "Szövegformázás megváltozott";
|
|
6274
6284
|
readonly tableDeleted: "Táblázat törölve";
|
|
6275
6285
|
readonly tableInserted: "Táblázat beszúrva";
|
|
6276
6286
|
readonly tablePropertiesChanged: "Táblázatformázás megváltozott";
|
|
@@ -6913,6 +6923,7 @@ declare const CATALOGS: {
|
|
|
6913
6923
|
readonly rowDeleted: "Eilutė panaikinta";
|
|
6914
6924
|
readonly rowInserted: "Eilutė įterpta";
|
|
6915
6925
|
readonly rowPropertiesChanged: "Eilutės formatavimas pakeistas";
|
|
6926
|
+
readonly runPropertiesChanged: "Teksto formatavimas pakeistas";
|
|
6916
6927
|
readonly tableDeleted: "Lentelė panaikinta";
|
|
6917
6928
|
readonly tableInserted: "Lentelė įterpta";
|
|
6918
6929
|
readonly tablePropertiesChanged: "Lentelės formatavimas pakeistas";
|
|
@@ -7555,6 +7566,7 @@ declare const CATALOGS: {
|
|
|
7555
7566
|
readonly rowDeleted: "Rinda izdzēsta";
|
|
7556
7567
|
readonly rowInserted: "Rinda ievietota";
|
|
7557
7568
|
readonly rowPropertiesChanged: "Rindas formatējums mainīts";
|
|
7569
|
+
readonly runPropertiesChanged: "Teksta formatējums mainīts";
|
|
7558
7570
|
readonly tableDeleted: "Tabula izdzēsta";
|
|
7559
7571
|
readonly tableInserted: "Tabula ievietota";
|
|
7560
7572
|
readonly tablePropertiesChanged: "Tabulas formatējums mainīts";
|
|
@@ -8197,6 +8209,7 @@ declare const CATALOGS: {
|
|
|
8197
8209
|
readonly rowDeleted: "Usunięto wiersz";
|
|
8198
8210
|
readonly rowInserted: "Wstawiono wiersz";
|
|
8199
8211
|
readonly rowPropertiesChanged: "Zmieniono formatowanie wiersza";
|
|
8212
|
+
readonly runPropertiesChanged: "Zmieniono formatowanie tekstu";
|
|
8200
8213
|
readonly tableDeleted: "Usunięto tabelę";
|
|
8201
8214
|
readonly tableInserted: "Wstawiono tabelę";
|
|
8202
8215
|
readonly tablePropertiesChanged: "Zmieniono formatowanie tabeli";
|
|
@@ -8839,6 +8852,7 @@ declare const CATALOGS: {
|
|
|
8839
8852
|
readonly rowDeleted: "Linha excluída";
|
|
8840
8853
|
readonly rowInserted: "Linha inserida";
|
|
8841
8854
|
readonly rowPropertiesChanged: "Formatação da linha alterada";
|
|
8855
|
+
readonly runPropertiesChanged: "Formatação do texto alterada";
|
|
8842
8856
|
readonly tableDeleted: "Tabela excluída";
|
|
8843
8857
|
readonly tableInserted: "Tabela inserida";
|
|
8844
8858
|
readonly tablePropertiesChanged: "Formatação da tabela alterada";
|
|
@@ -9481,6 +9495,7 @@ declare const CATALOGS: {
|
|
|
9481
9495
|
readonly rowDeleted: "Riadok odstránený";
|
|
9482
9496
|
readonly rowInserted: "Riadok vložený";
|
|
9483
9497
|
readonly rowPropertiesChanged: "Formátovanie riadka zmenené";
|
|
9498
|
+
readonly runPropertiesChanged: "Formátovanie textu zmenené";
|
|
9484
9499
|
readonly tableDeleted: "Tabuľka odstránená";
|
|
9485
9500
|
readonly tableInserted: "Tabuľka vložená";
|
|
9486
9501
|
readonly tablePropertiesChanged: "Formátovanie tabuľky zmenené";
|
|
@@ -10123,6 +10138,7 @@ declare const CATALOGS: {
|
|
|
10123
10138
|
readonly rowDeleted: "Satır silindi";
|
|
10124
10139
|
readonly rowInserted: "Satır eklendi";
|
|
10125
10140
|
readonly rowPropertiesChanged: "Satır biçimlendirmesi değiştirildi";
|
|
10141
|
+
readonly runPropertiesChanged: "Metin biçimlendirmesi değiştirildi";
|
|
10126
10142
|
readonly tableDeleted: "Tablo silindi";
|
|
10127
10143
|
readonly tableInserted: "Tablo eklendi";
|
|
10128
10144
|
readonly tablePropertiesChanged: "Tablo biçimlendirmesi değiştirildi";
|
|
@@ -10765,6 +10781,7 @@ declare const CATALOGS: {
|
|
|
10765
10781
|
readonly rowDeleted: "已删除行";
|
|
10766
10782
|
readonly rowInserted: "已插入行";
|
|
10767
10783
|
readonly rowPropertiesChanged: "行格式已更改";
|
|
10784
|
+
readonly runPropertiesChanged: "文本格式已更改";
|
|
10768
10785
|
readonly tableDeleted: "已删除表格";
|
|
10769
10786
|
readonly tableInserted: "已插入表格";
|
|
10770
10787
|
readonly tablePropertiesChanged: "表格格式已更改";
|