@stll/folio-core 0.43.0 → 0.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai-edits/__fixtures__/paragraphs.js +2 -2
- package/dist/ai-edits/headless.js +7 -5
- package/dist/ai-edits/index.d.ts +2 -2
- package/dist/ai-edits/index.js +2 -2
- package/dist/ai-edits/snapshot.js +13 -9
- package/dist/compare/content-alignment.js +94 -54
- package/dist/compare/inline-atoms.js +34 -20
- package/dist/compare/style-resources.js +6 -0
- package/dist/content-controls/mutateContentControls.js +4 -2
- package/dist/display-list/dom/renderDisplayListToDom.js +8 -8
- package/dist/document-operations.js +14 -3
- package/dist/docx/appVersionNormalization.d.ts +0 -18
- package/dist/docx/blockContentParser.js +8 -0
- package/dist/docx/blockRangeMarkers.d.ts +36 -0
- package/dist/docx/blockRangeMarkers.js +59 -0
- package/dist/docx/bookmarkParser.d.ts +2 -20
- package/dist/docx/bookmarkParser.js +6 -30
- package/dist/docx/borderParser.d.ts +13 -0
- package/dist/docx/borderParser.js +71 -0
- package/dist/docx/builtInStyles.d.ts +165 -0
- package/dist/docx/builtInStyles.js +239 -0
- package/dist/docx/commentIdNormalization.d.ts +3 -1
- package/dist/docx/commentIdNormalization.js +18 -1
- package/dist/docx/commentParser.d.ts +2 -1
- package/dist/docx/commentParser.js +80 -42
- package/dist/docx/commentReferenceNormalization.d.ts +4 -1
- package/dist/docx/commentReferenceNormalization.js +23 -14
- package/dist/docx/commentThreadKey.d.ts +18 -0
- package/dist/docx/commentThreadKey.js +22 -0
- package/dist/docx/danglingRelationshipReferences.d.ts +15 -0
- package/dist/docx/danglingRelationshipReferences.js +30 -0
- package/dist/docx/defaultParagraphStyle.d.ts +18 -1
- package/dist/docx/defaultParagraphStyle.js +23 -1
- package/dist/docx/diagramPreview.js +87 -27
- package/dist/docx/documentParser.d.ts +2 -1
- package/dist/docx/documentParser.js +2 -2
- package/dist/docx/drawingUtils.d.ts +8 -1
- package/dist/docx/drawingUtils.js +12 -3
- package/dist/docx/fieldParser.js +3 -5
- package/dist/docx/footnoteParser.d.ts +3 -2
- package/dist/docx/footnoteParser.js +19 -4
- package/dist/docx/groupDrawingParser.js +4 -4
- package/dist/docx/headerFooterRefParser.d.ts +4 -3
- package/dist/docx/headerFooterRefParser.js +42 -12
- package/dist/docx/headerFooterReferenceNormalization.d.ts +4 -1
- package/dist/docx/headerFooterReferenceNormalization.js +5 -1
- package/dist/docx/hyperlinkParser.js +13 -17
- package/dist/docx/imageParser.d.ts +10 -2
- package/dist/docx/imageParser.js +80 -30
- package/dist/docx/imageRawXml.d.ts +14 -1
- package/dist/docx/imageRawXml.js +35 -11
- package/dist/docx/markupRangeMarker.d.ts +15 -0
- package/dist/docx/markupRangeMarker.js +44 -0
- package/dist/docx/mathToMathml.js +12 -14
- package/dist/docx/nonVisualDrawingProps.d.ts +34 -0
- package/dist/docx/nonVisualDrawingProps.js +46 -0
- package/dist/docx/noteReferenceStyles.d.ts +29 -0
- package/dist/docx/noteReferenceStyles.js +70 -0
- package/dist/docx/numberingReferenceNormalization.d.ts +4 -1
- package/dist/docx/numberingReferenceNormalization.js +20 -1
- package/dist/docx/paraIdRangeNormalization.d.ts +0 -19
- package/dist/docx/paragraphParser.js +66 -99
- package/dist/docx/paragraphPropertySource.js +1 -0
- package/dist/docx/paragraphTextBoxEnrichment.js +3 -0
- package/dist/docx/paragraphTraversal.d.ts +37 -1
- package/dist/docx/paragraphTraversal.js +84 -1
- package/dist/docx/parseContext.d.ts +37 -0
- package/dist/docx/parseContext.js +67 -0
- package/dist/docx/parseWarningMessage.d.ts +6 -0
- package/dist/docx/parseWarningMessage.js +44 -0
- package/dist/docx/parser.js +83 -29
- package/dist/docx/previewBudget.d.ts +64 -0
- package/dist/docx/previewBudget.js +88 -0
- package/dist/docx/relsParser.d.ts +28 -11
- package/dist/docx/relsParser.js +26 -13
- package/dist/docx/revisionIdNormalization.js +96 -10
- package/dist/docx/rezip.js +80 -40
- package/dist/docx/runConsolidator.js +1 -2
- package/dist/docx/runParser.d.ts +8 -1
- package/dist/docx/runParser.js +30 -48
- package/dist/docx/sdtPropertiesPatch.js +24 -18
- package/dist/docx/sectionParser.d.ts +2 -1
- package/dist/docx/sectionParser.js +21 -65
- package/dist/docx/sectionReferenceHistory.js +2 -2
- package/dist/docx/selectiveSave.js +6 -6
- package/dist/docx/serializer/blockSdtSerializer.js +38 -26
- package/dist/docx/serializer/borderSerializer.d.ts +2 -3
- package/dist/docx/serializer/borderSerializer.js +13 -12
- package/dist/docx/serializer/commentSerializer.d.ts +41 -16
- package/dist/docx/serializer/commentSerializer.js +82 -72
- package/dist/docx/serializer/documentSerializer.d.ts +1 -5
- package/dist/docx/serializer/documentSerializer.js +6 -16
- package/dist/docx/serializer/fontTableSerializer.js +6 -6
- package/dist/docx/serializer/headerFooterSerializer.js +10 -5
- package/dist/docx/serializer/markupRangeAttributes.d.ts +8 -0
- package/dist/docx/serializer/markupRangeAttributes.js +24 -0
- package/dist/docx/serializer/noteSerializer.js +5 -0
- package/dist/docx/serializer/numberingSerializer.js +7 -6
- package/dist/docx/serializer/paragraphSerializer.d.ts +1 -5
- package/dist/docx/serializer/paragraphSerializer.js +47 -52
- package/dist/docx/serializer/partNamespaces.js +2 -2
- package/dist/docx/serializer/runSerializer.js +57 -31
- package/dist/docx/serializer/sectionPropertiesSerializer.js +11 -10
- package/dist/docx/serializer/settingsSerializer.js +4 -3
- package/dist/docx/serializer/stylesSerializer.js +6 -6
- package/dist/docx/serializer/tableSerializer.js +37 -21
- package/dist/docx/serializer/textFormattingSerializer.d.ts +2 -3
- package/dist/docx/serializer/textFormattingSerializer.js +29 -28
- package/dist/docx/serializer/themeSerializer.js +6 -6
- package/dist/docx/serializer/trackedChangeAttributes.js +2 -2
- package/dist/docx/serializer/xmlUtils.d.ts +1 -2
- package/dist/docx/serializer/xmlUtils.js +1 -13
- package/dist/docx/server/boundedArchive.d.ts +12 -0
- package/dist/docx/server/boundedArchive.js +20 -1
- package/dist/docx/server/build.js +8 -1
- package/dist/docx/server/createBilingualDocument.js +10 -18
- package/dist/docx/server/extractDocxText.js +3 -4
- package/dist/docx/server/validateDocxConformance.js +22 -1
- package/dist/docx/shadingParser.d.ts +6 -0
- package/dist/docx/shadingParser.js +32 -0
- package/dist/docx/shapeParser.js +10 -8
- package/dist/docx/styleParser.js +13 -87
- package/dist/docx/styleReferenceResolution.d.ts +36 -0
- package/dist/docx/styleReferenceResolution.js +51 -0
- package/dist/docx/tableLook.d.ts +57 -0
- package/dist/docx/tableLook.js +63 -0
- package/dist/docx/tableParser.d.ts +7 -9
- package/dist/docx/tableParser.js +64 -110
- package/dist/docx/textBoxParser.js +11 -6
- package/dist/docx/trackedMoveRangeNormalization.d.ts +3 -1
- package/dist/docx/trackedMoveRangeNormalization.js +11 -21
- package/dist/docx/transitionalSpelling.d.ts +13 -2
- package/dist/docx/transitionalSpelling.js +23 -1
- package/dist/docx/unzip.d.ts +23 -0
- package/dist/docx/unzip.js +32 -22
- package/dist/docx/verbatimCapture.js +5 -12
- package/dist/docx/vmlImageParser.js +5 -4
- package/dist/docx/vmlPreview.d.ts +1 -3
- package/dist/docx/vmlPreview.js +2 -30
- package/dist/docx/watermarkParser.js +2 -2
- package/dist/docx/xmlParser.d.ts +38 -33
- package/dist/docx/xmlParser.js +92 -47
- package/dist/docx/xmlResourceLimits.d.ts +89 -9
- package/dist/docx/xmlResourceLimits.js +105 -24
- package/dist/internal/pageBreakRunSourceDescendantIndex.js +2 -1
- package/dist/internal/paragraphFormattingSerialization.d.ts +2 -3
- package/dist/internal/paragraphFormattingSerialization.js +29 -8
- package/dist/layout-bridge/convert/footnoteLayout.js +2 -7
- package/dist/layout-engine/index.d.ts +2 -2
- package/dist/layout-engine/index.js +2 -2
- package/dist/layout-engine/measure/measureBlocks.js +1 -6
- package/dist/layout-engine/types.d.ts +8 -2
- package/dist/layout-engine/types.js +35 -2
- package/dist/layout-painter/renderImage.js +4 -3
- package/dist/layout-painter/renderParagraph.js +4 -3
- package/dist/managers/autoSaveCodec.js +2 -8
- package/dist/markdown/images.js +1 -4
- package/dist/markdown/index.js +1 -1
- package/dist/markdown/internals.d.ts +6 -1
- package/dist/markdown/internals.js +14 -1
- package/dist/markdown/renderBlock.js +35 -21
- package/dist/markdown/renderParagraph.js +14 -5
- package/dist/markdown/renderRuns.js +4 -3
- package/dist/markdown/renderTable.js +4 -3
- package/dist/markdown/trailers.js +41 -7
- package/dist/markdown/types.d.ts +3 -7
- package/dist/prosemirror/attrs/index.js +71 -5
- package/dist/prosemirror/bookmarkBoundaryAttrs.d.ts +11 -1
- package/dist/prosemirror/bookmarkBoundaryAttrs.js +18 -3
- package/dist/prosemirror/commands/image.js +1 -0
- package/dist/prosemirror/commands/index.d.ts +3 -3
- package/dist/prosemirror/commands/index.js +2 -2
- package/dist/prosemirror/commands/paragraph.d.ts +3 -3
- package/dist/prosemirror/commands/paragraph.js +2 -2
- package/dist/prosemirror/commentIdAllocator.js +2 -7
- package/dist/prosemirror/conversion/fromProseDoc.js +197 -68
- package/dist/prosemirror/conversion/toProseDoc.d.ts +1 -14
- package/dist/prosemirror/conversion/toProseDoc.js +458 -335
- package/dist/prosemirror/extensions/core/ParagraphExtension.d.ts +14 -1
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +11 -6
- package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +3 -3
- package/dist/prosemirror/extensions/features/PasteCleanupExtension.d.ts +4 -1
- package/dist/prosemirror/extensions/features/PasteCleanupExtension.js +6 -2
- package/dist/prosemirror/extensions/features/pastedHeadingStyles.d.ts +7 -0
- package/dist/prosemirror/extensions/features/pastedHeadingStyles.js +74 -0
- package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +2 -3
- package/dist/prosemirror/extensions/marks/markUtils.d.ts +11 -3
- package/dist/prosemirror/extensions/marks/markUtils.js +98 -19
- package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +7 -3
- package/dist/prosemirror/extensions/nodes/ImageExtension.js +6 -1
- package/dist/prosemirror/extensions/nodes/ShapeExtension.js +8 -2
- package/dist/prosemirror/extensions/nodes/TableExtension.js +15 -1
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +8 -4
- package/dist/prosemirror/extensions/types.d.ts +2 -2
- package/dist/prosemirror/index.d.ts +3 -3
- package/dist/prosemirror/index.js +3 -3
- package/dist/prosemirror/insertOperations.d.ts +9 -2
- package/dist/prosemirror/insertOperations.js +9 -4
- package/dist/prosemirror/paragraphFormattingProvenance.d.ts +162 -0
- package/dist/prosemirror/paragraphFormattingProvenance.js +115 -0
- package/dist/prosemirror/plugins/documentStyles.d.ts +9 -1
- package/dist/prosemirror/plugins/documentStyles.js +11 -1
- package/dist/prosemirror/plugins/index.d.ts +2 -2
- package/dist/prosemirror/plugins/index.js +2 -2
- package/dist/prosemirror/plugins/revisionIds.d.ts +11 -2
- package/dist/prosemirror/plugins/revisionIds.js +21 -6
- package/dist/prosemirror/runFormattingReconciliation.js +3 -2
- package/dist/prosemirror/runStyleFormatting.d.ts +1 -1
- package/dist/prosemirror/schema/nodes.d.ts +81 -1
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +2 -0
- package/dist/prosemirror/styles/styleResolver.d.ts +9 -0
- package/dist/prosemirror/styles/styleResolver.js +12 -0
- package/dist/style-engine/styleEngine.d.ts +3 -0
- package/dist/style-engine/styleEngine.js +3 -0
- package/dist/style-sets/extract.js +1 -23
- package/dist/style-sets/stellaStyle.js +46 -39
- package/dist/style-sets/styleSetNormalization.d.ts +19 -0
- package/dist/style-sets/styleSetNormalization.js +99 -0
- package/dist/types/content.d.ts +2 -2
- package/dist/utils/base64.d.ts +36 -0
- package/dist/utils/base64.js +40 -0
- package/dist/utils/clipboard.js +2 -1
- package/dist/utils/createDocument.js +145 -20
- package/dist/utils/headingCollector.d.ts +8 -5
- package/dist/utils/headingCollector.js +23 -25
- package/dist/utils/tableOfContentsStyle.js +9 -2
- package/dist/utils/units.d.ts +10 -1
- package/dist/utils/units.js +12 -1
- package/dist/utils/urlSecurity.d.ts +8 -2
- package/dist/utils/urlSecurity.js +21 -3
- package/package.json +2 -2
- package/dist/docx/textWhitespace.d.ts +0 -4
- package/dist/docx/textWhitespace.js +0 -4
- package/dist/layout-bridge/engine/tableWidthUtils.d.ts +0 -6
- package/dist/layout-bridge/engine/tableWidthUtils.js +0 -25
- package/dist/markdown/headings.d.ts +0 -13
- package/dist/markdown/headings.js +0 -20
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { escapeXmlText } from "@stll/docx-core";
|
|
1
2
|
import JSZip from "jszip";
|
|
2
3
|
//#region src/ai-edits/__fixtures__/paragraphs.ts
|
|
3
4
|
/**
|
|
@@ -13,8 +14,7 @@ const ZIP_ENTRY_OPTIONS = {
|
|
|
13
14
|
date: new Date(Date.UTC(2e3, 0, 1)),
|
|
14
15
|
createFolders: false
|
|
15
16
|
};
|
|
16
|
-
const
|
|
17
|
-
const paragraphXml = (text) => `<w:p><w:r><w:t xml:space="preserve">${escapeXml(text)}</w:t></w:r></w:p>`;
|
|
17
|
+
const paragraphXml = (text) => `<w:p><w:r><w:t xml:space="preserve">${escapeXmlText(text)}</w:t></w:r></w:p>`;
|
|
18
18
|
const buildParagraphsDocx = async (paragraphs, { inTableCell } = {}) => {
|
|
19
19
|
const paragraphsXml = paragraphs.map(paragraphXml).join("");
|
|
20
20
|
const body = inTableCell ? `<w:tbl><w:tblPr><w:tblW w:w="0" w:type="auto"/></w:tblPr><w:tblGrid><w:gridCol w:w="9360"/></w:tblGrid><w:tr><w:tc><w:tcPr><w:tcW w:w="9360" w:type="dxa"/></w:tcPr>${paragraphsXml}</w:tc></w:tr></w:tbl>` + paragraphXml("After the table.") : paragraphsXml;
|
|
@@ -212,6 +212,7 @@ const sameReferencedNumberingLevels = ({ current, target, numId, levelsByNumId }
|
|
|
212
212
|
for (const level of levelsByNumId.get(numId) ?? []) {
|
|
213
213
|
const currentLevel = currentNumbering.getLevel(numId, level);
|
|
214
214
|
const targetLevel = targetNumbering.getLevel(numId, level);
|
|
215
|
+
if (currentLevel === null && targetLevel === null) continue;
|
|
215
216
|
if (!currentLevel || !targetLevel || canonicalJson(currentLevel) !== canonicalJson(targetLevel)) return false;
|
|
216
217
|
}
|
|
217
218
|
return true;
|
|
@@ -264,11 +265,12 @@ const formatBlockLine = (block, text) => {
|
|
|
264
265
|
return `${label} ${text}`;
|
|
265
266
|
};
|
|
266
267
|
const formatBlockForLLM = (block) => formatBlockLine(block, block.text);
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
268
|
+
/**
|
|
269
|
+
* The level the snapshot already classified. Scraping a digit out of the style
|
|
270
|
+
* id instead read `ClauseParagraph2` as an h2 and every localized heading id
|
|
271
|
+
* without a digit as an h1.
|
|
272
|
+
*/
|
|
273
|
+
const headingLevel = (block) => block.headingLevel ?? 1;
|
|
272
274
|
const revisionIdOf = (target) => typeof target === "number" ? target : target.id;
|
|
273
275
|
const commentPlainText = (comment) => (comment.content ?? []).map(paragraphPlainText).join("\n");
|
|
274
276
|
const paragraphPlainText = (paragraph) => {
|
package/dist/ai-edits/index.d.ts
CHANGED
|
@@ -6,8 +6,8 @@ import { DocPositionRange, clampRangeToDocSize, resolveFolioAIBlockRange, resolv
|
|
|
6
6
|
import { buildAnnotatedBlockText } from "./clean-text.js";
|
|
7
7
|
import { ApplyFolioDocumentOperationsOptions, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, 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, FolioDocumentOperationCapabilities, FolioDocumentOperationIssue, FolioDocumentOperationMode, FolioDocumentOperationPrecondition, FolioDocumentOperationReceipt, FolioDocumentOperationRecovery, FolioDocumentOperationResult, FolioDocumentOperationResultBase, FolioDocumentOperationStatus, FolioDocumentOperationStory, FolioDocumentOperationType, FolioDocumentOperationUndoFailureReason, FolioDocumentOperationUndoHandle, FolioDocumentOperationUndoResult, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch } from "../document-operations.js";
|
|
8
8
|
import { FolioCommentAnchor, FolioReviewChange, FolioReviewChangeKind, getCommentAnchorsFromDoc, getTrackedChangesFromDoc } from "./read.js";
|
|
9
|
-
import { createFolioAIEditSnapshot, createFolioAITextRangeHandle, hashFolioAIBlockText, isFolioAIContentBlock, normalizeFolioAIBlockText } from "./snapshot.js";
|
|
9
|
+
import { createFolioAIEditSnapshot, createFolioAIEditSnapshotWithStyleResolver, createFolioAITextRangeHandle, hashFolioAIBlockText, isFolioAIContentBlock, normalizeFolioAIBlockText } from "./snapshot.js";
|
|
10
10
|
import { FOLIO_RESOLVED_REVIEWED_VIEWS, FOLIO_REVIEWED_VIEWS, FolioApplyDocumentOperationsToStoryOptions, FolioDocumentStory, FolioDocumentStoryHandle, FolioDocumentStoryNotFoundError, FolioEditableDocumentStoryHandle, FolioReadReviewedStoryOptions, FolioResolveReviewedStoryOptions, FolioResolvedReviewedView, FolioReviewedStory, FolioReviewedView, UnsupportedFolioReviewedViewError, isFolioResolvedReviewedView, isFolioReviewedView } from "./headless.js";
|
|
11
11
|
import { getFolioDocumentOutline, readFolioDocumentSection } from "./scoped-reading.js";
|
|
12
12
|
import { getFolioParaIdFromBlockId } from "../types/block-id.js";
|
|
13
|
-
export { type ApplyFolioDocumentOperationsOptions, type DocPositionRange, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, 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, FOLIO_RESOLVED_REVIEWED_VIEWS, FOLIO_REVIEWED_VIEWS, type FolioAIBlock, type FolioAIBlockAnchor, type FolioAIBlockKind, type FolioAIBlockPreviewRun, type FolioAIBlockStructuralBoundary, type FolioAIBlockTableLocation, type FolioAIComment, type FolioAIEditAppliedOperation, type FolioAIEditApplyMode, type FolioAIEditApplyOutcome, type FolioAIEditApplyResult, type FolioAIEditNormalization, type FolioAIEditNormalizationCode, type FolioAIEditOperation, type FolioAIEditPrecondition, type FolioAIEditReviewMeta, type FolioAIEditSeverity, type FolioAIEditSkipReason, type FolioAIEditSkippedOperation, type FolioAIEditSnapshot, type FolioAIEditView, type FolioAIInlineBooleanProperty, type FolioAIInlineFormatting, type FolioAIInlineFormattingPatch, type FolioAIInsertFormattingScope, type FolioAIParagraphSpacing, type FolioAISignatureParty, type FolioAITextRangeHandle, type FolioApplyDocumentOperationsToStoryOptions, type FolioCommentAnchor, type FolioContentParagraphKind, type FolioDocumentNavigationTarget, type FolioDocumentOperation, type FolioDocumentOperationAffectedTarget, type FolioDocumentOperationBatch, type FolioDocumentOperationCapabilities, type FolioDocumentOperationIssue, type FolioDocumentOperationMode, type FolioDocumentOperationPrecondition, type FolioDocumentOperationReceipt, type FolioDocumentOperationRecovery, type FolioDocumentOperationResult, type FolioDocumentOperationResultBase, type FolioDocumentOperationStatus, type FolioDocumentOperationStory, type FolioDocumentOperationType, type FolioDocumentOperationUndoFailureReason, type FolioDocumentOperationUndoHandle, type FolioDocumentOperationUndoResult, type FolioDocumentOutline, type FolioDocumentOutlineEntry, type FolioDocumentSection, type FolioDocumentSectionHandle, type FolioDocumentSectionReadResult, type FolioDocumentStory, type FolioDocumentStoryHandle, FolioDocumentStoryNotFoundError, type FolioEditableDocumentStoryHandle, type FolioReadReviewedStoryOptions, type FolioResolveReviewedStoryOptions, type FolioResolvedReviewedView, type FolioReviewChange, type FolioReviewChangeKind, type FolioReviewedStory, type FolioReviewedView, type FolioRevisionStamp, type FolioWordDiffOptions, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, UnsupportedFolioReviewedViewError, WORD_DIFF_GRANULARITIES, type WordDiffGranularity, type WordDiffNormalization, type WordDiffOptions, type WordDiffSegment, applyFolioAIEditOperations, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, buildAnnotatedBlockText, clampRangeToDocSize, createFolioAIEditSnapshot, createFolioAITextRangeHandle, diffWordSegments, getCommentAnchorsFromDoc, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioDocumentOutline, getFolioParaIdFromBlockId, getTrackedChangesFromDoc, hashFolioAIBlockText, isFolioAIContentBlock, isFolioDocumentOperationModeSupported, isFolioResolvedReviewedView, isFolioReviewedView, isSupportedFolioDocumentOperationVersion, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, readFolioDocumentSection, resolveFolioAIBlockRange, resolveFolioAITextRange, resolvePassageRange };
|
|
13
|
+
export { type ApplyFolioDocumentOperationsOptions, type DocPositionRange, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, 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, FOLIO_RESOLVED_REVIEWED_VIEWS, FOLIO_REVIEWED_VIEWS, type FolioAIBlock, type FolioAIBlockAnchor, type FolioAIBlockKind, type FolioAIBlockPreviewRun, type FolioAIBlockStructuralBoundary, type FolioAIBlockTableLocation, type FolioAIComment, type FolioAIEditAppliedOperation, type FolioAIEditApplyMode, type FolioAIEditApplyOutcome, type FolioAIEditApplyResult, type FolioAIEditNormalization, type FolioAIEditNormalizationCode, type FolioAIEditOperation, type FolioAIEditPrecondition, type FolioAIEditReviewMeta, type FolioAIEditSeverity, type FolioAIEditSkipReason, type FolioAIEditSkippedOperation, type FolioAIEditSnapshot, type FolioAIEditView, type FolioAIInlineBooleanProperty, type FolioAIInlineFormatting, type FolioAIInlineFormattingPatch, type FolioAIInsertFormattingScope, type FolioAIParagraphSpacing, type FolioAISignatureParty, type FolioAITextRangeHandle, type FolioApplyDocumentOperationsToStoryOptions, type FolioCommentAnchor, type FolioContentParagraphKind, type FolioDocumentNavigationTarget, type FolioDocumentOperation, type FolioDocumentOperationAffectedTarget, type FolioDocumentOperationBatch, type FolioDocumentOperationCapabilities, type FolioDocumentOperationIssue, type FolioDocumentOperationMode, type FolioDocumentOperationPrecondition, type FolioDocumentOperationReceipt, type FolioDocumentOperationRecovery, type FolioDocumentOperationResult, type FolioDocumentOperationResultBase, type FolioDocumentOperationStatus, type FolioDocumentOperationStory, type FolioDocumentOperationType, type FolioDocumentOperationUndoFailureReason, type FolioDocumentOperationUndoHandle, type FolioDocumentOperationUndoResult, type FolioDocumentOutline, type FolioDocumentOutlineEntry, type FolioDocumentSection, type FolioDocumentSectionHandle, type FolioDocumentSectionReadResult, type FolioDocumentStory, type FolioDocumentStoryHandle, FolioDocumentStoryNotFoundError, type FolioEditableDocumentStoryHandle, type FolioReadReviewedStoryOptions, type FolioResolveReviewedStoryOptions, type FolioResolvedReviewedView, type FolioReviewChange, type FolioReviewChangeKind, type FolioReviewedStory, type FolioReviewedView, type FolioRevisionStamp, type FolioWordDiffOptions, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, UnsupportedFolioReviewedViewError, WORD_DIFF_GRANULARITIES, type WordDiffGranularity, type WordDiffNormalization, type WordDiffOptions, type WordDiffSegment, applyFolioAIEditOperations, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, buildAnnotatedBlockText, clampRangeToDocSize, createFolioAIEditSnapshot, createFolioAIEditSnapshotWithStyleResolver, createFolioAITextRangeHandle, diffWordSegments, getCommentAnchorsFromDoc, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioDocumentOutline, getFolioParaIdFromBlockId, getTrackedChangesFromDoc, hashFolioAIBlockText, isFolioAIContentBlock, isFolioDocumentOperationModeSupported, isFolioResolvedReviewedView, isFolioReviewedView, isSupportedFolioDocumentOperationVersion, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, readFolioDocumentSection, resolveFolioAIBlockRange, resolveFolioAITextRange, resolvePassageRange };
|
package/dist/ai-edits/index.js
CHANGED
|
@@ -6,6 +6,6 @@ import { buildAnnotatedBlockText } from "./clean-text.js";
|
|
|
6
6
|
import { FOLIO_RESOLVED_REVIEWED_VIEWS, FOLIO_REVIEWED_VIEWS, FolioDocumentStoryNotFoundError, UnsupportedFolioReviewedViewError, isFolioResolvedReviewedView, isFolioReviewedView } from "./headless.js";
|
|
7
7
|
import { getCommentAnchorsFromDoc, getTrackedChangesFromDoc } from "./read.js";
|
|
8
8
|
import { getFolioDocumentOutline, readFolioDocumentSection } from "./scoped-reading.js";
|
|
9
|
-
import { createFolioAIEditSnapshot, createFolioAITextRangeHandle, hashFolioAIBlockText, isFolioAIContentBlock, normalizeFolioAIBlockText } from "./snapshot.js";
|
|
9
|
+
import { createFolioAIEditSnapshot, createFolioAIEditSnapshotWithStyleResolver, createFolioAITextRangeHandle, hashFolioAIBlockText, isFolioAIContentBlock, normalizeFolioAIBlockText } from "./snapshot.js";
|
|
10
10
|
import { WORD_DIFF_GRANULARITIES, diffWordSegments } from "./word-diff.js";
|
|
11
|
-
export { FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, 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, FOLIO_RESOLVED_REVIEWED_VIEWS, FOLIO_REVIEWED_VIEWS, FolioDocumentStoryNotFoundError, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, UnsupportedFolioReviewedViewError, WORD_DIFF_GRANULARITIES, applyFolioAIEditOperations, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, buildAnnotatedBlockText, clampRangeToDocSize, createFolioAIEditSnapshot, createFolioAITextRangeHandle, diffWordSegments, getCommentAnchorsFromDoc, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioDocumentOutline, getFolioParaIdFromBlockId, getTrackedChangesFromDoc, hashFolioAIBlockText, isFolioAIContentBlock, isFolioDocumentOperationModeSupported, isFolioResolvedReviewedView, isFolioReviewedView, isSupportedFolioDocumentOperationVersion, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, readFolioDocumentSection, resolveFolioAIBlockRange, resolveFolioAITextRange, resolvePassageRange };
|
|
11
|
+
export { FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, 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, FOLIO_RESOLVED_REVIEWED_VIEWS, FOLIO_REVIEWED_VIEWS, FolioDocumentStoryNotFoundError, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, UnsupportedFolioReviewedViewError, WORD_DIFF_GRANULARITIES, applyFolioAIEditOperations, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, buildAnnotatedBlockText, clampRangeToDocSize, createFolioAIEditSnapshot, createFolioAIEditSnapshotWithStyleResolver, createFolioAITextRangeHandle, diffWordSegments, getCommentAnchorsFromDoc, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioDocumentOutline, getFolioParaIdFromBlockId, getTrackedChangesFromDoc, hashFolioAIBlockText, isFolioAIContentBlock, isFolioDocumentOperationModeSupported, isFolioResolvedReviewedView, isFolioReviewedView, isSupportedFolioDocumentOperationVersion, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, readFolioDocumentSection, resolveFolioAIBlockRange, resolveFolioAITextRange, resolvePassageRange };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { EMPTY_BUILT_IN_STYLE_INDEX, resolveHeadingLevel } from "../docx/builtInStyles.js";
|
|
1
2
|
import { recreateProseNodeWithParagraphPropertySource } from "../docx/paragraphPropertySource.js";
|
|
2
3
|
import { expectCharacterStyleMarkAttrs, expectHyperlinkMarkAttrs, expectParagraphAttrs, expectRunFormattingOverrideMarkAttrs } from "../prosemirror/attrs/index.js";
|
|
3
4
|
import { marksToTextFormatting } from "../prosemirror/conversion/fromProseDoc.js";
|
|
@@ -335,6 +336,7 @@ const getTableLocation = ({ path, blockIndex, tableIndexByStart }) => {
|
|
|
335
336
|
}
|
|
336
337
|
};
|
|
337
338
|
const createFolioAIEditSnapshotInternal = (doc, styleResolver) => {
|
|
339
|
+
const builtInStyles = styleResolver?.builtInStyles ?? EMPTY_BUILT_IN_STYLE_INDEX;
|
|
338
340
|
const draftBlocks = [];
|
|
339
341
|
const hashCounts = /* @__PURE__ */ new Map();
|
|
340
342
|
const usedBlockIds = /* @__PURE__ */ new Set();
|
|
@@ -394,9 +396,9 @@ const createFolioAIEditSnapshotInternal = (doc, styleResolver) => {
|
|
|
394
396
|
});
|
|
395
397
|
}
|
|
396
398
|
usedBlockIds.add(id);
|
|
397
|
-
const headingLevel = getHeadingLevel(node);
|
|
399
|
+
const headingLevel = getHeadingLevel(node, builtInStyles);
|
|
398
400
|
const kind = getBlockKind(node, headingLevel);
|
|
399
|
-
const displayLabel = getDisplayLabel(node);
|
|
401
|
+
const displayLabel = getDisplayLabel(node, kind === "heading");
|
|
400
402
|
const styleId = getStyleId(node);
|
|
401
403
|
const listLevel = getListLevel(node);
|
|
402
404
|
const listReference = getListReference(node);
|
|
@@ -477,19 +479,21 @@ const getBlockKind = (node, headingLevel) => {
|
|
|
477
479
|
if (headingLevel !== void 0) return "heading";
|
|
478
480
|
return "paragraph";
|
|
479
481
|
};
|
|
480
|
-
|
|
482
|
+
/** The block's 1-based heading level, as {@link resolveHeadingLevel} classifies it. */
|
|
483
|
+
const getHeadingLevel = (node, styles) => {
|
|
481
484
|
const outlineLevel = node.attrs["outlineLevel"];
|
|
482
|
-
if (typeof outlineLevel === "number" && Number.isInteger(outlineLevel) && outlineLevel >= 0 && outlineLevel <= 8) return outlineLevel + 1;
|
|
483
485
|
const styleId = node.attrs["styleId"];
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
486
|
+
const level = resolveHeadingLevel({
|
|
487
|
+
outlineLevel: typeof outlineLevel === "number" ? outlineLevel : null,
|
|
488
|
+
styleId: typeof styleId === "string" ? styleId : null
|
|
489
|
+
}, styles);
|
|
490
|
+
return level === void 0 ? void 0 : level + 1;
|
|
487
491
|
};
|
|
488
|
-
const getDisplayLabel = (node) => {
|
|
492
|
+
const getDisplayLabel = (node, isHeading) => {
|
|
489
493
|
const listMarker = node.attrs["listMarker"];
|
|
490
494
|
if (typeof listMarker === "string" && listMarker.trim().length > 0) return listMarker.trim();
|
|
491
495
|
const styleId = node.attrs["styleId"];
|
|
492
|
-
if (typeof styleId === "string"
|
|
496
|
+
if (isHeading && typeof styleId === "string") return styleId;
|
|
493
497
|
};
|
|
494
498
|
const getListLevel = (node) => {
|
|
495
499
|
const numPr = node.attrs["numPr"];
|
|
@@ -455,6 +455,27 @@ const MAX_CONTENT_STRUCTURE_PROFILE_TEXT_CODE_UNITS = 16384;
|
|
|
455
455
|
const MAX_CONTENT_STRUCTURE_PROFILE_TOKENS = 64;
|
|
456
456
|
const MAX_CONTENT_STRUCTURE_PROFILE_KIND_CODE_UNITS = 256;
|
|
457
457
|
const CONTENT_STRUCTURE_ANCHOR_MINIMUM_WORD_COUNT = 3;
|
|
458
|
+
/** Four independent 32-bit lanes, so a digest collision needs four at once. */
|
|
459
|
+
const CONTENT_DIGEST_SEEDS = [
|
|
460
|
+
2166136261,
|
|
461
|
+
2654435769,
|
|
462
|
+
2246822507,
|
|
463
|
+
3266489909
|
|
464
|
+
];
|
|
465
|
+
const CONTENT_DIGEST_PRIMES = [
|
|
466
|
+
16777619,
|
|
467
|
+
1540483477,
|
|
468
|
+
668265263,
|
|
469
|
+
374761393
|
|
470
|
+
];
|
|
471
|
+
const foldContentDigest = (lanes, text) => {
|
|
472
|
+
for (let index = 0; index < text.length; index++) {
|
|
473
|
+
const unit = text.charCodeAt(index);
|
|
474
|
+
for (let lane = 0; lane < lanes.length; lane++) lanes[lane] = Math.imul((lanes[lane] ?? 0) ^ unit, CONTENT_DIGEST_PRIMES[lane] ?? 1);
|
|
475
|
+
}
|
|
476
|
+
for (let lane = 0; lane < lanes.length; lane++) lanes[lane] = Math.imul((lanes[lane] ?? 0) ^ text.length, CONTENT_DIGEST_PRIMES[lane] ?? 1);
|
|
477
|
+
};
|
|
478
|
+
const renderContentDigest = (lanes, blockCount) => `${String(blockCount)}:${[...lanes].map((lane) => (lane >>> 0).toString(36)).join(":")}`;
|
|
458
479
|
const createContentStructureProfile = ({ blocks, blockStructure, idStability, physicalCellCount, retainContainerIdentity = false }) => {
|
|
459
480
|
let containerIdentity = null;
|
|
460
481
|
if (retainContainerIdentity) if (blocks.length > MAX_CONTENT_STRUCTURE_PROFILE_BLOCKS) containerIdentity = { status: "unavailable" };
|
|
@@ -481,39 +502,34 @@ const createContentStructureProfile = ({ blocks, blockStructure, idStability, ph
|
|
|
481
502
|
if (idStability(block) === "stable") stableIds.push(block.id);
|
|
482
503
|
}
|
|
483
504
|
}
|
|
484
|
-
|
|
485
|
-
|
|
505
|
+
const lanes = Int32Array.from(CONTENT_DIGEST_SEEDS);
|
|
506
|
+
for (const block of blocks) foldContentDigest(lanes, JSON.stringify([
|
|
507
|
+
...blockStructure(block),
|
|
508
|
+
block.kind,
|
|
509
|
+
block.text
|
|
510
|
+
]));
|
|
511
|
+
const identity = {
|
|
486
512
|
blockIds,
|
|
487
513
|
containerIdentity,
|
|
488
|
-
|
|
514
|
+
contentDigest: renderContentDigest(lanes, blocks.length),
|
|
489
515
|
physicalCellCount: physicalCellCount ?? null,
|
|
490
|
-
stableIds
|
|
491
|
-
tokenCounts: null,
|
|
492
|
-
tokenCount: 0
|
|
516
|
+
stableIds
|
|
493
517
|
};
|
|
518
|
+
const overCap = {
|
|
519
|
+
...identity,
|
|
520
|
+
anchors: { status: "skipped-over-cap" },
|
|
521
|
+
tokens: { status: "skipped-over-cap" }
|
|
522
|
+
};
|
|
523
|
+
if (blocks.length > MAX_CONTENT_STRUCTURE_PROFILE_BLOCKS) return overCap;
|
|
494
524
|
let textCodeUnits = 0;
|
|
495
525
|
for (const block of blocks) {
|
|
496
|
-
if (block.kind.length > MAX_CONTENT_STRUCTURE_PROFILE_KIND_CODE_UNITS || block.text.length > MAX_CONTENT_STRUCTURE_PROFILE_TEXT_CODE_UNITS - textCodeUnits) return
|
|
497
|
-
anchorTexts: [],
|
|
498
|
-
blockIds,
|
|
499
|
-
containerIdentity,
|
|
500
|
-
exactSignature: null,
|
|
501
|
-
physicalCellCount: physicalCellCount ?? null,
|
|
502
|
-
stableIds,
|
|
503
|
-
tokenCounts: null,
|
|
504
|
-
tokenCount: 0
|
|
505
|
-
};
|
|
526
|
+
if (block.kind.length > MAX_CONTENT_STRUCTURE_PROFILE_KIND_CODE_UNITS || block.text.length > MAX_CONTENT_STRUCTURE_PROFILE_TEXT_CODE_UNITS - textCodeUnits) return overCap;
|
|
506
527
|
textCodeUnits += block.text.length;
|
|
507
528
|
}
|
|
508
529
|
const tokenCounts = /* @__PURE__ */ new Map();
|
|
509
530
|
const anchorTexts = /* @__PURE__ */ new Set();
|
|
510
531
|
let tokenCount = 0;
|
|
511
532
|
let tokensComplete = true;
|
|
512
|
-
const signature = blocks.map((block) => [
|
|
513
|
-
...blockStructure(block),
|
|
514
|
-
block.kind,
|
|
515
|
-
block.text
|
|
516
|
-
]);
|
|
517
533
|
for (const block of blocks) {
|
|
518
534
|
let blockWordCount = 0;
|
|
519
535
|
for (const match of block.text.matchAll(/\S+/gu)) {
|
|
@@ -530,24 +546,31 @@ const createContentStructureProfile = ({ blocks, blockStructure, idStability, ph
|
|
|
530
546
|
if (!tokensComplete) break;
|
|
531
547
|
}
|
|
532
548
|
return {
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
549
|
+
...identity,
|
|
550
|
+
anchors: {
|
|
551
|
+
status: "computed",
|
|
552
|
+
texts: [...anchorTexts]
|
|
553
|
+
},
|
|
554
|
+
tokens: tokensComplete ? {
|
|
555
|
+
status: "computed",
|
|
556
|
+
counts: tokenCounts,
|
|
557
|
+
total: tokenCount
|
|
558
|
+
} : { status: "skipped-over-cap" }
|
|
541
559
|
};
|
|
542
560
|
};
|
|
561
|
+
const UNKNOWN_CONTENT_STRUCTURE_SIMILARITY = { status: "unknown" };
|
|
543
562
|
const contentStructureProfileSimilarity = (base, revised, workSession) => {
|
|
544
|
-
if (
|
|
545
|
-
|
|
546
|
-
|
|
563
|
+
if (base.tokens.status === "skipped-over-cap" || revised.tokens.status === "skipped-over-cap") return UNKNOWN_CONTENT_STRUCTURE_SIMILARITY;
|
|
564
|
+
if (base.tokens.total === 0 || revised.tokens.total === 0) return UNKNOWN_CONTENT_STRUCTURE_SIMILARITY;
|
|
565
|
+
const [tokens, counterparts] = base.tokens.counts.size <= revised.tokens.counts.size ? [base.tokens.counts, revised.tokens.counts] : [revised.tokens.counts, base.tokens.counts];
|
|
566
|
+
if (tokens.size > workSession.remainingStructuralTokenLookups) return UNKNOWN_CONTENT_STRUCTURE_SIMILARITY;
|
|
547
567
|
workSession.remainingStructuralTokenLookups -= tokens.size;
|
|
548
568
|
let shared = 0;
|
|
549
569
|
for (const [token, count] of tokens) shared += Math.min(count, counterparts.get(token) ?? 0);
|
|
550
|
-
return
|
|
570
|
+
return {
|
|
571
|
+
status: "measured",
|
|
572
|
+
value: 2 * shared / (base.tokens.total + revised.tokens.total)
|
|
573
|
+
};
|
|
551
574
|
};
|
|
552
575
|
const tableStructureProfile = (blocks, idStability) => {
|
|
553
576
|
const tableOrdinalByIndex = /* @__PURE__ */ new Map();
|
|
@@ -634,7 +657,6 @@ const uniqueExactContentSequencePairs = ({ baseKeys, revisedKeys }) => {
|
|
|
634
657
|
const uniqueIndexes = (keys) => {
|
|
635
658
|
const indexes = /* @__PURE__ */ new Map();
|
|
636
659
|
keys.forEach((key, index) => {
|
|
637
|
-
if (key === -1) return;
|
|
638
660
|
indexes.set(key, indexes.has(key) ? null : index);
|
|
639
661
|
});
|
|
640
662
|
return indexes;
|
|
@@ -731,16 +753,15 @@ const alignProfiledContentSequence = ({ base, revised, workSession, canPair = ()
|
|
|
731
753
|
}
|
|
732
754
|
const exactSignatureKeys = /* @__PURE__ */ new Map();
|
|
733
755
|
let nextExactSignatureKey = 0;
|
|
734
|
-
const
|
|
735
|
-
|
|
736
|
-
const existing = exactSignatureKeys.get(signature);
|
|
756
|
+
const internContentDigest = (digest) => {
|
|
757
|
+
const existing = exactSignatureKeys.get(digest);
|
|
737
758
|
if (existing !== void 0) return existing;
|
|
738
759
|
const key = nextExactSignatureKey++;
|
|
739
|
-
exactSignatureKeys.set(
|
|
760
|
+
exactSignatureKeys.set(digest, key);
|
|
740
761
|
return key;
|
|
741
762
|
};
|
|
742
|
-
const baseExactSignatureKeys = base.map(({ profile }) =>
|
|
743
|
-
const revisedExactSignatureKeys = revised.map(({ profile }) =>
|
|
763
|
+
const baseExactSignatureKeys = base.map(({ profile }) => internContentDigest(profile.contentDigest));
|
|
764
|
+
const revisedExactSignatureKeys = revised.map(({ profile }) => internContentDigest(profile.contentDigest));
|
|
744
765
|
let persistedPairs = /* @__PURE__ */ new Set();
|
|
745
766
|
if (base.some(({ profile }) => profile.containerIdentity !== null) || revised.some(({ profile }) => profile.containerIdentity !== null)) {
|
|
746
767
|
const exactPairs = uniqueExactContentSequencePairs({
|
|
@@ -781,16 +802,20 @@ const alignProfiledContentSequence = ({ base, revised, workSession, canPair = ()
|
|
|
781
802
|
if (!revisedItem) continue;
|
|
782
803
|
if (!canPair(baseItem, revisedItem)) continue;
|
|
783
804
|
const pairIndex = baseIndex * revised.length + revisedIndex;
|
|
784
|
-
const exact = baseExactSignatureKeys[baseIndex]
|
|
805
|
+
const exact = baseExactSignatureKeys[baseIndex] === revisedExactSignatureKeys[revisedIndex];
|
|
785
806
|
const stable = stablePairs.has(pairIndex);
|
|
786
|
-
const profileSimilarity = exact ?
|
|
787
|
-
|
|
807
|
+
const profileSimilarity = exact ? {
|
|
808
|
+
status: "measured",
|
|
809
|
+
value: 1
|
|
810
|
+
} : contentStructureProfileSimilarity(baseItem.profile, revisedItem.profile, workSession);
|
|
811
|
+
const similar = profileSimilarity.status === "measured" ? Math.max(0, Math.min(1, profileSimilarity.value * similarityFactor(baseItem, revisedItem))) : 0;
|
|
812
|
+
const similarEnough = profileSimilarity.status === "measured" && similar >= CONTENT_STRUCTURE_PAIR_SIMILARITY;
|
|
788
813
|
const stableAtSamePosition = stable && baseIndex === revisedIndex;
|
|
789
814
|
const persistedAtSamePosition = baseIndex === revisedIndex && provenanceTransitionAtSamePosition[baseIndex] === 1;
|
|
790
815
|
const shiftedPersisted = baseIndex !== revisedIndex && persistedPairs.has(pairIndex);
|
|
791
816
|
const persisted = persistedAtSamePosition || shiftedPersisted;
|
|
792
817
|
const soleStructuralSlot = pairSoleStructuralSlot && base.length === 1 && revised.length === 1;
|
|
793
|
-
if (!exact && !stableAtSamePosition && !persisted && !soleStructuralSlot &&
|
|
818
|
+
if (!exact && !stableAtSamePosition && !persisted && !soleStructuralSlot && !similarEnough) continue;
|
|
794
819
|
pairScores[pairIndex] = (stable ? stableWeight : 0) + (exact ? exactWeight : 0) + (shiftedPersisted && !stable && !exact ? secondaryWeight : 0) + (persistedAtSamePosition ? continuityBonus : 0) + Math.round(similar * CONTENT_STRUCTURE_SIMILARITY_SCALE) + (soleStructuralSlot ? 1 : 0);
|
|
795
820
|
}
|
|
796
821
|
}
|
|
@@ -1124,11 +1149,10 @@ const contentStructureEvidenceIndexes = (base, revised) => {
|
|
|
1124
1149
|
let nextExactKey = 0;
|
|
1125
1150
|
const internExactSignatures = (items) => {
|
|
1126
1151
|
for (const { profile } of items) {
|
|
1127
|
-
|
|
1128
|
-
let key = exactKeys.get(profile.exactSignature);
|
|
1152
|
+
let key = exactKeys.get(profile.contentDigest);
|
|
1129
1153
|
if (key === void 0) {
|
|
1130
1154
|
key = nextExactKey++;
|
|
1131
|
-
exactKeys.set(profile.
|
|
1155
|
+
exactKeys.set(profile.contentDigest, key);
|
|
1132
1156
|
}
|
|
1133
1157
|
exactKeyByProfile.set(profile, key);
|
|
1134
1158
|
}
|
|
@@ -1152,7 +1176,7 @@ const contentStructureEvidenceIndexes = (base, revised) => {
|
|
|
1152
1176
|
if (indexes.at(-1) !== itemIndex) indexes.push(itemIndex);
|
|
1153
1177
|
} else stableIndexes.set(id, [itemIndex]);
|
|
1154
1178
|
}
|
|
1155
|
-
for (const text of profile.
|
|
1179
|
+
for (const text of profile.anchors.status === "computed" ? profile.anchors.texts : []) {
|
|
1156
1180
|
const indexes = anchorTextIndexes.get(text);
|
|
1157
1181
|
if (indexes) {
|
|
1158
1182
|
if (indexes.at(-1) !== itemIndex) indexes.push(itemIndex);
|
|
@@ -1171,16 +1195,32 @@ const contentStructureEvidenceIndexes = (base, revised) => {
|
|
|
1171
1195
|
revised: index(revised)
|
|
1172
1196
|
};
|
|
1173
1197
|
};
|
|
1174
|
-
|
|
1198
|
+
/**
|
|
1199
|
+
* Whether the evidence lies outside the range, and only outside it.
|
|
1200
|
+
*
|
|
1201
|
+
* Evidence inside the range is at least as good a counterpart as evidence
|
|
1202
|
+
* beyond it, so a match that is also present locally does not make the local
|
|
1203
|
+
* pair suspect. Without the second test, two structurally identical tables in
|
|
1204
|
+
* one document cancel each other: each shares every exact signature and anchor
|
|
1205
|
+
* text with the other by construction, so each looks like it belongs
|
|
1206
|
+
* elsewhere, and comparing the document with itself reports both deleted and
|
|
1207
|
+
* both re-inserted.
|
|
1208
|
+
*/
|
|
1209
|
+
const sortedIndexesLeaveRange = (indexes, start, end) => {
|
|
1210
|
+
if (indexes === void 0) return false;
|
|
1211
|
+
if ((indexes.at(0) ?? start) >= start && (indexes.at(-1) ?? end - 1) < end) return false;
|
|
1212
|
+
return !indexes.some((index) => index >= start && index < end);
|
|
1213
|
+
};
|
|
1175
1214
|
const profileHasEvidenceOutsideRange = (profile, opposite, start, end) => {
|
|
1176
1215
|
const exactKey = opposite.exactKeyByProfile.get(profile);
|
|
1177
1216
|
if (exactKey !== void 0 && sortedIndexesLeaveRange(opposite.exactIndexes.get(exactKey), start, end)) return true;
|
|
1178
|
-
if (profile.
|
|
1217
|
+
if (profile.anchors.status === "computed" && profile.anchors.texts.some((text) => sortedIndexesLeaveRange(opposite.anchorTextIndexes.get(text), start, end))) return true;
|
|
1179
1218
|
return profile.stableIds.some((id) => sortedIndexesLeaveRange(opposite.stableIndexes.get(id), start, end));
|
|
1180
1219
|
};
|
|
1181
1220
|
const profilesShareContentAnchor = (base, revised) => {
|
|
1182
|
-
|
|
1183
|
-
|
|
1221
|
+
if (base.anchors.status === "skipped-over-cap" || revised.anchors.status === "skipped-over-cap") return "unknown";
|
|
1222
|
+
const baseTexts = new Set(base.anchors.texts);
|
|
1223
|
+
return revised.anchors.texts.some((text) => baseTexts.has(text)) ? "shares" : "disjoint";
|
|
1184
1224
|
};
|
|
1185
1225
|
const isBodyDocumentSegment = (segment) => segment.kind === "body";
|
|
1186
1226
|
const profileBodySegments = (segments, idStability) => segments.flatMap((segment) => isBodyDocumentSegment(segment) ? [{
|
|
@@ -1273,13 +1313,13 @@ const pairTableSegmentsInGaps = ({ base, revised, baseGaps, revisedGaps, trusted
|
|
|
1273
1313
|
const revisedEnd = revisedStart + revisedItems.length;
|
|
1274
1314
|
const baseHasExternalEvidence = new Set(baseItems.filter(({ profile }) => profileHasEvidenceOutsideRange(profile, evidence.revised, revisedStart, revisedEnd)).map(({ item }) => item));
|
|
1275
1315
|
const revisedHasExternalEvidence = new Set(revisedItems.filter(({ profile }) => profileHasEvidenceOutsideRange(profile, evidence.base, baseStart, baseEnd)).map(({ item }) => item));
|
|
1276
|
-
const
|
|
1316
|
+
const solePairAnchorOverlap = baseItems.length === 1 && revisedItems.length === 1 ? profilesShareContentAnchor(baseItems.at(0)?.profile ?? panic("A sole base table has no profile"), revisedItems.at(0)?.profile ?? panic("A sole revised table has no profile")) : "disjoint";
|
|
1277
1317
|
const alignments = alignProfiledContentSequence({
|
|
1278
1318
|
base: baseItems,
|
|
1279
1319
|
revised: revisedItems,
|
|
1280
1320
|
workSession,
|
|
1281
1321
|
canPair: (baseItem, revisedItem) => !baseHasExternalEvidence.has(baseItem.item) && !revisedHasExternalEvidence.has(revisedItem.item),
|
|
1282
|
-
pairSoleStructuralSlot: trustedBodyPairCount > 0 ||
|
|
1322
|
+
pairSoleStructuralSlot: trustedBodyPairCount > 0 || solePairAnchorOverlap === "shares"
|
|
1283
1323
|
});
|
|
1284
1324
|
for (const alignment of alignments) {
|
|
1285
1325
|
if (alignment.type !== "pair") continue;
|
|
@@ -29,6 +29,15 @@ const textBlocksOf = (doc) => {
|
|
|
29
29
|
});
|
|
30
30
|
return blocks;
|
|
31
31
|
};
|
|
32
|
+
/**
|
|
33
|
+
* Clean-text offset nearest a document position.
|
|
34
|
+
*
|
|
35
|
+
* `buildCleanBlockText` returns one offset per character plus one for
|
|
36
|
+
* end-of-block, so there is always an offset to land on. The result was typed
|
|
37
|
+
* `number | null` and never was: the caller's refusal branch could not run,
|
|
38
|
+
* while an empty `offsets` would have produced `-1` rather than the `null` the
|
|
39
|
+
* type promised.
|
|
40
|
+
*/
|
|
32
41
|
const offsetAt = ({ offsets, position }) => {
|
|
33
42
|
let low = 0;
|
|
34
43
|
let high = offsets.length;
|
|
@@ -40,16 +49,33 @@ const offsetAt = ({ offsets, position }) => {
|
|
|
40
49
|
}
|
|
41
50
|
return Math.min(low, offsets.length - 1);
|
|
42
51
|
};
|
|
52
|
+
/**
|
|
53
|
+
* Attributes a conversion mints for itself rather than reads from the package.
|
|
54
|
+
*
|
|
55
|
+
* `toProseDoc` salts text-box anchor ids with a per-load nonce so a pasted span
|
|
56
|
+
* cannot hijack a real anchor. A comparison reads two independent conversions,
|
|
57
|
+
* so a minted handle differs on every run, and a key holding one makes a
|
|
58
|
+
* document differ from itself. Only document facts belong in a key.
|
|
59
|
+
*
|
|
60
|
+
* The guard against a node type gaining a minted attribute without being added
|
|
61
|
+
* here is not this list but `compareIdentity.property.test.ts`, which compares
|
|
62
|
+
* generated packages carrying each atom with themselves.
|
|
63
|
+
*/
|
|
64
|
+
const CONVERSION_LOCAL_ATTRS = { textBoxAnchor: ["anchorId"] };
|
|
65
|
+
const documentFactAttrs = (node) => {
|
|
66
|
+
const local = CONVERSION_LOCAL_ATTRS[node.type.name];
|
|
67
|
+
if (!local) return node.attrs;
|
|
68
|
+
return Object.fromEntries(Object.entries(node.attrs).filter(([name]) => !local.includes(name)));
|
|
69
|
+
};
|
|
43
70
|
const atomKey = (node) => canonicalJson({
|
|
44
71
|
type: node.type.name,
|
|
45
|
-
attrs: node
|
|
72
|
+
attrs: documentFactAttrs(node),
|
|
46
73
|
content: node.content.toJSON()
|
|
47
74
|
});
|
|
48
75
|
const atomBlockOf = ({ node, from }) => {
|
|
49
76
|
const clean = buildCleanBlockText(node, from, { fieldResults: "omitted" });
|
|
50
77
|
const supported = [];
|
|
51
78
|
const unsupportedTopology = [];
|
|
52
|
-
let unalignable = false;
|
|
53
79
|
node.descendants((child, relativePosition) => {
|
|
54
80
|
if (child.isText) return false;
|
|
55
81
|
if (!child.isInline || !child.isAtom) return true;
|
|
@@ -58,18 +84,14 @@ const atomBlockOf = ({ node, from }) => {
|
|
|
58
84
|
offsets: clean.offsets,
|
|
59
85
|
position
|
|
60
86
|
});
|
|
61
|
-
if (offset === null) {
|
|
62
|
-
unalignable = true;
|
|
63
|
-
return false;
|
|
64
|
-
}
|
|
65
87
|
if (!isSupportedAtom(child)) {
|
|
66
88
|
if (child.type.name === "renderedPageBreak") return false;
|
|
67
|
-
unsupportedTopology.push(`${offset}:${child.type.name}:${canonicalJson(child
|
|
89
|
+
unsupportedTopology.push(`${offset}:${child.type.name}:${canonicalJson(documentFactAttrs(child))}`);
|
|
68
90
|
return false;
|
|
69
91
|
}
|
|
70
92
|
const prepared = prepareTargetInlineAtom(child);
|
|
71
93
|
if (!prepared) {
|
|
72
|
-
|
|
94
|
+
unsupportedTopology.push(`${offset}:${child.type.name}:${canonicalJson(documentFactAttrs(child))}`);
|
|
73
95
|
return false;
|
|
74
96
|
}
|
|
75
97
|
supported.push({
|
|
@@ -80,7 +102,7 @@ const atomBlockOf = ({ node, from }) => {
|
|
|
80
102
|
});
|
|
81
103
|
return false;
|
|
82
104
|
});
|
|
83
|
-
return
|
|
105
|
+
return {
|
|
84
106
|
node,
|
|
85
107
|
from,
|
|
86
108
|
cleanText: clean.text,
|
|
@@ -108,15 +130,7 @@ const targetBlockIdLookup = (snapshot) => {
|
|
|
108
130
|
return owner?.id;
|
|
109
131
|
};
|
|
110
132
|
};
|
|
111
|
-
const atomBlocksOf = (doc) =>
|
|
112
|
-
const blocks = [];
|
|
113
|
-
for (const block of textBlocksOf(doc)) {
|
|
114
|
-
const atoms = atomBlockOf(block);
|
|
115
|
-
if (!atoms) return null;
|
|
116
|
-
blocks.push(atoms);
|
|
117
|
-
}
|
|
118
|
-
return blocks;
|
|
119
|
-
};
|
|
133
|
+
const atomBlocksOf = (doc) => textBlocksOf(doc).map(atomBlockOf);
|
|
120
134
|
const sameBlockTopology = (left, right) => left.node.type === right.node.type && left.cleanText === right.cleanText && canonicalJson(left.unsupportedTopology) === canonicalJson(right.unsupportedTopology);
|
|
121
135
|
const matchingAtomGroup = ({ live, target, liveStart, targetStart }) => {
|
|
122
136
|
if (live.length === target.length && live.every((atom, index) => atom.key === target[index]?.key)) return live.map((_, index) => [liveStart + index, targetStart + index]);
|
|
@@ -260,7 +274,7 @@ const matchInlineAtoms = ({ state, targetSnapshot, revisionStamp, originalRevisi
|
|
|
260
274
|
let sourceBlocks;
|
|
261
275
|
const liveBlocks = atomBlocksOf(reviewed.state.doc);
|
|
262
276
|
const targetBlocks = atomBlocksOf(targetDocument);
|
|
263
|
-
if (
|
|
277
|
+
if (liveBlocks.length !== targetBlocks.length) return { status: "unalignable" };
|
|
264
278
|
const actions = [];
|
|
265
279
|
for (const [index, live] of liveBlocks.entries()) {
|
|
266
280
|
const target = targetBlocks[index];
|
|
@@ -366,7 +380,7 @@ const sameInlineAtoms = (leftDocument, rightDocument) => {
|
|
|
366
380
|
if (!hasSupportedAtom(leftDocument) && !hasSupportedAtom(rightDocument)) return true;
|
|
367
381
|
const leftBlocks = atomBlocksOf(leftDocument);
|
|
368
382
|
const rightBlocks = atomBlocksOf(rightDocument);
|
|
369
|
-
if (
|
|
383
|
+
if (leftBlocks.length !== rightBlocks.length) return false;
|
|
370
384
|
return leftBlocks.every((left, index) => {
|
|
371
385
|
const right = rightBlocks[index];
|
|
372
386
|
if (left.supported.length === 0 && right?.supported.length === 0) return true;
|
|
@@ -213,6 +213,12 @@ const importReferencedStyleDefinitions = ({ sourceStyles, destinationStyles, sou
|
|
|
213
213
|
styleIdMap: /* @__PURE__ */ new Map(),
|
|
214
214
|
importedStyleIds: []
|
|
215
215
|
};
|
|
216
|
+
if (requested.length === 0 && !sourceStyles && !destinationStyles) return {
|
|
217
|
+
status: "unchanged",
|
|
218
|
+
styles: destinationStyles,
|
|
219
|
+
styleIdMap: /* @__PURE__ */ new Map(),
|
|
220
|
+
importedStyleIds: []
|
|
221
|
+
};
|
|
216
222
|
if (!sourceStyles) return {
|
|
217
223
|
status: "unalignable",
|
|
218
224
|
detail: "the target has no style definitions"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { formatDate } from "../docx/fieldParser.js";
|
|
2
2
|
import { ContentControlBoundError, ContentControlLockedError, ContentControlTypeError } from "./errors.js";
|
|
3
|
+
import { sanitizeXmlCharacters } from "@stll/docx-core";
|
|
3
4
|
//#region src/content-controls/mutateContentControls.ts
|
|
4
5
|
/**
|
|
5
6
|
* Pure (immutable) write helpers for block-level content controls.
|
|
@@ -220,7 +221,8 @@ function controlMatchesFilter(control, filter) {
|
|
|
220
221
|
if (filter.sdtType !== void 0 && control.properties.sdtType !== filter.sdtType) return false;
|
|
221
222
|
return true;
|
|
222
223
|
}
|
|
223
|
-
function makeParagraphFromText(
|
|
224
|
+
function makeParagraphFromText(rawText) {
|
|
225
|
+
const text = sanitizeXmlCharacters(rawText);
|
|
224
226
|
return {
|
|
225
227
|
type: "paragraph",
|
|
226
228
|
content: text.length === 0 ? [] : [{
|
|
@@ -300,7 +302,7 @@ function setContentControlValue(doc, filter, input, options = {}) {
|
|
|
300
302
|
...control,
|
|
301
303
|
properties: {
|
|
302
304
|
...control.properties,
|
|
303
|
-
dropdownLastValue: input.value,
|
|
305
|
+
dropdownLastValue: sanitizeXmlCharacters(input.value),
|
|
304
306
|
showingPlaceholder: false,
|
|
305
307
|
...strippedRawPropertiesXml !== void 0 ? { rawPropertiesXml: strippedRawPropertiesXml } : {}
|
|
306
308
|
},
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { bytesToDataUrl } from "../../utils/base64.js";
|
|
2
|
+
import { anchorTargetAttrs } from "../../utils/urlSecurity.js";
|
|
1
3
|
import { STROKE_DASH_FACTORS, walkRegions } from "../primitives.js";
|
|
2
4
|
import { panic } from "better-result";
|
|
3
5
|
//#region src/display-list/dom/renderDisplayListToDom.ts
|
|
@@ -42,7 +44,6 @@ const PAGE_CLASS_NAME = "layout-page";
|
|
|
42
44
|
*/
|
|
43
45
|
const PAGE_ELEMENT_ID_PREFIX = "page-";
|
|
44
46
|
const DEGREES_PER_RADIAN = 180 / Math.PI;
|
|
45
|
-
const BASE64_CHUNK_SIZE = 32768;
|
|
46
47
|
const IMAGE_MIME_TYPES = {
|
|
47
48
|
png: "image/png",
|
|
48
49
|
jpeg: "image/jpeg"
|
|
@@ -98,17 +99,11 @@ const resolveImage = (ref, images) => {
|
|
|
98
99
|
if (source === void 0) panic(`renderDisplayListToDom: image ref ${ref} is out of range (${images.length} images)`);
|
|
99
100
|
return source;
|
|
100
101
|
};
|
|
101
|
-
const toBase64 = (bytes) => {
|
|
102
|
-
let binary = "";
|
|
103
|
-
for (let offset = 0; offset < bytes.length; offset += BASE64_CHUNK_SIZE) binary += String.fromCharCode(...bytes.subarray(offset, offset + BASE64_CHUNK_SIZE));
|
|
104
|
-
return btoa(binary);
|
|
105
|
-
};
|
|
106
102
|
/** A `Blob` part cannot be backed by shared memory, so prove it is not. */
|
|
107
103
|
const isBlobPart = (bytes) => bytes.buffer instanceof ArrayBuffer;
|
|
108
104
|
const binarySrc = (bytes, mimeType) => {
|
|
109
105
|
if (isBlobPart(bytes) && typeof Blob === "function" && typeof URL !== "undefined" && typeof URL.createObjectURL === "function") return URL.createObjectURL(new Blob([bytes], { type: mimeType }));
|
|
110
|
-
|
|
111
|
-
panic("renderDisplayListToDom: no Blob or btoa to build a binary source from");
|
|
106
|
+
return bytesToDataUrl(bytes, mimeType);
|
|
112
107
|
};
|
|
113
108
|
const fontFaceRule = (face, embedded, src) => `@font-face { font-family: ${quoteFontFamily(embedded.id)}; src: url("${src}"); font-weight: ${face.weight}; font-style: ${face.italic ? "italic" : "normal"}; }`;
|
|
114
109
|
/**
|
|
@@ -489,6 +484,11 @@ const paintLink = ({ rect, target, tooltip }, context) => {
|
|
|
489
484
|
element.style.width = px(rect.widthPx);
|
|
490
485
|
element.style.height = px(rect.heightPx);
|
|
491
486
|
element.href = linkHref(target);
|
|
487
|
+
if (target.kind !== "page") {
|
|
488
|
+
const anchor = anchorTargetAttrs(void 0);
|
|
489
|
+
element.target = anchor.target;
|
|
490
|
+
element.rel = anchor.rel;
|
|
491
|
+
}
|
|
492
492
|
if (tooltip !== void 0) element.title = tooltip;
|
|
493
493
|
context.parent.append(element);
|
|
494
494
|
};
|