@stll/folio-core 0.54.2 → 0.56.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai-edits/apply.js +185 -33
- package/dist/ai-edits/headless.js +3 -2
- package/dist/ai-edits/types.d.ts +7 -1
- package/dist/compare/compare.js +1 -0
- package/dist/compare/content-types.d.ts +3 -15
- package/dist/compare/reproducible-package.d.ts +0 -17
- package/dist/compare/reproducible-package.js +12 -18
- package/dist/controller/canonicalClipboard.d.ts +23 -0
- package/dist/controller/canonicalClipboard.js +476 -0
- package/dist/controller/canonicalClipboardResources.d.ts +21 -0
- package/dist/controller/canonicalClipboardResources.js +382 -0
- package/dist/controller/canonicalComposition.d.ts +53 -0
- package/dist/controller/canonicalComposition.js +296 -0
- package/dist/controller/canonicalInlineProjection.d.ts +113 -0
- package/dist/controller/canonicalInlineProjection.js +393 -0
- package/dist/controller/canonicalInput.d.ts +54 -0
- package/dist/controller/canonicalInput.js +377 -0
- package/dist/controller/canonicalInputTimer.d.ts +7 -0
- package/dist/controller/canonicalInputTimer.js +11 -0
- package/dist/controller/canonicalOperations.d.ts +22 -0
- package/dist/controller/canonicalOperations.js +85 -0
- package/dist/controller/canonicalPublicOperations.d.ts +48 -0
- package/dist/controller/canonicalPublicOperations.js +556 -0
- package/dist/controller/canonicalReview.d.ts +12 -0
- package/dist/controller/canonicalReview.js +19 -0
- package/dist/controller/canonicalSession.d.ts +167 -0
- package/dist/controller/canonicalSession.js +1186 -0
- package/dist/controller/canonicalStoryEditor.d.ts +36 -0
- package/dist/controller/canonicalStoryEditor.js +87 -0
- package/dist/controller/canonicalStructure.d.ts +16 -0
- package/dist/controller/canonicalStructure.js +322 -0
- package/dist/controller/canonicalTocSelection.d.ts +11 -0
- package/dist/controller/canonicalTocSelection.js +43 -0
- package/dist/controller/folioEditor.d.ts +3 -10
- package/dist/controller/folioEditor.js +14 -4
- package/dist/controller/headerFooterEditorManager.d.ts +5 -0
- package/dist/controller/headerFooterEditorManager.js +72 -3
- package/dist/controller/hiddenEditorApi.d.ts +45 -0
- package/dist/controller/hiddenEditorApi.js +29 -8
- package/dist/controller/hiddenEditorManager.d.ts +13 -2
- package/dist/controller/hiddenEditorManager.js +639 -31
- package/dist/controller/layoutPipeline.d.ts +1 -1
- package/dist/controller/layoutPipeline.js +2 -0
- package/dist/controller/noteEditorManager.d.ts +5 -0
- package/dist/controller/noteEditorManager.js +114 -15
- package/dist/document-operations.d.ts +8 -1
- package/dist/document-operations.js +6 -4
- package/dist/docx/attributeRemainder.js +1 -0
- package/dist/docx/blockPlainText.d.ts +1 -1
- package/dist/docx/blockPlainText.js +11 -3
- package/dist/docx/canonicalResourceSave.d.ts +16 -0
- package/dist/docx/canonicalResourceSave.js +27 -0
- package/dist/docx/canonicalSave.d.ts +29 -0
- package/dist/docx/canonicalSave.js +101 -0
- package/dist/docx/canonicalSessionInput.d.ts +11 -0
- package/dist/docx/canonicalSessionInput.js +27 -0
- package/dist/docx/canonicalStoryRepack.d.ts +10 -0
- package/dist/docx/canonicalStoryRepack.js +74 -0
- package/dist/docx/contentTypeRegistry.d.ts +8 -0
- package/dist/docx/contentTypeRegistry.js +64 -0
- package/dist/docx/documentParser.d.ts +1 -13
- package/dist/docx/documentParser.js +1 -47
- package/dist/docx/ensureParaIds.d.ts +7 -1
- package/dist/docx/ensureParaIds.js +173 -215
- package/dist/docx/foldedListNumberFields.d.ts +85 -0
- package/dist/docx/foldedListNumberFields.js +267 -0
- package/dist/docx/footnoteParser.d.ts +1 -11
- package/dist/docx/footnoteParser.js +1 -16
- package/dist/docx/headerFooterParser.d.ts +1 -9
- package/dist/docx/headerFooterParser.js +1 -12
- package/dist/docx/headerFooterVerbatim.d.ts +39 -1
- package/dist/docx/headerFooterVerbatim.js +173 -2
- package/dist/docx/imageParser.d.ts +13 -1
- package/dist/docx/imageParser.js +20 -11
- package/dist/docx/metadataPrivacy.js +6 -1
- package/dist/docx/noteIds.d.ts +5 -0
- package/dist/docx/noteIds.js +6 -2
- package/dist/docx/noteReferenceMark.d.ts +3 -1
- package/dist/docx/noteReferenceMark.js +15 -14
- package/dist/docx/numberingParser.d.ts +3 -1
- package/dist/docx/numberingParser.js +17 -3
- package/dist/docx/packageParts.d.ts +3 -1
- package/dist/docx/packageParts.js +74 -19
- package/dist/docx/paragraphMarkPropertyPresence.d.ts +9 -0
- package/dist/docx/paragraphMarkPropertyPresence.js +21 -0
- package/dist/docx/paragraphParser.js +101 -53
- package/dist/docx/paragraphPropertySource.d.ts +15 -1
- package/dist/docx/paragraphPropertySource.js +77 -22
- package/dist/docx/parser.js +3 -1
- package/dist/docx/removeHeaderFooterParts.js +17 -6
- package/dist/docx/reviewHistoryNamespace.d.ts +4 -0
- package/dist/docx/reviewHistoryNamespace.js +4 -0
- package/dist/docx/reviewResolutionProvenance.d.ts +25 -0
- package/dist/docx/reviewResolutionProvenance.js +153 -0
- package/dist/docx/rezip.d.ts +54 -6
- package/dist/docx/rezip.js +835 -257
- package/dist/docx/runConsolidator.d.ts +2 -58
- package/dist/docx/runConsolidator.js +3 -175
- package/dist/docx/runParser.d.ts +2 -1
- package/dist/docx/runParser.js +156 -116
- package/dist/docx/saveDiagnostics.d.ts +22 -0
- package/dist/docx/saveDiagnostics.js +0 -0
- package/dist/docx/selectiveSave.d.ts +3 -1
- package/dist/docx/selectiveSave.js +36 -4
- package/dist/docx/selectiveXmlPatch.d.ts +16 -8
- package/dist/docx/selectiveXmlPatch.js +81 -7
- package/dist/docx/serializer/documentSerializer.d.ts +9 -2
- package/dist/docx/serializer/documentSerializer.js +29 -10
- package/dist/docx/serializer/headerFooterSerializer.d.ts +5 -1
- package/dist/docx/serializer/headerFooterSerializer.js +19 -11
- package/dist/docx/serializer/noteSerializer.d.ts +2 -2
- package/dist/docx/serializer/noteSerializer.js +24 -8
- package/dist/docx/serializer/paragraphSerializer.js +41 -4
- package/dist/docx/serializer/partNamespaces.js +2 -1
- package/dist/docx/serializer/runSerializer.js +3 -1
- package/dist/docx/server/applyDocxXmlPatchProposal.js +14 -9
- package/dist/docx/settingsHeaderFooterUpdate.d.ts +5 -0
- package/dist/docx/settingsHeaderFooterUpdate.js +90 -0
- package/dist/docx/settingsParser.d.ts +1 -2
- package/dist/docx/settingsParser.js +5 -6
- package/dist/docx/storyBlockReplay.d.ts +31 -0
- package/dist/docx/storyBlockReplay.js +471 -0
- package/dist/docx/storyPlainText.d.ts +20 -0
- package/dist/docx/storyPlainText.js +23 -0
- package/dist/docx/streamingXmlParser.d.ts +22 -1
- package/dist/docx/streamingXmlParser.js +49 -3
- package/dist/docx/structuralXmlPatch.js +18 -23
- package/dist/docx/styleParser.d.ts +5 -1
- package/dist/docx/styleParser.js +1 -1
- package/dist/docx/tableParser.d.ts +1 -8
- package/dist/docx/tableParser.js +1 -28
- package/dist/docx/textBoxParser.d.ts +1 -5
- package/dist/docx/textBoxParser.js +1 -20
- package/dist/docx/unzip.js +6 -1
- package/dist/docx/verbatimCapture.d.ts +3 -1
- package/dist/docx/verbatimCapture.js +49 -6
- package/dist/i18n/messages/ar.gen.d.ts +5 -0
- package/dist/i18n/messages/ar.gen.js +656 -0
- package/dist/i18n/messages/cs.gen.d.ts +5 -0
- package/dist/i18n/messages/cs.gen.js +656 -0
- package/dist/i18n/messages/de.gen.d.ts +5 -0
- package/dist/i18n/messages/de.gen.js +656 -0
- package/dist/i18n/messages/en.gen.d.ts +5 -0
- package/dist/i18n/messages/en.gen.js +656 -0
- package/dist/i18n/messages/es.gen.d.ts +5 -0
- package/dist/i18n/messages/es.gen.js +656 -0
- package/dist/i18n/messages/et.gen.d.ts +5 -0
- package/dist/i18n/messages/et.gen.js +656 -0
- package/dist/i18n/messages/fr.gen.d.ts +5 -0
- package/dist/i18n/messages/fr.gen.js +656 -0
- package/dist/i18n/messages/he.gen.d.ts +5 -0
- package/dist/i18n/messages/he.gen.js +656 -0
- package/dist/i18n/messages/hi.gen.d.ts +5 -0
- package/dist/i18n/messages/hi.gen.js +656 -0
- package/dist/i18n/messages/hu.gen.d.ts +5 -0
- package/dist/i18n/messages/hu.gen.js +656 -0
- package/dist/i18n/messages/locales.d.ts +5 -0
- package/dist/i18n/messages/locales.js +22 -0
- package/dist/i18n/messages/lt.gen.d.ts +5 -0
- package/dist/i18n/messages/lt.gen.js +656 -0
- package/dist/i18n/messages/lv.gen.d.ts +5 -0
- package/dist/i18n/messages/lv.gen.js +656 -0
- package/dist/i18n/messages/pl.gen.d.ts +5 -0
- package/dist/i18n/messages/pl.gen.js +656 -0
- package/dist/i18n/messages/pt-BR.gen.d.ts +5 -0
- package/dist/i18n/messages/pt-BR.gen.js +656 -0
- package/dist/i18n/messages/sk.gen.d.ts +5 -0
- package/dist/i18n/messages/sk.gen.js +656 -0
- package/dist/i18n/messages/tr.gen.d.ts +5 -0
- package/dist/i18n/messages/tr.gen.js +656 -0
- package/dist/i18n/messages/zh-CN.gen.d.ts +5 -0
- package/dist/i18n/messages/zh-CN.gen.js +656 -0
- package/dist/i18n/messages.d.ts +2 -3
- package/dist/i18n/messages.js +1 -19
- package/dist/internal/acceptedBlockProjection.d.ts +12 -0
- package/dist/internal/acceptedBlockProjection.js +45 -0
- package/dist/internal/noteMarkerAttrs.d.ts +8 -0
- package/dist/internal/noteMarkerAttrs.js +16 -0
- package/dist/internal/pageBreakRunSourceDescendantIndex.js +1 -0
- package/dist/internal/prosemirrorAttrBoundary.d.ts +21 -0
- package/dist/internal/prosemirrorAttrBoundary.js +50 -0
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/footnoteLayout.js +3 -3
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/headerFooterLayout.js +1 -0
- package/dist/layout-bridge/convert/noteReferences.d.ts +1 -3
- package/dist/layout-bridge/convert/noteReferences.js +1 -6
- package/dist/layout-bridge/convert/paragraphRuns.js +2 -4
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +2 -2
- package/dist/layout-bridge/convert/toFlowBlocks.js +2 -2
- package/dist/managers/DocumentLoaderManager.d.ts +1 -0
- package/dist/managers/DocumentLoaderManager.js +9 -1
- package/dist/markdown/escape.d.ts +3 -1
- package/dist/markdown/escape.js +9 -2
- package/dist/markdown/renderBlock.js +20 -121
- package/dist/markdown/renderParagraph.js +13 -15
- package/dist/markdown/renderRuns.d.ts +7 -1
- package/dist/markdown/renderRuns.js +35 -15
- package/dist/markdown/renderTable.js +2 -0
- package/dist/markdown/types.d.ts +3 -9
- package/dist/prosemirror/attrs/index.d.ts +2 -12
- package/dist/prosemirror/attrs/index.js +22 -48
- package/dist/prosemirror/bookmarkBoundaryAttrs.d.ts +2 -1
- package/dist/prosemirror/canonicalCommands.d.ts +121 -0
- package/dist/prosemirror/canonicalCommands.js +35 -0
- package/dist/prosemirror/canonicalSelectionRange.d.ts +9 -0
- package/dist/prosemirror/canonicalSelectionRange.js +15 -0
- package/dist/prosemirror/clipboardIntent.d.ts +7 -0
- package/dist/prosemirror/clipboardIntent.js +9 -0
- package/dist/prosemirror/commands/pageBreak.js +15 -1
- package/dist/prosemirror/commands/pastePlainText.js +2 -1
- package/dist/prosemirror/commentReferenceAttrs.d.ts +2 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +91 -19
- package/dist/prosemirror/conversion/hyphenTextCarriers.d.ts +8 -0
- package/dist/prosemirror/conversion/hyphenTextCarriers.js +8 -0
- package/dist/prosemirror/conversion/listRenderingDefinition.d.ts +6 -0
- package/dist/prosemirror/conversion/listRenderingDefinition.js +97 -0
- package/dist/prosemirror/conversion/toProseDoc.d.ts +11 -4
- package/dist/prosemirror/conversion/toProseDoc.js +55 -14
- package/dist/prosemirror/executeEditorCommand.d.ts +11 -0
- package/dist/prosemirror/executeEditorCommand.js +26 -0
- package/dist/prosemirror/extensions/StarterKit.js +2 -0
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +88 -48
- package/dist/prosemirror/extensions/features/ListExtension.js +18 -5
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +5 -2
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +13 -1
- package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +56 -28
- package/dist/prosemirror/extensions/marks/TextColorExtension.js +3 -2
- package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +2 -0
- package/dist/prosemirror/extensions/marks/markUtils.js +72 -8
- package/dist/prosemirror/extensions/nodes/NoteMarkerExtension.d.ts +6 -0
- package/dist/prosemirror/extensions/nodes/NoteMarkerExtension.js +36 -0
- package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.js +4 -2
- package/dist/prosemirror/insertOperations.js +2 -1
- package/dist/prosemirror/listMarker.d.ts +1 -0
- package/dist/prosemirror/listMarker.js +16 -7
- package/dist/prosemirror/listNumbering.js +26 -5
- package/dist/prosemirror/listRenderingAttrs.d.ts +1 -0
- package/dist/prosemirror/listRenderingAttrs.js +3 -0
- package/dist/prosemirror/markupViewNotes.js +3 -2
- package/dist/prosemirror/moveRangeBoundaryAttrs.d.ts +2 -1
- package/dist/prosemirror/noteReferenceReview.js +5 -3
- package/dist/prosemirror/paragraphPropertyCarry.d.ts +7 -1
- package/dist/prosemirror/paragraphPropertyCarry.js +8 -3
- package/dist/prosemirror/plugins/suggestionMode.js +57 -7
- package/dist/prosemirror/rangeAnchorAttrs.d.ts +2 -1
- package/dist/prosemirror/runFormattingFromMarks.d.ts +4 -1
- package/dist/prosemirror/runFormattingFromMarks.js +15 -1
- package/dist/prosemirror/runFormattingInlineCarriers.d.ts +2 -1
- package/dist/prosemirror/runFormattingInlineCarriers.js +4 -1
- package/dist/prosemirror/schema/marks.d.ts +2 -0
- package/dist/prosemirror/schema/nodes.d.ts +10 -2
- package/dist/prosemirror/textBoxAnchorAttrs.d.ts +2 -1
- package/dist/prosemirror/textInput.js +5 -1
- package/dist/prosemirror/trackedRevisionPath.js +2 -1
- package/dist/prosemirror/trackedRunInlineAtoms.d.ts +1 -0
- package/dist/prosemirror/trackedRunInlineAtoms.js +1 -0
- package/dist/prosemirror/validation.js +4 -0
- package/dist/types/canonicalCapabilities.d.ts +215 -0
- package/dist/types/canonicalCapabilities.js +212 -0
- package/dist/types/canonicalSave.d.ts +11 -0
- package/dist/types/canonicalSave.js +0 -0
- package/dist/types/content.d.ts +2 -2
- package/dist/types/docxSerialization.d.ts +14 -0
- package/dist/types/docxSerialization.js +7 -0
- package/dist/utils/createDocument.js +2 -2
- package/package.json +16 -4
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
import { readNoteMarkerAttrs } from "../internal/noteMarkerAttrs.js";
|
|
2
|
+
import { readFootnoteRefMarkAttrs, readPreservedXmlAttrs } from "../prosemirror/attrs/index.js";
|
|
3
|
+
import { bookmarkMarkerFromAttrs, readBookmarkBoundaryAttrs } from "../prosemirror/bookmarkBoundaryAttrs.js";
|
|
4
|
+
import { HYPHEN_TEXT_CARRIERS } from "../prosemirror/conversion/hyphenTextCarriers.js";
|
|
5
|
+
import { readMoveRangeBoundaryAttrs } from "../prosemirror/moveRangeBoundaryAttrs.js";
|
|
6
|
+
import { readRangeAnchorAttrs } from "../prosemirror/rangeAnchorAttrs.js";
|
|
7
|
+
import { PRESERVED_XML_LEVELS } from "../prosemirror/schema/nodes.js";
|
|
8
|
+
import { Result, TaggedError, panic } from "better-result";
|
|
9
|
+
import { hasIllegalXmlCharacters } from "@stll/docx-core";
|
|
10
|
+
import { inlineLeafSpans, paragraphLogicalText } from "@stll/docx-core/ops";
|
|
11
|
+
//#region src/controller/canonicalInlineProjection.ts
|
|
12
|
+
const CANONICAL_SOURCE_INLINE_POLICIES = {
|
|
13
|
+
run: "container",
|
|
14
|
+
hyperlink: "container",
|
|
15
|
+
insertion: "container",
|
|
16
|
+
deletion: "container",
|
|
17
|
+
moveFrom: "container",
|
|
18
|
+
moveTo: "container",
|
|
19
|
+
inlineWrapper: "container",
|
|
20
|
+
inlineSdt: "control",
|
|
21
|
+
simpleField: "leaf",
|
|
22
|
+
complexField: "leaf",
|
|
23
|
+
mathEquation: "leaf",
|
|
24
|
+
preservedInline: "leaf",
|
|
25
|
+
bookmarkStart: "leaf",
|
|
26
|
+
bookmarkEnd: "leaf",
|
|
27
|
+
commentRangeStart: "leaf",
|
|
28
|
+
commentRangeEnd: "leaf",
|
|
29
|
+
commentReference: "leaf",
|
|
30
|
+
moveFromRangeStart: "leaf",
|
|
31
|
+
moveFromRangeEnd: "leaf",
|
|
32
|
+
moveToRangeStart: "leaf",
|
|
33
|
+
moveToRangeEnd: "leaf",
|
|
34
|
+
text: "text",
|
|
35
|
+
tab: "leaf",
|
|
36
|
+
break: "leaf",
|
|
37
|
+
symbol: "leaf",
|
|
38
|
+
footnoteRef: "leaf",
|
|
39
|
+
endnoteRef: "leaf",
|
|
40
|
+
noteMarker: "leaf",
|
|
41
|
+
fieldChar: "rawField",
|
|
42
|
+
instrText: "rawField",
|
|
43
|
+
softHyphen: "leaf",
|
|
44
|
+
noBreakHyphen: "leaf",
|
|
45
|
+
renderedPageBreak: "layout",
|
|
46
|
+
preservedXml: "leaf",
|
|
47
|
+
drawing: "leaf",
|
|
48
|
+
shape: "leaf"
|
|
49
|
+
};
|
|
50
|
+
const CANONICAL_NATIVE_INLINE_POLICIES = {
|
|
51
|
+
text: "text",
|
|
52
|
+
bookmarkBoundary: "markers",
|
|
53
|
+
moveRangeBoundary: "markers",
|
|
54
|
+
rangeAnchor: "markers",
|
|
55
|
+
noteMarker: "noteMarker",
|
|
56
|
+
preservedXml: "capture",
|
|
57
|
+
field: "unit",
|
|
58
|
+
structuredField: "unit",
|
|
59
|
+
hardBreak: "unit",
|
|
60
|
+
image: "unit",
|
|
61
|
+
math: "unit",
|
|
62
|
+
pageBreakRun: "unit",
|
|
63
|
+
shape: "unit",
|
|
64
|
+
symbol: "unit",
|
|
65
|
+
tab: "unit",
|
|
66
|
+
textBoxAnchor: "unit",
|
|
67
|
+
commentReference: "unit",
|
|
68
|
+
renderedPageBreak: "refused",
|
|
69
|
+
sdt: "refused"
|
|
70
|
+
};
|
|
71
|
+
const nativePolicies = new Map(Object.entries(CANONICAL_NATIVE_INLINE_POLICIES));
|
|
72
|
+
var InlineProjectionError = class extends TaggedError("InlineProjectionError") {};
|
|
73
|
+
const refuse = (message) => Result.err(new InlineProjectionError({ message }));
|
|
74
|
+
/** Every source variant makes a decision before conversion can discard its positions. */
|
|
75
|
+
const canonicalInlineSourceIssue = (items, context = "paragraph") => {
|
|
76
|
+
for (const item of items) switch (CANONICAL_SOURCE_INLINE_POLICIES[item.type]) {
|
|
77
|
+
case "control":
|
|
78
|
+
if (context === "fieldPayload" && item.type === "inlineSdt") {
|
|
79
|
+
const issue = canonicalInlineSourceIssue(item.content, context);
|
|
80
|
+
if (issue !== null) return issue;
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
return "Canonical editing cannot preserve inline content-control boundary positions.";
|
|
84
|
+
case "rawField":
|
|
85
|
+
if (context === "fieldPayload") break;
|
|
86
|
+
return "Canonical editing cannot preserve unstructured field instructions; a structured field is required.";
|
|
87
|
+
case "layout": return "Canonical editing cannot preserve cached rendered page-break positions.";
|
|
88
|
+
case "text":
|
|
89
|
+
if (item.type === "text" && (hasIllegalXmlCharacters(item.text) || /[\t\r\n]/u.test(item.text))) return "Canonical text requires valid XML characters and explicit tab or break elements.";
|
|
90
|
+
break;
|
|
91
|
+
case "container": {
|
|
92
|
+
if ((item.type === "insertion" || item.type === "deletion") && item.resolutionJoins !== void 0 && item.content.some((child) => child.type === "hyperlink")) return "Canonical editing cannot preserve hyperlink wrapper review provenance.";
|
|
93
|
+
const children = sourceContainerChildren(item);
|
|
94
|
+
const issue = canonicalInlineSourceIssue(children, context);
|
|
95
|
+
if (issue !== null) return issue;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
case "leaf": {
|
|
99
|
+
let children = [];
|
|
100
|
+
if (item.type === "simpleField") children = item.content;
|
|
101
|
+
if (item.type === "complexField") children = [...item.fieldCode, ...item.fieldResult];
|
|
102
|
+
const issue = canonicalInlineSourceIssue(children, "fieldPayload");
|
|
103
|
+
if (issue !== null) return issue;
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
default:
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
};
|
|
110
|
+
const sourceContainerChildren = (item) => {
|
|
111
|
+
switch (item.type) {
|
|
112
|
+
case "hyperlink": return item.children;
|
|
113
|
+
case "run":
|
|
114
|
+
case "insertion":
|
|
115
|
+
case "deletion":
|
|
116
|
+
case "moveFrom":
|
|
117
|
+
case "moveTo":
|
|
118
|
+
case "inlineWrapper": return item.content;
|
|
119
|
+
default: return panic(`Source policy incorrectly classified ${item.type} as a container.`);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
/** Native positions and deletion geometry read the same inline-cell classification. */
|
|
123
|
+
const canonicalNativeCells = (paragraph) => {
|
|
124
|
+
const cells = [];
|
|
125
|
+
let issue;
|
|
126
|
+
paragraph.forEach((node, from) => {
|
|
127
|
+
if (issue !== void 0) return;
|
|
128
|
+
const to = from + node.nodeSize;
|
|
129
|
+
switch (nativePolicies.get(node.type.name)) {
|
|
130
|
+
case "text": {
|
|
131
|
+
const reference = node.marks.find(({ type }) => type.name === "footnoteRef");
|
|
132
|
+
if (!reference) {
|
|
133
|
+
cells.push({
|
|
134
|
+
type: "text",
|
|
135
|
+
text: node.text ?? "",
|
|
136
|
+
from,
|
|
137
|
+
to,
|
|
138
|
+
node
|
|
139
|
+
});
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const attrs = readFootnoteRefMarkAttrs(reference);
|
|
143
|
+
if (!attrs.ok) {
|
|
144
|
+
issue = "Canonical editing requires valid note-reference mark attributes.";
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const label = String(attrs.value.id);
|
|
148
|
+
const text = node.text ?? "";
|
|
149
|
+
if (label.length === 0 || text.length % label.length !== 0 || text !== label.repeat(text.length / label.length)) {
|
|
150
|
+
issue = "Canonical editing cannot map the rendered note-reference labels.";
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
for (let offset = 0; offset < text.length; offset += label.length) cells.push({
|
|
154
|
+
type: "markedUnit",
|
|
155
|
+
sourceType: attrs.value.noteType === "endnote" ? "endnoteRef" : "footnoteRef",
|
|
156
|
+
label,
|
|
157
|
+
from: from + offset,
|
|
158
|
+
to: from + offset + label.length,
|
|
159
|
+
node
|
|
160
|
+
});
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
case "unit":
|
|
164
|
+
cells.push({
|
|
165
|
+
type: "unit",
|
|
166
|
+
from,
|
|
167
|
+
to,
|
|
168
|
+
node
|
|
169
|
+
});
|
|
170
|
+
return;
|
|
171
|
+
case "markers":
|
|
172
|
+
if (node.type.name === "bookmarkBoundary") {
|
|
173
|
+
const attrs = readBookmarkBoundaryAttrs(node);
|
|
174
|
+
if (!attrs.ok) {
|
|
175
|
+
issue = "Canonical editing requires valid bookmark boundary attributes.";
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
cells.push({
|
|
179
|
+
type: "zeroWidth",
|
|
180
|
+
sources: [bookmarkMarkerFromAttrs(attrs.value)],
|
|
181
|
+
from,
|
|
182
|
+
to,
|
|
183
|
+
node
|
|
184
|
+
});
|
|
185
|
+
} else if (node.type.name === "moveRangeBoundary") {
|
|
186
|
+
const attrs = readMoveRangeBoundaryAttrs(node);
|
|
187
|
+
if (!attrs.ok) {
|
|
188
|
+
issue = "Canonical editing requires valid move-range boundary attributes.";
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
cells.push({
|
|
192
|
+
type: "zeroWidth",
|
|
193
|
+
sources: [attrs.value],
|
|
194
|
+
from,
|
|
195
|
+
to,
|
|
196
|
+
node
|
|
197
|
+
});
|
|
198
|
+
} else {
|
|
199
|
+
const attrs = readRangeAnchorAttrs(node);
|
|
200
|
+
if (!attrs.ok) {
|
|
201
|
+
issue = "Canonical editing requires a valid collapsed range anchor.";
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
cells.push({
|
|
205
|
+
type: "zeroWidth",
|
|
206
|
+
sources: [attrs.value.start, attrs.value.end],
|
|
207
|
+
from,
|
|
208
|
+
to,
|
|
209
|
+
node
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
return;
|
|
213
|
+
case "noteMarker": {
|
|
214
|
+
const attrs = readNoteMarkerAttrs(node);
|
|
215
|
+
if (!attrs.ok) {
|
|
216
|
+
issue = "Canonical editing requires a valid automatic note marker.";
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
cells.push({
|
|
220
|
+
type: "zeroWidth",
|
|
221
|
+
sources: [{
|
|
222
|
+
type: "noteMarker",
|
|
223
|
+
kind: attrs.value.kind
|
|
224
|
+
}],
|
|
225
|
+
from,
|
|
226
|
+
to,
|
|
227
|
+
node
|
|
228
|
+
});
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
case "capture": {
|
|
232
|
+
const attrs = readPreservedXmlAttrs(node);
|
|
233
|
+
if (!attrs.ok) {
|
|
234
|
+
issue = "Canonical editing requires valid preserved inline markup.";
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
if (attrs.value.level === PRESERVED_XML_LEVELS.inline && attrs.value.text === "") cells.push({
|
|
238
|
+
type: "zeroWidth",
|
|
239
|
+
sources: [{
|
|
240
|
+
type: "preservedInline",
|
|
241
|
+
xml: attrs.value.xml,
|
|
242
|
+
text: ""
|
|
243
|
+
}],
|
|
244
|
+
from,
|
|
245
|
+
to,
|
|
246
|
+
node
|
|
247
|
+
});
|
|
248
|
+
else cells.push({
|
|
249
|
+
type: "unit",
|
|
250
|
+
from,
|
|
251
|
+
to,
|
|
252
|
+
node
|
|
253
|
+
});
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
case "refused":
|
|
257
|
+
issue = `Canonical editing cannot preserve ${node.type.name} boundary positions.`;
|
|
258
|
+
return;
|
|
259
|
+
case void 0:
|
|
260
|
+
issue = `Canonical editing has no position mapping for inline ${node.type.name}.`;
|
|
261
|
+
return;
|
|
262
|
+
default:
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
return issue === void 0 ? Result.ok(cells) : refuse(issue);
|
|
266
|
+
};
|
|
267
|
+
const sameSourceMarker = (left, right) => {
|
|
268
|
+
switch (left.type) {
|
|
269
|
+
case "bookmarkStart":
|
|
270
|
+
case "bookmarkEnd":
|
|
271
|
+
case "commentRangeStart":
|
|
272
|
+
case "commentRangeEnd":
|
|
273
|
+
case "moveFromRangeStart":
|
|
274
|
+
case "moveFromRangeEnd":
|
|
275
|
+
case "moveToRangeStart":
|
|
276
|
+
case "moveToRangeEnd": return right.type === left.type && left.id === right.id;
|
|
277
|
+
case "noteMarker": return right.type === "noteMarker" && left.kind === right.kind;
|
|
278
|
+
case "preservedInline": return right.type === "preservedInline" && left.xml === right.xml && left.text === right.text;
|
|
279
|
+
default: return false;
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
/** Bind rendered gaps to the operation owner's source leaf ordinals, including collapsed pairs. */
|
|
283
|
+
const projectCanonicalInline = ({ source, paragraph, pairedBookmarkIds }) => {
|
|
284
|
+
const native = canonicalNativeCells(paragraph);
|
|
285
|
+
if (native.isErr()) return native;
|
|
286
|
+
const spans = inlineLeafSpans(source.content);
|
|
287
|
+
const erasedBookmarks = /* @__PURE__ */ new Set();
|
|
288
|
+
const collectErasedBookmarks = (items, context) => {
|
|
289
|
+
for (const item of items) {
|
|
290
|
+
if (item.type === "bookmarkStart" || item.type === "bookmarkEnd") {
|
|
291
|
+
if (context === "paragraph" && !pairedBookmarkIds.has(item.id)) erasedBookmarks.add(item);
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
if (CANONICAL_SOURCE_INLINE_POLICIES[item.type] !== "container") continue;
|
|
295
|
+
collectErasedBookmarks(sourceContainerChildren(item), item.type === "run" || item.type === "inlineWrapper" ? context : "nested");
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
collectErasedBookmarks(source.content, "paragraph");
|
|
299
|
+
const text = paragraphLogicalText(source);
|
|
300
|
+
const boundaries = Array.from({ length: text.length + 1 }, () => []);
|
|
301
|
+
let index = 0;
|
|
302
|
+
let consumed = 0;
|
|
303
|
+
const addGap = (position, gap) => {
|
|
304
|
+
const gaps = boundaries.at(gap.offset);
|
|
305
|
+
if (!gaps) panic(`Source leaf offset ${gap.offset} exceeds paragraph ${source.paraId}.`);
|
|
306
|
+
const existing = gaps.findIndex((entry) => entry.position === position);
|
|
307
|
+
const entry = {
|
|
308
|
+
position,
|
|
309
|
+
zeroWidthBefore: gap.zeroWidthBefore
|
|
310
|
+
};
|
|
311
|
+
if (existing < 0) gaps.push(entry);
|
|
312
|
+
else gaps[existing] = entry;
|
|
313
|
+
};
|
|
314
|
+
const consumeErasedLeaves = (position) => {
|
|
315
|
+
while (consumed === 0) {
|
|
316
|
+
const span = spans.at(index);
|
|
317
|
+
if (!span || span.before.offset !== span.after.offset || !(erasedBookmarks.has(span.node) || CANONICAL_SOURCE_INLINE_POLICIES[span.node.type] === "container" && sourceContainerChildren(span.node).length === 0)) break;
|
|
318
|
+
index += 1;
|
|
319
|
+
if (position !== null) addGap(position, span.after);
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
addGap(0, {
|
|
323
|
+
offset: 0,
|
|
324
|
+
zeroWidthBefore: 0
|
|
325
|
+
});
|
|
326
|
+
for (const cell of native.value) {
|
|
327
|
+
consumeErasedLeaves(cell.from);
|
|
328
|
+
let span = spans.at(index);
|
|
329
|
+
if (!span) return refuse(`Canonical editing cannot map native ${cell.node.type.name} to a source leaf.`);
|
|
330
|
+
addGap(cell.from, consumed === 0 ? span.before : {
|
|
331
|
+
offset: span.before.offset + consumed,
|
|
332
|
+
zeroWidthBefore: 0
|
|
333
|
+
});
|
|
334
|
+
switch (cell.type) {
|
|
335
|
+
case "zeroWidth":
|
|
336
|
+
for (const marker of cell.sources) {
|
|
337
|
+
consumeErasedLeaves(null);
|
|
338
|
+
span = spans.at(index);
|
|
339
|
+
if (!span || consumed !== 0 || span.before.offset !== span.after.offset || !sameSourceMarker(span.node, marker)) return refuse(`Canonical editing cannot preserve ${marker.type} source boundary positions.`);
|
|
340
|
+
index += 1;
|
|
341
|
+
}
|
|
342
|
+
if (!span) return refuse("Canonical editing lost a source range boundary.");
|
|
343
|
+
addGap(cell.to, span.after);
|
|
344
|
+
break;
|
|
345
|
+
case "unit":
|
|
346
|
+
case "markedUnit":
|
|
347
|
+
if (cell.type === "markedUnit" && (span.node.type !== "footnoteRef" && span.node.type !== "endnoteRef" || span.node.type !== cell.sourceType || String(span.node.id) !== cell.label)) return refuse("Canonical editing cannot preserve note-reference identity.");
|
|
348
|
+
if (consumed !== 0 || span.node.type === "text" || span.after.offset - span.before.offset !== 1) return refuse(`Canonical editing cannot map ${span.node.type} to one native inline unit.`);
|
|
349
|
+
index += 1;
|
|
350
|
+
addGap(cell.to, span.after);
|
|
351
|
+
break;
|
|
352
|
+
case "text":
|
|
353
|
+
for (let unit = 0; unit < cell.text.length; unit += 1) {
|
|
354
|
+
consumeErasedLeaves(cell.from + unit);
|
|
355
|
+
span = spans.at(index);
|
|
356
|
+
if (!span) return refuse("Canonical editing cannot map missing source text to native text positions.");
|
|
357
|
+
let value;
|
|
358
|
+
switch (span.node.type) {
|
|
359
|
+
case "text":
|
|
360
|
+
value = span.node.text;
|
|
361
|
+
break;
|
|
362
|
+
case "softHyphen":
|
|
363
|
+
case "noBreakHyphen":
|
|
364
|
+
value = HYPHEN_TEXT_CARRIERS[span.node.type];
|
|
365
|
+
break;
|
|
366
|
+
default: return refuse(`Canonical editing cannot map ${span.node.type} to native text positions.`);
|
|
367
|
+
}
|
|
368
|
+
if (value.charAt(consumed) !== cell.text.charAt(unit)) return refuse("Canonical editing cannot preserve the source text carrier.");
|
|
369
|
+
consumed += 1;
|
|
370
|
+
addGap(cell.from + unit + 1, {
|
|
371
|
+
offset: span.before.offset + consumed,
|
|
372
|
+
zeroWidthBefore: 0
|
|
373
|
+
});
|
|
374
|
+
if (consumed === value.length) {
|
|
375
|
+
index += 1;
|
|
376
|
+
consumed = 0;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
break;
|
|
380
|
+
default:
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
consumeErasedLeaves(paragraph.content.size);
|
|
384
|
+
const missing = spans.at(index);
|
|
385
|
+
if (missing || consumed !== 0) return refuse(`Canonical editing cannot display the source positions of ${missing?.node.type ?? "incomplete text"}.`);
|
|
386
|
+
if (boundaries.some((gaps) => gaps.length === 0)) return refuse("Canonical editing lost a source character boundary.");
|
|
387
|
+
return Result.ok({
|
|
388
|
+
text,
|
|
389
|
+
boundaries
|
|
390
|
+
});
|
|
391
|
+
};
|
|
392
|
+
//#endregion
|
|
393
|
+
export { CANONICAL_NATIVE_INLINE_POLICIES, CANONICAL_SOURCE_INLINE_POLICIES, canonicalInlineSourceIssue, canonicalNativeCells, projectCanonicalInline };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { EditorState, Transaction } from "prosemirror-state";
|
|
2
|
+
import { EditorView } from "prosemirror-view";
|
|
3
|
+
//#region src/controller/canonicalInput.d.ts
|
|
4
|
+
declare const CANONICAL_COMPOSITION_INPUT_TYPES: readonly ["insertCompositionText", "insertFromComposition", "deleteCompositionText", "deleteByComposition"];
|
|
5
|
+
type ReplaceTextInput = {
|
|
6
|
+
from: number;
|
|
7
|
+
to: number;
|
|
8
|
+
text: string;
|
|
9
|
+
} & ({
|
|
10
|
+
semantic: "composition";
|
|
11
|
+
compositionPhase?: "correction";
|
|
12
|
+
} | {
|
|
13
|
+
semantic?: "typing" | "deleteBackward" | "deleteForward";
|
|
14
|
+
compositionPhase?: never;
|
|
15
|
+
});
|
|
16
|
+
type CanonicalInputOptions = {
|
|
17
|
+
replace: (input: ReplaceTextInput) => void;
|
|
18
|
+
structure?: (type: "split" | "joinBackward" | "joinForward" | "lineBreak" | "pageBreak" | "tab" | "indent" | "outdent") => void;
|
|
19
|
+
command?: (name: "toggleBold" | "toggleItalic" | "toggleUnderline") => void;
|
|
20
|
+
breakUndoGroup?: () => void;
|
|
21
|
+
beginComposition?: () => boolean;
|
|
22
|
+
endComposition?: () => void;
|
|
23
|
+
pastePlainText?: (view: EditorView) => void;
|
|
24
|
+
cut?: (view: EditorView, event: ClipboardEvent) => boolean;
|
|
25
|
+
undo: () => boolean;
|
|
26
|
+
redo: () => boolean;
|
|
27
|
+
refuse: (reason: string) => void;
|
|
28
|
+
};
|
|
29
|
+
/** Native changes require a preceding, classified input event at the same state. */
|
|
30
|
+
declare const createCanonicalInputBoundary: (options: CanonicalInputOptions) => {
|
|
31
|
+
reset: () => void;
|
|
32
|
+
readonly isComposing: boolean;
|
|
33
|
+
acceptComposition: (view: EditorView, transaction: Transaction) => boolean;
|
|
34
|
+
handleTextInput: (view: EditorView, from: number, to: number, text: string) => boolean;
|
|
35
|
+
handleKeyDown: (view: EditorView, event: KeyboardEvent) => boolean;
|
|
36
|
+
handleDOMEvents: {
|
|
37
|
+
keydown: (view: EditorView, event: KeyboardEvent) => boolean;
|
|
38
|
+
compositionstart: (view: EditorView) => boolean;
|
|
39
|
+
compositionend: (view: EditorView) => boolean;
|
|
40
|
+
mousedown: (view: EditorView) => boolean;
|
|
41
|
+
blur: (view: EditorView) => boolean;
|
|
42
|
+
beforeinput: (view: EditorView, event: InputEvent) => boolean;
|
|
43
|
+
input: (view: EditorView) => boolean;
|
|
44
|
+
paste: (_view: EditorView, event: Event) => boolean;
|
|
45
|
+
cut: (view: EditorView, event: ClipboardEvent) => boolean;
|
|
46
|
+
drop: (_view: EditorView, event: Event) => boolean;
|
|
47
|
+
};
|
|
48
|
+
/** Returns a classified intent only; the proposed PM document is never authoritative. */
|
|
49
|
+
takeNativeProposal: (state: EditorState, transaction: Transaction) => ReplaceTextInput | null;
|
|
50
|
+
refuseNativeMutation: (view: EditorView) => void;
|
|
51
|
+
commitNativeProposal: (view: EditorView, transaction: Transaction) => boolean;
|
|
52
|
+
};
|
|
53
|
+
//#endregion
|
|
54
|
+
export { CANONICAL_COMPOSITION_INPUT_TYPES, createCanonicalInputBoundary };
|