@stll/folio-core 0.36.0 → 0.37.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/README.md +59 -1
- package/dist/ai-edits/apply.js +545 -296
- package/dist/ai-edits/block-identity.d.ts +4 -1
- package/dist/ai-edits/block-identity.js +4 -1
- package/dist/ai-edits/blockRange.js +14 -14
- package/dist/ai-edits/clean-text.d.ts +40 -1
- package/dist/ai-edits/clean-text.js +52 -2
- package/dist/ai-edits/headless.d.ts +3 -1
- package/dist/ai-edits/headless.js +133 -71
- package/dist/ai-edits/index.d.ts +3 -3
- package/dist/ai-edits/index.js +2 -2
- package/dist/ai-edits/read.js +38 -20
- package/dist/ai-edits/snapshot.d.ts +14 -6
- package/dist/ai-edits/snapshot.js +99 -19
- package/dist/ai-edits/table-cell-mutations.js +1 -1
- package/dist/ai-edits/table-row-column-mutations.js +7 -0
- package/dist/ai-edits/table-template.d.ts +11 -1
- package/dist/ai-edits/table-template.js +49 -17
- package/dist/ai-edits/types.d.ts +45 -57
- package/dist/ai-suggestions/conflict.js +1 -4
- package/dist/ai-suggestions/text-positions.d.ts +8 -0
- package/dist/ai-suggestions/text-positions.js +27 -5
- package/dist/compare/__fixtures__/body-sequence.js +3 -4
- package/dist/compare/column-alignment.d.ts +13 -13
- package/dist/compare/column-alignment.js +78 -39
- package/dist/compare/compare.d.ts +4 -3
- package/dist/compare/compare.js +41 -5
- package/dist/compare/content-alignment.d.ts +95 -0
- package/dist/compare/content-alignment.js +1450 -0
- package/dist/compare/content-types.d.ts +100 -0
- package/dist/compare/content-types.js +0 -0
- package/dist/compare/content.d.ts +209 -0
- package/dist/compare/content.js +885 -0
- package/dist/compare/formatting.d.ts +5 -5
- package/dist/compare/formatting.js +6 -4
- package/dist/compare/plan.d.ts +6 -1
- package/dist/compare/plan.js +169 -567
- package/dist/compare/scenario.d.ts +2 -2
- package/dist/compare/types.d.ts +3 -3
- package/dist/compare/verification.d.ts +2 -2
- package/dist/compare/verification.js +25 -8
- package/dist/compat/eigenpal.d.ts +5 -3
- package/dist/compat/eigenpal.js +3 -2
- package/dist/controller/headerFooterEditorManager.js +14 -6
- package/dist/controller/hiddenEditorManager.d.ts +7 -2
- package/dist/controller/hiddenEditorManager.js +15 -6
- package/dist/controller/layoutPipeline.js +5 -3
- package/dist/controller/noteEditorManager.js +12 -7
- package/dist/display-list/build/headerFooterPrimitives.js +1 -0
- package/dist/display-list/build/storyPrimitives.d.ts +5 -2
- package/dist/display-list/build/storyPrimitives.js +60 -3
- package/dist/display-list/build/tablePrimitives.js +30 -0
- package/dist/display-list/primitives.d.ts +1 -1
- package/dist/document-operations.d.ts +6 -4
- package/dist/document-operations.js +77 -12
- package/dist/docx/blockContentParser.js +6 -27
- package/dist/docx/ensureParaIds.js +9 -4
- package/dist/docx/numberingParser.d.ts +3 -1
- package/dist/docx/numberingParser.js +4 -1
- package/dist/docx/paragraphParser.js +7 -6
- package/dist/docx/paragraphTraversal.js +30 -34
- package/dist/docx/rezip.d.ts +0 -8
- package/dist/docx/rezip.js +41 -16
- package/dist/docx/runParser.js +4 -2
- package/dist/docx/serializer/paragraphSerializer.js +2 -0
- package/dist/docx/serializer/runSerializer.js +5 -3
- package/dist/docx/serializer/trackedChangeAttributes.d.ts +3 -1
- package/dist/docx/serializer/trackedChangeAttributes.js +11 -1
- package/dist/docx/server/build.d.ts +1 -1
- package/dist/headless-layout.js +5 -4
- package/dist/index.d.ts +5 -3
- package/dist/index.js +3 -2
- package/dist/internal/headlessRevisionResolution.d.ts +23 -0
- package/dist/internal/headlessRevisionResolution.js +155 -0
- package/dist/internal/headlessRevisionResolutionGuard.d.ts +12 -0
- package/dist/internal/headlessRevisionResolutionGuard.js +28 -0
- package/dist/internal/pageBreakRunDescendantIndex.d.ts +9 -0
- package/dist/internal/pageBreakRunDescendantIndex.js +27 -0
- package/dist/internal/pageBreakRunPartition.d.ts +26 -0
- package/dist/internal/pageBreakRunPartition.js +35 -0
- package/dist/internal/pageBreakRunSourceDescendantIndex.d.ts +15 -0
- package/dist/internal/pageBreakRunSourceDescendantIndex.js +126 -0
- package/dist/internal/sectionEndpointResolution.d.ts +32 -0
- package/dist/internal/sectionEndpointResolution.js +38 -0
- package/dist/layout-bridge/convert/footnoteLayout.js +1 -0
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +16 -4
- package/dist/layout-bridge/convert/headerFooterLayout.js +48 -5
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +4 -0
- package/dist/layout-bridge/convert/toFlowBlocks.js +379 -75
- package/dist/layout-bridge/dom/clickToPositionDom.d.ts +8 -1
- package/dist/layout-bridge/dom/clickToPositionDom.js +114 -40
- package/dist/layout-bridge/dom/textStreamDom.d.ts +24 -0
- package/dist/layout-bridge/dom/textStreamDom.js +75 -0
- package/dist/layout-bridge/headerFooterLayout.js +16 -30
- package/dist/layout-engine/index.js +12 -3
- package/dist/layout-engine/measure/tableFragmentBorderGeometry.d.ts +17 -0
- package/dist/layout-engine/measure/tableFragmentBorderGeometry.js +24 -0
- package/dist/layout-engine/renderedBreakReconciliation.js +1 -1
- package/dist/layout-engine/types.d.ts +7 -0
- package/dist/layout-painter/imageLayout.d.ts +1 -1
- package/dist/layout-painter/renderTable.js +20 -0
- package/dist/model.d.ts +1 -1
- package/dist/paged-layout/rangeProjection.js +6 -9
- package/dist/paged-layout/transactionDirtyRange.d.ts +3 -1
- package/dist/paged-layout/transactionDirtyRange.js +23 -1
- package/dist/prosemirror/attrs/index.d.ts +7 -3
- package/dist/prosemirror/attrs/index.js +113 -7
- package/dist/prosemirror/bookmarkBoundaryIntegrity.d.ts +9 -0
- package/dist/prosemirror/bookmarkBoundaryIntegrity.js +22 -0
- package/dist/prosemirror/commands/comments.d.ts +10 -1
- package/dist/prosemirror/commands/comments.js +190 -59
- package/dist/prosemirror/commands/formatPainter.d.ts +45 -10
- package/dist/prosemirror/commands/formatPainter.js +319 -63
- package/dist/prosemirror/commands/index.d.ts +2 -2
- package/dist/prosemirror/commands/pageBreak.d.ts +5 -2
- package/dist/prosemirror/commands/pageBreak.js +18 -36
- package/dist/prosemirror/commands/propertyChangeScope.d.ts +7 -5
- package/dist/prosemirror/commands/propertyChangeScope.js +27 -18
- package/dist/prosemirror/conversion/fromProseDoc.d.ts +7 -2
- package/dist/prosemirror/conversion/fromProseDoc.js +809 -209
- package/dist/prosemirror/conversion/runShadingMark.js +2 -2
- package/dist/prosemirror/conversion/toProseDoc.d.ts +26 -1
- package/dist/prosemirror/conversion/toProseDoc.js +416 -283
- package/dist/prosemirror/extensions/StarterKit.js +4 -0
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +12 -8
- package/dist/prosemirror/extensions/features/ListExtension.js +95 -123
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +1 -1
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +27 -1
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +134 -30
- package/dist/prosemirror/extensions/features/pasteCleanup.js +9 -15
- package/dist/prosemirror/extensions/marks/BoldExtension.js +4 -3
- package/dist/prosemirror/extensions/marks/CharacterStyleExtension.d.ts +4 -7
- package/dist/prosemirror/extensions/marks/CharacterStyleExtension.js +5 -11
- package/dist/prosemirror/extensions/marks/FontSizeExtension.js +3 -3
- package/dist/prosemirror/extensions/marks/ItalicExtension.js +4 -3
- package/dist/prosemirror/extensions/marks/PageBreakRunOwnerExtension.d.ts +13 -0
- package/dist/prosemirror/extensions/marks/PageBreakRunOwnerExtension.js +39 -0
- package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.d.ts +7 -1
- package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.js +67 -21
- package/dist/prosemirror/extensions/marks/markUtils.d.ts +8 -1
- package/dist/prosemirror/extensions/marks/markUtils.js +88 -2
- package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +44 -3
- package/dist/prosemirror/extensions/nodes/FieldExtension.js +1 -1
- package/dist/prosemirror/extensions/nodes/HardBreakExtension.js +15 -4
- package/dist/prosemirror/extensions/nodes/PageBreakExtension.d.ts +6 -0
- package/dist/prosemirror/extensions/nodes/PageBreakExtension.js +6 -0
- package/dist/prosemirror/extensions/nodes/PageBreakRunExtension.d.ts +6 -0
- package/dist/prosemirror/extensions/nodes/PageBreakRunExtension.js +36 -0
- package/dist/prosemirror/findReplaceSelection.js +8 -3
- package/dist/prosemirror/index.d.ts +3 -3
- package/dist/prosemirror/listMarker.d.ts +26 -1
- package/dist/prosemirror/listMarker.js +108 -14
- package/dist/prosemirror/pageBreakRunProjection.d.ts +28 -0
- package/dist/prosemirror/pageBreakRunProjection.js +47 -0
- package/dist/prosemirror/paraText.js +6 -0
- package/dist/prosemirror/paragraphSpacing.d.ts +29 -0
- package/dist/prosemirror/paragraphSpacing.js +125 -0
- package/dist/prosemirror/plugins/documentNumbering.d.ts +8 -0
- package/dist/prosemirror/plugins/documentNumbering.js +18 -0
- package/dist/prosemirror/plugins/pmTextScan.d.ts +3 -2
- package/dist/prosemirror/plugins/pmTextScan.js +14 -4
- package/dist/prosemirror/plugins/suggestionMode.js +8 -10
- package/dist/prosemirror/rebaseParagraphRunFormatting.d.ts +16 -0
- package/dist/prosemirror/rebaseParagraphRunFormatting.js +61 -0
- package/dist/prosemirror/runFormattingInlineCarriers.d.ts +64 -0
- package/dist/prosemirror/runFormattingInlineCarriers.js +121 -0
- package/dist/prosemirror/runFormattingProvenance.d.ts +12 -0
- package/dist/prosemirror/runFormattingProvenance.js +48 -0
- package/dist/prosemirror/runFormattingReconciliation.d.ts +25 -0
- package/dist/prosemirror/runFormattingReconciliation.js +54 -0
- package/dist/prosemirror/runPropertyChangeResolution.d.ts +18 -0
- package/dist/prosemirror/runPropertyChangeResolution.js +18 -0
- package/dist/prosemirror/runStyleFormatting.d.ts +50 -0
- package/dist/prosemirror/runStyleFormatting.js +105 -0
- package/dist/prosemirror/schema/index.d.ts +3 -3
- package/dist/prosemirror/schema/marks.d.ts +82 -9
- package/dist/prosemirror/schema/marks.js +73 -1
- package/dist/prosemirror/schema/nodes.d.ts +18 -5
- package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +14 -2
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +44 -23
- package/dist/prosemirror/styles/styleResolver.d.ts +10 -13
- package/dist/prosemirror/styles/styleResolver.js +3 -3
- package/dist/prosemirror/styles/styleToggleCascade.d.ts +8 -1
- package/dist/prosemirror/styles/styleToggleCascade.js +24 -1
- package/dist/prosemirror/tableGridMutation.d.ts +20 -0
- package/dist/prosemirror/tableGridMutation.js +30 -0
- package/dist/prosemirror/trackedRunInlineAtoms.d.ts +31 -0
- package/dist/prosemirror/trackedRunInlineAtoms.js +39 -0
- package/dist/prosemirror/utils/visualLineNavigation.js +27 -31
- package/dist/prosemirror/validation.js +23 -4
- package/dist/render-dom/HeaderFooterSelectionOverlay.js +20 -20
- package/dist/render-dom/RenderedDomContext.js +17 -34
- package/dist/server.d.ts +4 -4
- package/dist/server.js +2 -2
- package/dist/style-engine/styleEngine.d.ts +1 -1
- package/dist/utils/clipboard.js +1 -1
- package/dist/utils/findReplace.js +38 -21
- package/dist/version-comparison.d.ts +38 -44
- package/dist/version-comparison.js +270 -401
- package/package.json +3 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createTableCellFlowState, placeTableCellBlock } from "../../layout-engine/measure/tableCellFlow.js";
|
|
2
2
|
import { buildTableCellGrid, buildTableCellPlacements, getSourceCellAt } from "../../layout-engine/measure/tableCellGrid.js";
|
|
3
|
+
import { tableFragmentBottomBorders } from "../../layout-engine/measure/tableFragmentBorderGeometry.js";
|
|
3
4
|
import { resolveTableCellPadding } from "../../layout-engine/types.js";
|
|
4
5
|
import { HIT_REGION_KINDS } from "../primitives.js";
|
|
5
6
|
import { parseDisplayColor } from "./colors.js";
|
|
@@ -332,6 +333,28 @@ const paintTableBody = ({ composer, block, measure, xPx, yPx, fromRow, toRow, he
|
|
|
332
333
|
cursorYPx += rowMeasure.height;
|
|
333
334
|
}
|
|
334
335
|
};
|
|
336
|
+
const paintFragmentBottomBorders = ({ composer, fragment, block, measure, context }) => {
|
|
337
|
+
if (fragment.continuesOnNext !== true || fragment.bottomClip === void 0) return;
|
|
338
|
+
const primitives = [];
|
|
339
|
+
for (const { left, width, border } of tableFragmentBottomBorders({
|
|
340
|
+
fragment,
|
|
341
|
+
block,
|
|
342
|
+
measure
|
|
343
|
+
})) {
|
|
344
|
+
const stroke = strokeFor(border, context, "table fragment bottom border");
|
|
345
|
+
if (!stroke) continue;
|
|
346
|
+
const yPx = fragment.y + fragment.height - stroke.thicknessPx / 2;
|
|
347
|
+
primitives.push({
|
|
348
|
+
kind: "line",
|
|
349
|
+
x1Px: fragment.x + left,
|
|
350
|
+
y1Px: yPx,
|
|
351
|
+
x2Px: fragment.x + left + width,
|
|
352
|
+
y2Px: yPx,
|
|
353
|
+
stroke
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
composer.push(primitives);
|
|
357
|
+
};
|
|
335
358
|
/** A whole, unpaginated table: what a nested table inside a cell or box is. */
|
|
336
359
|
const paintTableBlock = ({ composer, block, measure, xPx, yPx, context, paintTextBox }) => paintTableBody({
|
|
337
360
|
composer,
|
|
@@ -404,6 +427,13 @@ const paintTableFragment = ({ composer, fragment, block, measure, context, paint
|
|
|
404
427
|
children: [...clipped.primitives()],
|
|
405
428
|
regions: [...clipped.regions()]
|
|
406
429
|
}]);
|
|
430
|
+
paintFragmentBottomBorders({
|
|
431
|
+
composer,
|
|
432
|
+
fragment,
|
|
433
|
+
block,
|
|
434
|
+
measure,
|
|
435
|
+
context
|
|
436
|
+
});
|
|
407
437
|
};
|
|
408
438
|
//#endregion
|
|
409
439
|
export { paintTableBlock, paintTableFragment };
|
|
@@ -15,7 +15,7 @@ import { hasComplexScript, isComplexScriptCodePoint } from "../utils/scriptSegme
|
|
|
15
15
|
* advances rightward from its origin whatever the paragraph does.
|
|
16
16
|
*/
|
|
17
17
|
declare const glyphCellOffsetsPx: (run: DisplayGlyphRun) => readonly number[];
|
|
18
|
-
declare const DISPLAY_PRIMITIVE_KINDS: ("
|
|
18
|
+
declare const DISPLAY_PRIMITIVE_KINDS: ("image" | "line" | "rect" | "glyphRun" | "clipGroup" | "rotateGroup" | "opacityGroup")[];
|
|
19
19
|
/**
|
|
20
20
|
* Dash geometry of each stroke pattern, as multiples of the stroke thickness.
|
|
21
21
|
*
|
|
@@ -5,6 +5,8 @@ import { FolioAIEditView, FolioRevisionStamp, FolioWordDiffOptions } from "./ai-
|
|
|
5
5
|
declare const FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION: 1;
|
|
6
6
|
/** Direct paragraph-alignment values accepted by the operation contract. */
|
|
7
7
|
declare const FOLIO_PARAGRAPH_ALIGNMENT_VALUES: readonly ("left" | "center" | "right" | "both" | "distribute" | "mediumKashida" | "highKashida" | "lowKashida" | "thaiDistribute")[];
|
|
8
|
+
/** `w:spacing/@w:lineRule` values accepted by the operation contract. */
|
|
9
|
+
declare const FOLIO_LINE_SPACING_RULE_VALUES: readonly ("auto" | "exact" | "atLeast")[];
|
|
8
10
|
declare const FOLIO_DOCUMENT_OPERATION_TYPES: readonly ["replaceInBlock", "replaceRange", "commentOnRange", "formatRange", "insertAfterBlock", "insertBeforeBlock", "replaceBlock", "deleteBlock", "splitBlock", "mergeBlockWithNext", "setBlockParagraphProperties", "insertTable", "deleteTable", "commentOnBlock", "insertSignatureTable", "insertTableRow", "deleteTableRow", "insertTableColumn", "deleteTableColumn", "mergeTableCells", "splitTableCell"];
|
|
9
11
|
declare const FOLIO_DOCUMENT_OPERATION_MODES: readonly ["direct", "tracked-changes", "suggested"];
|
|
10
12
|
declare const FOLIO_DOCUMENT_OPERATION_STORIES: readonly ["main", "header", "footer", "footnote", "endnote"];
|
|
@@ -95,8 +97,8 @@ declare const FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE: Readonly<{
|
|
|
95
97
|
readonly replaceRange: readonly ["id", "type", "range", "severity", "area", "precondition", "suggestionId", "replace", "comment"];
|
|
96
98
|
readonly commentOnRange: readonly ["id", "type", "range", "severity", "area", "precondition", "comment"];
|
|
97
99
|
readonly formatRange: readonly ["id", "type", "range", "severity", "area", "precondition", "suggestionId", "formatting"];
|
|
98
|
-
readonly insertAfterBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "text", "inheritFormatting", "alignment", "listLevel", "moveId", "pageBreakBefore", "styleId", "comment"];
|
|
99
|
-
readonly insertBeforeBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "text", "inheritFormatting", "alignment", "listLevel", "moveId", "pageBreakBefore", "styleId", "comment"];
|
|
100
|
+
readonly insertAfterBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "text", "inheritFormatting", "alignment", "spacing", "listLevel", "moveId", "pageBreakBefore", "styleId", "comment"];
|
|
101
|
+
readonly insertBeforeBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "text", "inheritFormatting", "alignment", "spacing", "listLevel", "moveId", "pageBreakBefore", "styleId", "comment"];
|
|
100
102
|
readonly replaceBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "text", "preserveFormatting", "styleId", "comment"];
|
|
101
103
|
readonly deleteBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "moveId", "comment"];
|
|
102
104
|
readonly splitBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "offset", "separator"];
|
|
@@ -119,7 +121,7 @@ declare const parseFolioDocumentOperationBatch: (value: unknown) => FolioDocumen
|
|
|
119
121
|
* review queue instead of applying it; the core apply path never produces it.
|
|
120
122
|
*/
|
|
121
123
|
type FolioDocumentOperationStatus = "committed" | "previewed" | "rejected" | "queued";
|
|
122
|
-
type FolioDocumentOperationRecovery = "refreshDocument" | "narrowMatch" | "changeMode" | "changeTarget" | "removeOperation" | "inspectBatch" | "retryLater";
|
|
124
|
+
type FolioDocumentOperationRecovery = "refreshDocument" | "narrowMatch" | "changeMode" | "changeTarget" | "removeOperation" | "inspectBatch" | "resolveTrackedChange" | "retryLater";
|
|
123
125
|
type FolioDocumentOperationIssue = {
|
|
124
126
|
operationId: string;
|
|
125
127
|
operationIndex: number;
|
|
@@ -280,4 +282,4 @@ type ApplyFolioDocumentOperationsOptions = {
|
|
|
280
282
|
};
|
|
281
283
|
declare const applyFolioDocumentOperations: ({ view, snapshot, batch, story, author, createCommentId, createUndoHandle, revisionStamp, wordDiff, tableTemplates }: ApplyFolioDocumentOperationsOptions) => FolioDocumentOperationResult;
|
|
282
284
|
//#endregion
|
|
283
|
-
export { ApplyFolioDocumentOperationsOptions, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_BATCH_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, FolioDocumentOperation, FolioDocumentOperationAffectedTarget, FolioDocumentOperationBatch, FolioDocumentOperationBatchPrecondition, FolioDocumentOperationCapabilities, FolioDocumentOperationIssue, FolioDocumentOperationMode, FolioDocumentOperationPrecondition, FolioDocumentOperationQueuedOperation, FolioDocumentOperationReceipt, FolioDocumentOperationRecovery, FolioDocumentOperationResult, FolioDocumentOperationResultBase, FolioDocumentOperationStatus, FolioDocumentOperationStory, FolioDocumentOperationType, FolioDocumentOperationUndoFailureReason, FolioDocumentOperationUndoHandle, FolioDocumentOperationUndoResult, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch };
|
|
285
|
+
export { ApplyFolioDocumentOperationsOptions, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_BATCH_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_LINE_SPACING_RULE_VALUES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, FolioDocumentOperation, FolioDocumentOperationAffectedTarget, FolioDocumentOperationBatch, FolioDocumentOperationBatchPrecondition, FolioDocumentOperationCapabilities, FolioDocumentOperationIssue, FolioDocumentOperationMode, FolioDocumentOperationPrecondition, FolioDocumentOperationQueuedOperation, FolioDocumentOperationReceipt, FolioDocumentOperationRecovery, FolioDocumentOperationResult, FolioDocumentOperationResultBase, FolioDocumentOperationStatus, FolioDocumentOperationStory, FolioDocumentOperationType, FolioDocumentOperationUndoFailureReason, FolioDocumentOperationUndoHandle, FolioDocumentOperationUndoResult, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch };
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { applyFolioAIEditOperations, previewFolioAIEditOperations } from "./ai-edits/apply.js";
|
|
2
|
-
import { PARAGRAPH_ALIGNMENT_VALUES } from "./types/documentEnumValues.js";
|
|
2
|
+
import { LINE_SPACING_RULE_VALUES, PARAGRAPH_ALIGNMENT_VALUES } from "./types/documentEnumValues.js";
|
|
3
3
|
import { TaggedError } from "better-result";
|
|
4
4
|
//#region src/document-operations.ts
|
|
5
5
|
const FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION = 1;
|
|
6
6
|
/** Direct paragraph-alignment values accepted by the operation contract. */
|
|
7
7
|
const FOLIO_PARAGRAPH_ALIGNMENT_VALUES = Object.freeze([...PARAGRAPH_ALIGNMENT_VALUES]);
|
|
8
|
+
/** `w:spacing/@w:lineRule` values accepted by the operation contract. */
|
|
9
|
+
const FOLIO_LINE_SPACING_RULE_VALUES = Object.freeze([...LINE_SPACING_RULE_VALUES]);
|
|
8
10
|
const FOLIO_DOCUMENT_OPERATION_TYPES = Object.freeze([
|
|
9
11
|
"replaceInBlock",
|
|
10
12
|
"replaceRange",
|
|
@@ -146,6 +148,12 @@ const readOptionalBoolean = (value, key, path) => {
|
|
|
146
148
|
if (typeof candidate === "boolean") return candidate;
|
|
147
149
|
return invalidBatch(`${path}.${key}`, "expected a boolean when provided");
|
|
148
150
|
};
|
|
151
|
+
const readClearableBoolean = (value, key, path) => {
|
|
152
|
+
const candidate = value[key];
|
|
153
|
+
if (candidate === void 0 || candidate === null) return candidate;
|
|
154
|
+
if (typeof candidate === "boolean") return candidate;
|
|
155
|
+
return invalidBatch(`${path}.${key}`, "expected a boolean or null when provided");
|
|
156
|
+
};
|
|
149
157
|
const readClearableNonEmptyString = (value, key, path) => {
|
|
150
158
|
const candidate = value[key];
|
|
151
159
|
if (candidate === void 0 || candidate === null) return candidate;
|
|
@@ -175,8 +183,8 @@ const readOptionalStringArray = (value, key, path) => {
|
|
|
175
183
|
};
|
|
176
184
|
const readNonNegativeInteger = (value, key, path) => {
|
|
177
185
|
const candidate = value[key];
|
|
178
|
-
if (typeof candidate === "number" && Number.
|
|
179
|
-
return invalidBatch(`${path}.${key}`, "expected a non-negative integer");
|
|
186
|
+
if (typeof candidate === "number" && Number.isSafeInteger(candidate) && candidate >= 0) return candidate;
|
|
187
|
+
return invalidBatch(`${path}.${key}`, "expected a non-negative safe integer");
|
|
180
188
|
};
|
|
181
189
|
/**
|
|
182
190
|
* A non-negative integer that may also be cleared. `undefined` is "say
|
|
@@ -194,6 +202,46 @@ const readClearableParagraphAlignment = ({ value, key, path }) => {
|
|
|
194
202
|
for (const alignment of FOLIO_PARAGRAPH_ALIGNMENT_VALUES) if (candidate === alignment) return alignment;
|
|
195
203
|
return invalidBatch(`${path}.${key}`, `expected one of ${FOLIO_PARAGRAPH_ALIGNMENT_VALUES.join(", ")} or null when provided`);
|
|
196
204
|
};
|
|
205
|
+
const PARAGRAPH_SPACING_KEYS = [
|
|
206
|
+
"spaceBefore",
|
|
207
|
+
"spaceAfter",
|
|
208
|
+
"lineSpacing",
|
|
209
|
+
"lineSpacingRule",
|
|
210
|
+
"beforeAutospacing",
|
|
211
|
+
"afterAutospacing"
|
|
212
|
+
];
|
|
213
|
+
const isLineSpacingRule = (value) => FOLIO_LINE_SPACING_RULE_VALUES.some((rule) => value === rule);
|
|
214
|
+
/**
|
|
215
|
+
* Read one complete direct `w:spacing` cluster. Individual fields are
|
|
216
|
+
* optional so explicit zero and false survive; null removes the child.
|
|
217
|
+
*/
|
|
218
|
+
const readClearableParagraphSpacing = ({ value, key, path }) => {
|
|
219
|
+
const candidate = value[key];
|
|
220
|
+
if (candidate === void 0 || candidate === null) return candidate;
|
|
221
|
+
const spacingPath = `${path}.${key}`;
|
|
222
|
+
if (!isPlainObject(candidate)) return invalidBatch(spacingPath, "expected an object or null when provided");
|
|
223
|
+
assertAllowedKeys(candidate, spacingPath, PARAGRAPH_SPACING_KEYS);
|
|
224
|
+
if (Object.keys(candidate).length === 0) return invalidBatch(spacingPath, "expected at least one spacing property");
|
|
225
|
+
const spacing = {};
|
|
226
|
+
for (const unsignedKey of ["spaceBefore", "spaceAfter"]) if (candidate[unsignedKey] !== void 0) spacing[unsignedKey] = readNonNegativeInteger(candidate, unsignedKey, spacingPath);
|
|
227
|
+
const lineSpacing = candidate["lineSpacing"];
|
|
228
|
+
if (lineSpacing !== void 0) {
|
|
229
|
+
if (typeof lineSpacing !== "number" || !Number.isSafeInteger(lineSpacing)) return invalidBatch(`${spacingPath}.lineSpacing`, "expected a safe signed integer when provided");
|
|
230
|
+
spacing.lineSpacing = lineSpacing;
|
|
231
|
+
}
|
|
232
|
+
const lineSpacingRule = candidate["lineSpacingRule"];
|
|
233
|
+
if (lineSpacingRule !== void 0) {
|
|
234
|
+
if (!isLineSpacingRule(lineSpacingRule)) return invalidBatch(`${spacingPath}.lineSpacingRule`, `expected one of ${FOLIO_LINE_SPACING_RULE_VALUES.join(", ")} when provided`);
|
|
235
|
+
spacing.lineSpacingRule = lineSpacingRule;
|
|
236
|
+
}
|
|
237
|
+
for (const booleanKey of ["beforeAutospacing", "afterAutospacing"]) {
|
|
238
|
+
const booleanValue = candidate[booleanKey];
|
|
239
|
+
if (booleanValue === void 0) continue;
|
|
240
|
+
if (typeof booleanValue !== "boolean") return invalidBatch(`${spacingPath}.${booleanKey}`, "expected a boolean when provided");
|
|
241
|
+
spacing[booleanKey] = booleanValue;
|
|
242
|
+
}
|
|
243
|
+
return spacing;
|
|
244
|
+
};
|
|
197
245
|
/**
|
|
198
246
|
* A rectangular grid of cell texts. Rectangular because a table whose rows
|
|
199
247
|
* hold different cell counts is not a table any consumer can lay out, and the
|
|
@@ -221,7 +269,8 @@ const readParagraphProperties = (value, path) => {
|
|
|
221
269
|
assertAllowedKeys(candidate, propertiesPath, [
|
|
222
270
|
"styleId",
|
|
223
271
|
"listLevel",
|
|
224
|
-
"alignment"
|
|
272
|
+
"alignment",
|
|
273
|
+
"spacing"
|
|
225
274
|
]);
|
|
226
275
|
const styleId = candidate["styleId"] === null ? null : readOptionalString(candidate, "styleId", propertiesPath);
|
|
227
276
|
const listLevel = readClearableNonNegativeInteger(candidate, "listLevel", propertiesPath);
|
|
@@ -230,11 +279,17 @@ const readParagraphProperties = (value, path) => {
|
|
|
230
279
|
key: "alignment",
|
|
231
280
|
path: propertiesPath
|
|
232
281
|
});
|
|
233
|
-
|
|
282
|
+
const spacing = readClearableParagraphSpacing({
|
|
283
|
+
value: candidate,
|
|
284
|
+
key: "spacing",
|
|
285
|
+
path: propertiesPath
|
|
286
|
+
});
|
|
287
|
+
if (styleId === void 0 && listLevel === void 0 && alignment === void 0 && spacing === void 0) return invalidBatch(propertiesPath, "expected at least one property to set");
|
|
234
288
|
return {
|
|
235
289
|
...styleId !== void 0 && { styleId },
|
|
236
290
|
...listLevel !== void 0 && { listLevel },
|
|
237
|
-
...alignment !== void 0 && { alignment }
|
|
291
|
+
...alignment !== void 0 && { alignment },
|
|
292
|
+
...spacing !== void 0 && { spacing }
|
|
238
293
|
};
|
|
239
294
|
};
|
|
240
295
|
const readTextRange = (value, path) => {
|
|
@@ -280,10 +335,10 @@ const readInlineFormatting = (value, path) => {
|
|
|
280
335
|
"fontSizePt",
|
|
281
336
|
"color"
|
|
282
337
|
]);
|
|
283
|
-
const bold =
|
|
284
|
-
const italic =
|
|
285
|
-
const underline =
|
|
286
|
-
const strike =
|
|
338
|
+
const bold = readClearableBoolean(candidate, "bold", formattingPath);
|
|
339
|
+
const italic = readClearableBoolean(candidate, "italic", formattingPath);
|
|
340
|
+
const underline = readClearableBoolean(candidate, "underline", formattingPath);
|
|
341
|
+
const strike = readClearableBoolean(candidate, "strike", formattingPath);
|
|
287
342
|
const fontFamily = readClearableNonEmptyString(candidate, "fontFamily", formattingPath);
|
|
288
343
|
const fontSizePt = readClearableFontSize(candidate, "fontSizePt", formattingPath);
|
|
289
344
|
const color = readClearableRgbColor(candidate, "color", formattingPath);
|
|
@@ -374,6 +429,7 @@ const FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE = Object.freeze({
|
|
|
374
429
|
"text",
|
|
375
430
|
"inheritFormatting",
|
|
376
431
|
"alignment",
|
|
432
|
+
"spacing",
|
|
377
433
|
"listLevel",
|
|
378
434
|
"moveId",
|
|
379
435
|
"pageBreakBefore",
|
|
@@ -385,6 +441,7 @@ const FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE = Object.freeze({
|
|
|
385
441
|
"text",
|
|
386
442
|
"inheritFormatting",
|
|
387
443
|
"alignment",
|
|
444
|
+
"spacing",
|
|
388
445
|
"listLevel",
|
|
389
446
|
"moveId",
|
|
390
447
|
"pageBreakBefore",
|
|
@@ -571,6 +628,11 @@ const parseDocumentOperation = (value, index) => {
|
|
|
571
628
|
key: "alignment",
|
|
572
629
|
path
|
|
573
630
|
});
|
|
631
|
+
const spacing = readClearableParagraphSpacing({
|
|
632
|
+
value,
|
|
633
|
+
key: "spacing",
|
|
634
|
+
path
|
|
635
|
+
});
|
|
574
636
|
return {
|
|
575
637
|
...operationMeta,
|
|
576
638
|
id,
|
|
@@ -579,6 +641,7 @@ const parseDocumentOperation = (value, index) => {
|
|
|
579
641
|
text: readString(value, "text", path),
|
|
580
642
|
...inheritFormatting !== void 0 && { inheritFormatting },
|
|
581
643
|
...alignment !== void 0 && { alignment },
|
|
644
|
+
...spacing !== void 0 && { spacing },
|
|
582
645
|
...listLevel !== void 0 && { listLevel },
|
|
583
646
|
...moveId !== void 0 && { moveId },
|
|
584
647
|
...pageBreakBefore !== void 0 && { pageBreakBefore },
|
|
@@ -762,6 +825,8 @@ const recoveryByReason = {
|
|
|
762
825
|
preconditionFailed: "refreshDocument",
|
|
763
826
|
staleRange: "refreshDocument",
|
|
764
827
|
emptyOperation: "removeOperation",
|
|
828
|
+
pendingParagraphPropertyChange: "resolveTrackedChange",
|
|
829
|
+
pendingRunPropertyChange: "resolveTrackedChange",
|
|
765
830
|
noopOperation: "removeOperation",
|
|
766
831
|
documentVersionMismatch: "refreshDocument",
|
|
767
832
|
documentNotEditable: "retryLater"
|
|
@@ -778,7 +843,7 @@ const getFolioDocumentOperationIssues = (operations, skipped) => {
|
|
|
778
843
|
operationIndex,
|
|
779
844
|
path: `$.operations[${operationIndex}]`,
|
|
780
845
|
code: reason,
|
|
781
|
-
retryable: reason !== "emptyOperation" && reason !== "noopOperation",
|
|
846
|
+
retryable: reason !== "emptyOperation" && reason !== "noopOperation" && reason !== "pendingParagraphPropertyChange" && reason !== "pendingRunPropertyChange",
|
|
782
847
|
recovery: recoveryByReason[reason]
|
|
783
848
|
};
|
|
784
849
|
});
|
|
@@ -1008,4 +1073,4 @@ const applyFolioDocumentOperations = ({ view, snapshot, batch, story = "main", a
|
|
|
1008
1073
|
};
|
|
1009
1074
|
};
|
|
1010
1075
|
//#endregion
|
|
1011
|
-
export { FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_BATCH_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch };
|
|
1076
|
+
export { FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_BATCH_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_LINE_SPACING_RULE_VALUES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch };
|
|
@@ -9,7 +9,7 @@ import { parseTable } from "./tableParser.js";
|
|
|
9
9
|
import { captureVerbatimXml } from "./verbatimCapture.js";
|
|
10
10
|
import { findChild, getChildElements, getLocalName, mergeXmlnsDeclarations } from "./xmlParser.js";
|
|
11
11
|
//#region src/docx/blockContentParser.ts
|
|
12
|
-
const computeListMarker = (paragraph, { numbering, listCounters, abstractCounters, restartedNumIds, previousList
|
|
12
|
+
const computeListMarker = (paragraph, { numbering, listCounters, abstractCounters, restartedNumIds, previousList }) => {
|
|
13
13
|
const listRendering = paragraph.listRendering;
|
|
14
14
|
if (!listRendering || !numbering) {
|
|
15
15
|
previousList.abstractNumId = null;
|
|
@@ -26,26 +26,17 @@ const computeListMarker = (paragraph, { numbering, listCounters, abstractCounter
|
|
|
26
26
|
}
|
|
27
27
|
const firstEncounter = !listCounters.has(numId);
|
|
28
28
|
if (firstEncounter) listCounters.set(numId, Array.from({ length: 9 }).fill(NaN));
|
|
29
|
-
|
|
29
|
+
let counters = listCounters.get(numId);
|
|
30
30
|
if (!counters) return;
|
|
31
31
|
const abstractNumId = numbering.getAbstractNumId(numId);
|
|
32
|
-
if (firstEncounter && abstractNumId !== null) {
|
|
33
|
-
let siblingNumIds = siblingNumIdsByAbstractNumId.get(abstractNumId);
|
|
34
|
-
if (!siblingNumIds) {
|
|
35
|
-
siblingNumIds = /* @__PURE__ */ new Set();
|
|
36
|
-
siblingNumIdsByAbstractNumId.set(abstractNumId, siblingNumIds);
|
|
37
|
-
}
|
|
38
|
-
siblingNumIds.add(numId);
|
|
39
|
-
}
|
|
40
32
|
const styleNumbering = paragraph.formatting?.numPrFromStyle;
|
|
41
|
-
let resumedAbstractCounters;
|
|
42
33
|
const resumesRestartedInstance = firstEncounter && listRendering.startOverride === void 0 && abstractNumId !== null && previousList.abstractNumId === abstractNumId && previousList.numId !== null && previousList.numId !== numId && restartedNumIds.has(previousList.numId);
|
|
43
34
|
const resumesStyleInstance = firstEncounter && !styleNumbering && listRendering.startOverride === void 0 && abstractNumId !== null && previousList.abstractNumId === abstractNumId && previousList.fromStyle === true;
|
|
44
35
|
if (abstractNumId !== null && (styleNumbering || resumesRestartedInstance || resumesStyleInstance)) {
|
|
45
36
|
const latestAbstractCounters = abstractCounters.get(abstractNumId);
|
|
46
37
|
if (latestAbstractCounters) {
|
|
47
|
-
|
|
48
|
-
|
|
38
|
+
counters = latestAbstractCounters;
|
|
39
|
+
listCounters.set(numId, counters);
|
|
49
40
|
}
|
|
50
41
|
}
|
|
51
42
|
if (listRendering.startOverride !== void 0 || resumesRestartedInstance || previousList.numId === numId && restartedNumIds.has(numId)) restartedNumIds.add(numId);
|
|
@@ -64,17 +55,7 @@ const computeListMarker = (paragraph, { numbering, listCounters, abstractCounter
|
|
|
64
55
|
const childCounter = counters[level + 1];
|
|
65
56
|
counters[level + 1] = (childCounter === void 0 || Number.isNaN(childCounter) ? 0 : childCounter) + childAdvances;
|
|
66
57
|
}
|
|
67
|
-
if (abstractNumId !== null)
|
|
68
|
-
if (resumedAbstractCounters) {
|
|
69
|
-
const siblingNumIds = siblingNumIdsByAbstractNumId.get(abstractNumId);
|
|
70
|
-
for (const otherNumId of siblingNumIds ?? []) {
|
|
71
|
-
const otherCounters = listCounters.get(otherNumId);
|
|
72
|
-
if (otherNumId === numId || !otherCounters || !otherCounters.every((value, index) => Object.is(value, resumedAbstractCounters[index]))) continue;
|
|
73
|
-
for (let i = 0; i < otherCounters.length; i += 1) otherCounters[i] = counters[i] ?? NaN;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
abstractCounters.set(abstractNumId, [...counters]);
|
|
77
|
-
}
|
|
58
|
+
if (abstractNumId !== null) abstractCounters.set(abstractNumId, counters);
|
|
78
59
|
previousList.abstractNumId = abstractNumId;
|
|
79
60
|
previousList.fromStyle = Boolean(styleNumbering);
|
|
80
61
|
previousList.numId = numId;
|
|
@@ -108,7 +89,6 @@ const parseBlockContent = (parent, styles, theme, numbering, rels, media, option
|
|
|
108
89
|
fromStyle: false,
|
|
109
90
|
numId: null
|
|
110
91
|
},
|
|
111
|
-
siblingNumIdsByAbstractNumId: /* @__PURE__ */ new Map(),
|
|
112
92
|
options: {
|
|
113
93
|
...options,
|
|
114
94
|
rootXmlns: mergeXmlnsDeclarations(options?.rootXmlns ?? {}, parent)
|
|
@@ -129,8 +109,7 @@ const parseBlockContentWithState = (parent, styles, theme, numbering, rels, medi
|
|
|
129
109
|
listCounters: state.listCounters,
|
|
130
110
|
abstractCounters: state.abstractCounters,
|
|
131
111
|
restartedNumIds: state.restartedNumIds,
|
|
132
|
-
previousList: state.previousList
|
|
133
|
-
siblingNumIdsByAbstractNumId: state.siblingNumIdsByAbstractNumId
|
|
112
|
+
previousList: state.previousList
|
|
134
113
|
});
|
|
135
114
|
content.push(paragraph);
|
|
136
115
|
continue;
|
|
@@ -392,10 +392,15 @@ const ensureParaIdsInternal = async (docx, options) => {
|
|
|
392
392
|
};
|
|
393
393
|
const zip = await JSZip.loadAsync(docx);
|
|
394
394
|
if (hasDigitalSignatureParts(zip) && options.allowSignedPackageMutation !== true) throw createEnsureParaIdsError("Refusing to normalize a digitally signed package because rewriting OOXML invalidates its signatures. Warn the user and pass allowSignedPackageMutation only if invalidation is acceptable.");
|
|
395
|
-
for (const [partPath, content] of updates)
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
395
|
+
for (const [partPath, content] of updates) {
|
|
396
|
+
const sourceEntry = zip.file(partPath);
|
|
397
|
+
if (sourceEntry === null) throw createEnsureParaIdsError(`Package part disappeared during normalization: ${partPath}`);
|
|
398
|
+
zip.file(partPath, content, {
|
|
399
|
+
compression: "DEFLATE",
|
|
400
|
+
compressionOptions: { level: 6 },
|
|
401
|
+
date: sourceEntry.date
|
|
402
|
+
});
|
|
403
|
+
}
|
|
399
404
|
return {
|
|
400
405
|
docx: await zip.generateAsync({
|
|
401
406
|
type: "uint8array",
|
|
@@ -80,5 +80,7 @@ declare function getBulletCharacter(level: document_d_exports.ListLevel): string
|
|
|
80
80
|
* Check if a list level is a bullet (not numbered)
|
|
81
81
|
*/
|
|
82
82
|
declare function isBulletLevel(level: document_d_exports.ListLevel): boolean;
|
|
83
|
+
/** Whether a numbering level reserves horizontal space for a visible marker. */
|
|
84
|
+
declare const numberingLevelHasMarkerSlot: (level: Pick<document_d_exports.ListLevel, "numFmt">) => boolean;
|
|
83
85
|
//#endregion
|
|
84
|
-
export { NumberingMap, computeListRendering, createNumberingMap, formatOoxmlCounter as formatNumber, getBulletCharacter, getCachedNumberingMap, isBulletLevel, markerFormattingFromLevel, numPrEqual, padDecimal, parseNumbering, renderListMarker };
|
|
86
|
+
export { NumberingMap, computeListRendering, createNumberingMap, formatOoxmlCounter as formatNumber, getBulletCharacter, getCachedNumberingMap, isBulletLevel, markerFormattingFromLevel, numPrEqual, numberingLevelHasMarkerSlot, padDecimal, parseNumbering, renderListMarker };
|
|
@@ -542,6 +542,7 @@ function computeListRendering(numPr, numbering) {
|
|
|
542
542
|
level: ilvl,
|
|
543
543
|
numId,
|
|
544
544
|
marker: level.lvlText,
|
|
545
|
+
markerTemplate: level.lvlText,
|
|
545
546
|
isBullet: level.numFmt === "bullet",
|
|
546
547
|
numFmt: level.isLgl ? "decimal" : level.numFmt,
|
|
547
548
|
levelNumFmts,
|
|
@@ -609,5 +610,7 @@ function getBulletCharacter(level) {
|
|
|
609
610
|
function isBulletLevel(level) {
|
|
610
611
|
return level.numFmt === "bullet" || level.numFmt === "none";
|
|
611
612
|
}
|
|
613
|
+
/** Whether a numbering level reserves horizontal space for a visible marker. */
|
|
614
|
+
const numberingLevelHasMarkerSlot = (level) => level.numFmt !== "none";
|
|
612
615
|
//#endregion
|
|
613
|
-
export { computeListRendering, createNumberingMap, formatOoxmlCounter as formatNumber, getBulletCharacter, getCachedNumberingMap, isBulletLevel, markerFormattingFromLevel, numPrEqual, padDecimal, parseNumbering, renderListMarker };
|
|
616
|
+
export { computeListRendering, createNumberingMap, formatOoxmlCounter as formatNumber, getBulletCharacter, getCachedNumberingMap, isBulletLevel, markerFormattingFromLevel, numPrEqual, numberingLevelHasMarkerSlot, padDecimal, parseNumbering, renderListMarker };
|
|
@@ -4,7 +4,7 @@ import { isValidHexId } from "../utils/hexId.js";
|
|
|
4
4
|
import { parseBookmarkEnd as parseBookmarkEnd$1, parseBookmarkStart as parseBookmarkStart$1 } from "./bookmarkParser.js";
|
|
5
5
|
import { parseFieldType } from "./fieldParser.js";
|
|
6
6
|
import { parseHyperlink as parseHyperlink$1, parseHyperlinkChild } from "./hyperlinkParser.js";
|
|
7
|
-
import { markerFormattingFromLevel } from "./numberingParser.js";
|
|
7
|
+
import { markerFormattingFromLevel, numberingLevelHasMarkerSlot } from "./numberingParser.js";
|
|
8
8
|
import { paraIdInRange } from "./paraIdRangeNormalization.js";
|
|
9
9
|
import { assignParagraphPropertySource } from "./paragraphPropertySource.js";
|
|
10
10
|
import { BorderStyleSchema, FrameWrapSchema, FrameXAlignSchema, FrameYAlignSchema, LineSpacingRuleSchema, ParagraphAlignmentSchema, ShadingPatternSchema, TabLeaderSchema, TabStopAlignmentSchema, ThemeColorSlotSchema, narrowEnum } from "./parserEnums.js";
|
|
@@ -495,10 +495,10 @@ function normalizeDeletionContentElement(node) {
|
|
|
495
495
|
let mappedName = node.name;
|
|
496
496
|
if (localName === "delText") mappedName = replaceLocalName(node.name, "t");
|
|
497
497
|
else if (localName === "delInstrText") mappedName = replaceLocalName(node.name, "instrText");
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
498
|
+
return cloneElement(node, {
|
|
499
|
+
...mappedName !== void 0 ? { name: mappedName } : {},
|
|
500
|
+
...node.elements ? { elements: node.elements.map(normalizeDeletionContentElement) } : {}
|
|
501
|
+
});
|
|
502
502
|
}
|
|
503
503
|
function parseParagraphPropertyChanges(pPr, theme, styles, currentFormatting) {
|
|
504
504
|
if (!pPr) return;
|
|
@@ -1122,6 +1122,7 @@ function parseParagraph(node, styles, theme, numbering, rels = null, media = nul
|
|
|
1122
1122
|
level: ilvl,
|
|
1123
1123
|
numId,
|
|
1124
1124
|
marker: level.lvlText,
|
|
1125
|
+
markerTemplate: level.lvlText,
|
|
1125
1126
|
isBullet: level.numFmt === "bullet",
|
|
1126
1127
|
levelNumFmts,
|
|
1127
1128
|
levelStarts
|
|
@@ -1186,7 +1187,7 @@ function parseParagraph(node, styles, theme, numbering, rels = null, media = nul
|
|
|
1186
1187
|
const directHanging = directInd ? parseNumericAttribute(directInd, "w", "hanging") : void 0;
|
|
1187
1188
|
const hasDirectFirstLineOrHanging = directFirstLine !== void 0 && directFirstLine !== 0 || directHanging !== void 0 && directHanging !== 0;
|
|
1188
1189
|
if (!hasDirectLeft && !chainInd.left && level.pPr.indentLeft !== void 0) paragraph.formatting.indentLeft = level.pPr.indentLeft;
|
|
1189
|
-
if (!hasDirectFirstLineOrHanging && !chainInd.firstLine) {
|
|
1190
|
+
if (!hasDirectFirstLineOrHanging && !chainInd.firstLine && numberingLevelHasMarkerSlot(level)) {
|
|
1190
1191
|
if (level.pPr.indentFirstLine !== void 0) paragraph.formatting.indentFirstLine = level.pPr.indentFirstLine;
|
|
1191
1192
|
if (level.pPr.hangingIndent !== void 0) paragraph.formatting.hangingIndent = level.pPr.hangingIndent;
|
|
1192
1193
|
}
|
|
@@ -1,41 +1,37 @@
|
|
|
1
1
|
//#region src/docx/paragraphTraversal.ts
|
|
2
2
|
/** Visit every run directly owned by a paragraph's inline-content tree. */
|
|
3
3
|
const visitParagraphRuns = (paragraph, visit) => {
|
|
4
|
-
const visitRun = (run) => {
|
|
5
|
-
visit(run);
|
|
6
|
-
};
|
|
7
|
-
const visitHyperlink = (hyperlink) => {
|
|
8
|
-
for (const child of hyperlink.children) if (child.type === "run") visitRun(child);
|
|
9
|
-
};
|
|
10
|
-
const visitInlineContent = (content) => {
|
|
11
|
-
for (const child of content) {
|
|
12
|
-
if (child.type === "run") {
|
|
13
|
-
visitRun(child);
|
|
14
|
-
continue;
|
|
15
|
-
}
|
|
16
|
-
if (child.type === "hyperlink") visitHyperlink(child);
|
|
17
|
-
}
|
|
18
|
-
};
|
|
19
4
|
const visitParagraphContent = (content) => {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
5
|
+
switch (content.type) {
|
|
6
|
+
case "run":
|
|
7
|
+
visit(content);
|
|
8
|
+
return;
|
|
9
|
+
case "hyperlink":
|
|
10
|
+
for (const child of content.children) visitParagraphContent(child);
|
|
11
|
+
return;
|
|
12
|
+
case "simpleField":
|
|
13
|
+
case "insertion":
|
|
14
|
+
case "deletion":
|
|
15
|
+
case "moveFrom":
|
|
16
|
+
case "moveTo":
|
|
17
|
+
case "inlineSdt":
|
|
18
|
+
for (const child of content.content) visitParagraphContent(child);
|
|
19
|
+
return;
|
|
20
|
+
case "complexField":
|
|
21
|
+
for (const run of content.fieldCode) visit(run);
|
|
22
|
+
for (const run of content.fieldResult) visit(run);
|
|
23
|
+
return;
|
|
24
|
+
case "bookmarkStart":
|
|
25
|
+
case "bookmarkEnd":
|
|
26
|
+
case "commentRangeStart":
|
|
27
|
+
case "commentRangeEnd":
|
|
28
|
+
case "commentReference":
|
|
29
|
+
case "moveFromRangeStart":
|
|
30
|
+
case "moveFromRangeEnd":
|
|
31
|
+
case "moveToRangeStart":
|
|
32
|
+
case "moveToRangeEnd":
|
|
33
|
+
case "mathEquation": return;
|
|
34
|
+
default: return content;
|
|
39
35
|
}
|
|
40
36
|
};
|
|
41
37
|
for (const content of paragraph.content) visitParagraphContent(content);
|
package/dist/docx/rezip.d.ts
CHANGED
|
@@ -28,14 +28,6 @@ type RepackOptions = {
|
|
|
28
28
|
/** Changed note paragraphs that must be serialized even without source paraIds. */
|
|
29
29
|
changedNoteParaIds?: ReadonlySet<string>;
|
|
30
30
|
};
|
|
31
|
-
/**
|
|
32
|
-
* Repack a Document into a valid DOCX file
|
|
33
|
-
*
|
|
34
|
-
* @param doc - Document with modified content
|
|
35
|
-
* @param options - Optional repack options
|
|
36
|
-
* @returns Promise resolving to DOCX as ArrayBuffer
|
|
37
|
-
* @throws {Error} if document has no original buffer for round-trip
|
|
38
|
-
*/
|
|
39
31
|
declare function repackDocx(doc: document_d_exports.Document, options?: RepackOptions): Promise<ArrayBuffer>;
|
|
40
32
|
/**
|
|
41
33
|
* Repack a Document using raw content for more control
|
package/dist/docx/rezip.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { consumeTrackedSectionEndpointRemoval } from "../internal/sectionEndpointResolution.js";
|
|
1
2
|
import { isAllowedExternalWatermarkImageUrl } from "../watermark/index.js";
|
|
2
3
|
import { normalizeAppVersionInExtendedProperties } from "./appVersionNormalization.js";
|
|
3
4
|
import { withoutOrphanCommentRanges } from "./commentRangeIntegrity.js";
|
|
@@ -115,11 +116,34 @@ const extractHeaderFooterReferences = (xml) => {
|
|
|
115
116
|
const hasParsedHeaderFooterPart = (doc, ref) => {
|
|
116
117
|
return (ref.element === "headerReference" ? doc.package.headers : doc.package.footers)?.has(ref.rId) ?? false;
|
|
117
118
|
};
|
|
118
|
-
|
|
119
|
+
const headerFooterReferenceKey = ({ element, type, rId }) => `${element}:${type}:${rId}`;
|
|
120
|
+
const incrementReferenceCount = (counts, key) => {
|
|
121
|
+
counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
122
|
+
};
|
|
123
|
+
const consumeReferenceCount = (counts, key) => {
|
|
124
|
+
const count = counts.get(key) ?? 0;
|
|
125
|
+
if (count === 0) return false;
|
|
126
|
+
counts.set(key, count - 1);
|
|
127
|
+
return true;
|
|
128
|
+
};
|
|
129
|
+
function assertDocumentPackageFidelity(originalDocumentXml, serializedDocumentXml, doc, sectionEndpointRemoval) {
|
|
119
130
|
const originalSectionCount = countDocumentSections(originalDocumentXml);
|
|
120
|
-
|
|
121
|
-
const
|
|
122
|
-
|
|
131
|
+
const serializedSectionCount = countDocumentSections(serializedDocumentXml);
|
|
132
|
+
const trackedRemovedSectionCount = sectionEndpointRemoval ? sectionEndpointRemoval.sourceParagraphEndpointCount - sectionEndpointRemoval.expectedParagraphEndpointCount : 0;
|
|
133
|
+
const exactTrackedSectionRemoval = trackedRemovedSectionCount > 0 && originalSectionCount - trackedRemovedSectionCount === serializedSectionCount && serializedSectionCount < originalSectionCount;
|
|
134
|
+
if (serializedSectionCount < originalSectionCount && !exactTrackedSectionRemoval) throw new DocxPackageFidelityError("Full DOCX repack would drop section properties. Use selective patching instead.");
|
|
135
|
+
const serializedReferenceCounts = /* @__PURE__ */ new Map();
|
|
136
|
+
for (const reference of extractHeaderFooterReferences(serializedDocumentXml)) incrementReferenceCount(serializedReferenceCounts, headerFooterReferenceKey(reference));
|
|
137
|
+
const removedReferenceCounts = /* @__PURE__ */ new Map();
|
|
138
|
+
if (exactTrackedSectionRemoval && sectionEndpointRemoval) for (const { part, type, relationshipId } of sectionEndpointRemoval.removedReferences) incrementReferenceCount(removedReferenceCounts, `${part}Reference:${type}:${relationshipId}`);
|
|
139
|
+
const missingRefs = [];
|
|
140
|
+
for (const reference of extractHeaderFooterReferences(originalDocumentXml)) {
|
|
141
|
+
if (!hasParsedHeaderFooterPart(doc, reference)) continue;
|
|
142
|
+
const key = headerFooterReferenceKey(reference);
|
|
143
|
+
if (consumeReferenceCount(serializedReferenceCounts, key) || consumeReferenceCount(removedReferenceCounts, key)) continue;
|
|
144
|
+
missingRefs.push(reference);
|
|
145
|
+
}
|
|
146
|
+
if (missingRefs.length > 0) throw new DocxPackageFidelityError("Full DOCX repack would drop header/footer references. Use selective patching instead.");
|
|
123
147
|
}
|
|
124
148
|
async function serializeCommentsToZip(doc, zip, compressionLevel) {
|
|
125
149
|
const comments = doc.package.document.comments ?? [];
|
|
@@ -488,7 +512,7 @@ const cloneDocxZip = (source) => {
|
|
|
488
512
|
clone.files = { ...source.files };
|
|
489
513
|
return clone;
|
|
490
514
|
};
|
|
491
|
-
const finishRepack = async ({ document, originalZip, outputZip, originalDocumentXml, originalCorePropertiesXml, compressionLevel, updateModifiedDate, modifiedBy, changedNoteParaIds }) => {
|
|
515
|
+
const finishRepack = async ({ document, originalZip, outputZip, originalDocumentXml, originalCorePropertiesXml, compressionLevel, updateModifiedDate, modifiedBy, changedNoteParaIds, sectionEndpointRemoval }) => {
|
|
492
516
|
await materializeNewHeaderFooterParts(document, outputZip, compressionLevel);
|
|
493
517
|
const parts = collectDocxParts(document, outputZip);
|
|
494
518
|
await processNewImages(parts, outputZip, compressionLevel);
|
|
@@ -496,7 +520,7 @@ const finishRepack = async ({ document, originalZip, outputZip, originalDocument
|
|
|
496
520
|
assertValidFolioDocumentModel(document, "Cannot repack invalid DOCX document model");
|
|
497
521
|
applyReplyThreadMarkers(document);
|
|
498
522
|
const documentXml = serializeDocument(document, originalDocumentXml === void 0 ? void 0 : readRootNamespaceBindings(originalDocumentXml));
|
|
499
|
-
if (originalDocumentXml) assertDocumentPackageFidelity(originalDocumentXml, documentXml, document);
|
|
523
|
+
if (originalDocumentXml) assertDocumentPackageFidelity(originalDocumentXml, documentXml, document, sectionEndpointRemoval);
|
|
500
524
|
outputZip.file("word/document.xml", documentXml, {
|
|
501
525
|
compression: "DEFLATE",
|
|
502
526
|
compressionOptions: { level: compressionLevel }
|
|
@@ -526,15 +550,7 @@ const finishRepack = async ({ document, originalZip, outputZip, originalDocument
|
|
|
526
550
|
}
|
|
527
551
|
return generateDocxZip(outputZip, compressionLevel);
|
|
528
552
|
};
|
|
529
|
-
|
|
530
|
-
* Repack a Document into a valid DOCX file
|
|
531
|
-
*
|
|
532
|
-
* @param doc - Document with modified content
|
|
533
|
-
* @param options - Optional repack options
|
|
534
|
-
* @returns Promise resolving to DOCX as ArrayBuffer
|
|
535
|
-
* @throws {Error} if document has no original buffer for round-trip
|
|
536
|
-
*/
|
|
537
|
-
async function repackDocx(doc, options = {}) {
|
|
553
|
+
async function repackDocxWithSectionEndpointRemoval({ document: doc, options, sectionEndpointRemoval }) {
|
|
538
554
|
if (!doc.originalBuffer) panic("Cannot repack document: no original buffer for round-trip. Use createDocx() for new documents.");
|
|
539
555
|
const { compressionLevel = 6, updateModifiedDate = true, modifiedBy, changedNoteParaIds } = options;
|
|
540
556
|
const exportDocument = withoutOrphanCommentRanges(doc);
|
|
@@ -551,7 +567,16 @@ async function repackDocx(doc, options = {}) {
|
|
|
551
567
|
compressionLevel,
|
|
552
568
|
updateModifiedDate,
|
|
553
569
|
...modifiedBy !== void 0 ? { modifiedBy } : {},
|
|
554
|
-
...changedNoteParaIds !== void 0 ? { changedNoteParaIds } : {}
|
|
570
|
+
...changedNoteParaIds !== void 0 ? { changedNoteParaIds } : {},
|
|
571
|
+
...sectionEndpointRemoval !== void 0 ? { sectionEndpointRemoval } : {}
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
function repackDocx(doc, options = {}) {
|
|
575
|
+
const sectionEndpointRemoval = consumeTrackedSectionEndpointRemoval(doc);
|
|
576
|
+
return repackDocxWithSectionEndpointRemoval({
|
|
577
|
+
document: doc,
|
|
578
|
+
options,
|
|
579
|
+
...sectionEndpointRemoval ? { sectionEndpointRemoval } : {}
|
|
555
580
|
});
|
|
556
581
|
}
|
|
557
582
|
/**
|