@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,267 @@
|
|
|
1
|
+
//#region src/docx/foldedListNumberFields.ts
|
|
2
|
+
/** Zero-width markup that can stand between a field and its tab. */
|
|
3
|
+
const RANGE_MARKER_TYPES = /* @__PURE__ */ new Set([
|
|
4
|
+
"bookmarkStart",
|
|
5
|
+
"bookmarkEnd",
|
|
6
|
+
"commentRangeStart",
|
|
7
|
+
"commentRangeEnd",
|
|
8
|
+
"commentReference"
|
|
9
|
+
]);
|
|
10
|
+
/** Markup that shows nothing and so does not end the start of a paragraph. */
|
|
11
|
+
const ZERO_WIDTH_TYPES = /* @__PURE__ */ new Set([
|
|
12
|
+
...RANGE_MARKER_TYPES,
|
|
13
|
+
"moveFromRangeStart",
|
|
14
|
+
"moveFromRangeEnd",
|
|
15
|
+
"moveToRangeStart",
|
|
16
|
+
"moveToRangeEnd"
|
|
17
|
+
]);
|
|
18
|
+
/** Whether `content` is markup that may stand between a field and the tab that follows it. */
|
|
19
|
+
const isListNumberGapMarker = (content) => RANGE_MARKER_TYPES.has(content.type);
|
|
20
|
+
const isZeroWidth = (content) => ZERO_WIDTH_TYPES.has(content.type) || content.type === "preservedInline" && content.text === "";
|
|
21
|
+
/** Whether `content` is a `LISTNUM` field, by its parsed type or its instruction. */
|
|
22
|
+
const isListNumberField = (content) => content.type === "complexField" && (content.fieldType === "LISTNUM" || content.instruction.trim().toUpperCase().startsWith("LISTNUM"));
|
|
23
|
+
/** A run that holds one tab and nothing else. */
|
|
24
|
+
const isTabOnlyRun = (content) => content.type === "run" && content.content.length === 1 && content.content[0]?.type === "tab";
|
|
25
|
+
/** The text a field's cached result puts in the marker. */
|
|
26
|
+
const cachedListNumberText = (field) => {
|
|
27
|
+
let text = "";
|
|
28
|
+
for (const run of field.fieldResult) for (const piece of run.content) if (piece.type === "text") text += piece.text;
|
|
29
|
+
return text;
|
|
30
|
+
};
|
|
31
|
+
const isRecord = (value) => typeof value === "object" && value !== null;
|
|
32
|
+
/** Whether `value` is what a capture stands for: a complex field, or a run. */
|
|
33
|
+
const isFoldedListNumber = (value) => {
|
|
34
|
+
if (!isRecord(value)) return false;
|
|
35
|
+
if (value["kind"] === "field") {
|
|
36
|
+
const field = value["field"];
|
|
37
|
+
return isRecord(field) && field["type"] === "complexField" && typeof field["instruction"] === "string" && Array.isArray(field["fieldCode"]) && Array.isArray(field["fieldResult"]);
|
|
38
|
+
}
|
|
39
|
+
if (value["kind"] === "tab") {
|
|
40
|
+
const run = value["run"];
|
|
41
|
+
return isRecord(run) && run["type"] === "run" && Array.isArray(run["content"]);
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
};
|
|
45
|
+
/** What `content` stands for when it is a capture the fold left, else nothing. */
|
|
46
|
+
const foldedListNumberOf = (content) => content.type === "preservedInline" ? content.foldedListNumber : void 0;
|
|
47
|
+
/** Whether `content` is a capture the fold left in place of a field or its tab. */
|
|
48
|
+
const isFoldedListNumberCapture = (content) => foldedListNumberOf(content) !== void 0;
|
|
49
|
+
/**
|
|
50
|
+
* Replace the `LISTNUM` fields that open a paragraph, and the tab after each,
|
|
51
|
+
* by captures of the markup they were read from.
|
|
52
|
+
*
|
|
53
|
+
* Only what stands ahead of the first thing the line shows is folded: a field
|
|
54
|
+
* after text is on the line where the text is. `sourceMarkupOf` answers the
|
|
55
|
+
* markup; a field it has none for is left as the field it is, and ends the
|
|
56
|
+
* fold. Bookmark and comment markers between a field and its tab stay where
|
|
57
|
+
* they are, and the tab is still the field's when only they separate the two.
|
|
58
|
+
*/
|
|
59
|
+
const foldListNumberFields = (content, sourceMarkupOf) => {
|
|
60
|
+
const folded = [];
|
|
61
|
+
const cached = [];
|
|
62
|
+
let fieldCount = 0;
|
|
63
|
+
let leading = true;
|
|
64
|
+
let awaitingTab = false;
|
|
65
|
+
for (const item of content) {
|
|
66
|
+
if (isListNumberField(item)) fieldCount += 1;
|
|
67
|
+
if (!leading) {
|
|
68
|
+
folded.push(item);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (awaitingTab && RANGE_MARKER_TYPES.has(item.type)) {
|
|
72
|
+
folded.push(item);
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (awaitingTab) {
|
|
76
|
+
awaitingTab = false;
|
|
77
|
+
const tabMarkup = isTabOnlyRun(item) ? sourceMarkupOf(item) : void 0;
|
|
78
|
+
if (isTabOnlyRun(item) && tabMarkup !== void 0) {
|
|
79
|
+
folded.push({
|
|
80
|
+
type: "preservedInline",
|
|
81
|
+
xml: tabMarkup,
|
|
82
|
+
text: "",
|
|
83
|
+
foldedListNumber: {
|
|
84
|
+
kind: "tab",
|
|
85
|
+
run: item
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (isListNumberField(item)) {
|
|
92
|
+
const markup = sourceMarkupOf(item);
|
|
93
|
+
if (markup !== void 0) {
|
|
94
|
+
folded.push({
|
|
95
|
+
type: "preservedInline",
|
|
96
|
+
xml: markup,
|
|
97
|
+
text: "",
|
|
98
|
+
foldedListNumber: {
|
|
99
|
+
kind: "field",
|
|
100
|
+
field: item
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
const text = cachedListNumberText(item);
|
|
104
|
+
if (text) cached.push(text);
|
|
105
|
+
awaitingTab = true;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
folded.push(item);
|
|
110
|
+
leading = isZeroWidth(item);
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
content: folded,
|
|
114
|
+
cached,
|
|
115
|
+
fieldCount
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
const isCapture = (item) => item?.kind === "field" || item?.kind === "tab";
|
|
119
|
+
/**
|
|
120
|
+
* Decide which captures of a paragraph stay hidden, and what its marker shows.
|
|
121
|
+
*
|
|
122
|
+
* `markerShowsFields` says whether the paragraph's marker shows folded fields
|
|
123
|
+
* at all. When it does not, no capture is hidden.
|
|
124
|
+
*
|
|
125
|
+
* When it does, the captures it shows are the ones that open the paragraph:
|
|
126
|
+
* those ahead of the first thing the line shows, each field followed at most
|
|
127
|
+
* by its own tab. Text put in front of them was put in front of the body, not
|
|
128
|
+
* of the marker, so if the first capture no longer opens the paragraph, it
|
|
129
|
+
* and the captures that stand with it go back to the start. Every capture
|
|
130
|
+
* further in is on the line.
|
|
131
|
+
*/
|
|
132
|
+
const planListNumberFold = (items, markerShowsFields) => {
|
|
133
|
+
const unmoved = items.map((_, index) => index);
|
|
134
|
+
const none = {
|
|
135
|
+
order: unmoved,
|
|
136
|
+
hidden: /* @__PURE__ */ new Set(),
|
|
137
|
+
suffix: void 0
|
|
138
|
+
};
|
|
139
|
+
const first = items.findIndex((item) => isCapture(item));
|
|
140
|
+
if (!markerShowsFields || first === -1) return none;
|
|
141
|
+
let order = unmoved;
|
|
142
|
+
if (items.slice(0, first).some((item) => item.kind === "shown")) {
|
|
143
|
+
let end = first + 1;
|
|
144
|
+
for (let index = first + 1; index < items.length; index += 1) {
|
|
145
|
+
const item = items[index];
|
|
146
|
+
if (item?.kind === "shown") break;
|
|
147
|
+
if (isCapture(item)) end = index + 1;
|
|
148
|
+
}
|
|
149
|
+
order = [
|
|
150
|
+
...unmoved.slice(first, end),
|
|
151
|
+
...unmoved.slice(0, first),
|
|
152
|
+
...unmoved.slice(end)
|
|
153
|
+
];
|
|
154
|
+
}
|
|
155
|
+
const hidden = /* @__PURE__ */ new Set();
|
|
156
|
+
const cached = [];
|
|
157
|
+
let fieldAwaitsTab = false;
|
|
158
|
+
for (const index of order) {
|
|
159
|
+
const item = items[index];
|
|
160
|
+
if (item?.kind === "hidden") continue;
|
|
161
|
+
if (item?.kind === "field") {
|
|
162
|
+
hidden.add(index);
|
|
163
|
+
if (item.cached) cached.push(item.cached);
|
|
164
|
+
fieldAwaitsTab = true;
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if (item?.kind === "tab" && fieldAwaitsTab) {
|
|
168
|
+
hidden.add(index);
|
|
169
|
+
fieldAwaitsTab = false;
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
return cached.length === 0 ? none : {
|
|
175
|
+
order,
|
|
176
|
+
hidden,
|
|
177
|
+
suffix: cached.join(" ")
|
|
178
|
+
};
|
|
179
|
+
};
|
|
180
|
+
/**
|
|
181
|
+
* What a paragraph's marker says about folded fields. It shows them after a
|
|
182
|
+
* tab its own level text does not have; a bullet shows only its glyph.
|
|
183
|
+
*/
|
|
184
|
+
const listMarkerFoldState = ({ marker, template, isBullet, numbered }) => {
|
|
185
|
+
const tab = marker?.indexOf(" ") ?? -1;
|
|
186
|
+
if (!marker || !numbered || isBullet || !template || template.includes(" ") || tab === -1) return {
|
|
187
|
+
showsFields: false,
|
|
188
|
+
base: marker ?? ""
|
|
189
|
+
};
|
|
190
|
+
return {
|
|
191
|
+
showsFields: true,
|
|
192
|
+
base: marker.slice(0, tab)
|
|
193
|
+
};
|
|
194
|
+
};
|
|
195
|
+
/** The marker text for `state` showing `suffix`. */
|
|
196
|
+
const listMarkerWithFold = (state, suffix) => suffix === void 0 ? state.base : `${state.base}\t${suffix}`;
|
|
197
|
+
const foldItemOf = (content) => {
|
|
198
|
+
const folded = foldedListNumberOf(content);
|
|
199
|
+
if (folded) return folded.kind === "field" ? {
|
|
200
|
+
kind: "field",
|
|
201
|
+
cached: cachedListNumberText(folded.field)
|
|
202
|
+
} : { kind: "tab" };
|
|
203
|
+
return isZeroWidth(content) ? { kind: "hidden" } : { kind: "shown" };
|
|
204
|
+
};
|
|
205
|
+
/** The item a capture stands for, which shows on the line; any other item is itself. */
|
|
206
|
+
const unfoldedListNumberContent = (content) => {
|
|
207
|
+
const folded = foldedListNumberOf(content);
|
|
208
|
+
if (!folded) return content;
|
|
209
|
+
return folded.kind === "field" ? folded.field : folded.run;
|
|
210
|
+
};
|
|
211
|
+
/**
|
|
212
|
+
* The one definition of a tracked change for the fold: content inserted,
|
|
213
|
+
* deleted, or moved from or to a place under revision tracking.
|
|
214
|
+
*/
|
|
215
|
+
const isTrackedChange = (content) => content.type === "insertion" || content.type === "deletion" || content.type === "moveFrom" || content.type === "moveTo";
|
|
216
|
+
/**
|
|
217
|
+
* `content` with every capture inside a tracked change replaced by the item
|
|
218
|
+
* it stands for. A tracked change is written with its own spellings (deleted
|
|
219
|
+
* text is `w:delText`, a deleted instruction `w:delInstrText`), which markup
|
|
220
|
+
* replayed as it was read does not have; the field and the run do.
|
|
221
|
+
*/
|
|
222
|
+
const withTrackedCapturesShown = (content) => {
|
|
223
|
+
let changed = false;
|
|
224
|
+
const next = content.map((item) => {
|
|
225
|
+
if (!isTrackedChange(item)) return item;
|
|
226
|
+
if (!item.content.some((child) => foldedListNumberOf(child) !== void 0)) return item;
|
|
227
|
+
changed = true;
|
|
228
|
+
return {
|
|
229
|
+
...item,
|
|
230
|
+
content: item.content.map((child) => {
|
|
231
|
+
const folded = foldedListNumberOf(child);
|
|
232
|
+
if (!folded) return child;
|
|
233
|
+
return structuredClone(folded.kind === "field" ? folded.field : folded.run);
|
|
234
|
+
})
|
|
235
|
+
};
|
|
236
|
+
});
|
|
237
|
+
return changed ? next : content;
|
|
238
|
+
};
|
|
239
|
+
/**
|
|
240
|
+
* Bring `paragraph` to the one form the fold allows: the captures its marker
|
|
241
|
+
* shows stand at its start, every other capture is the field or the tab it
|
|
242
|
+
* stood for, and the marker shows exactly the fields still hidden behind it.
|
|
243
|
+
* A capture under a tracked change is never hidden.
|
|
244
|
+
*/
|
|
245
|
+
const normalizeFoldedListNumbers = (paragraph) => {
|
|
246
|
+
paragraph.content = withTrackedCapturesShown(paragraph.content);
|
|
247
|
+
const rendering = paragraph.listRendering;
|
|
248
|
+
const state = listMarkerFoldState({
|
|
249
|
+
marker: rendering?.marker,
|
|
250
|
+
template: rendering?.markerTemplate,
|
|
251
|
+
isBullet: rendering?.isBullet === true,
|
|
252
|
+
numbered: rendering !== void 0
|
|
253
|
+
});
|
|
254
|
+
const content = paragraph.content;
|
|
255
|
+
if (!state.showsFields && !content.some(isFoldedListNumberCapture)) return;
|
|
256
|
+
const plan = planListNumberFold(content.map(foldItemOf), state.showsFields);
|
|
257
|
+
const next = [];
|
|
258
|
+
for (const index of plan.order) {
|
|
259
|
+
const item = content[index];
|
|
260
|
+
if (item === void 0) continue;
|
|
261
|
+
next.push(plan.hidden.has(index) || !isFoldedListNumberCapture(item) ? item : structuredClone(unfoldedListNumberContent(item)));
|
|
262
|
+
}
|
|
263
|
+
paragraph.content = next;
|
|
264
|
+
if (rendering && state.showsFields) rendering.marker = listMarkerWithFold(state, plan.suffix);
|
|
265
|
+
};
|
|
266
|
+
//#endregion
|
|
267
|
+
export { foldListNumberFields, foldedListNumberOf, isFoldedListNumber, isFoldedListNumberCapture, isListNumberField, isListNumberGapMarker, isTabOnlyRun, normalizeFoldedListNumbers, planListNumberFold, unfoldedListNumberContent };
|
|
@@ -67,16 +67,6 @@ declare function parseFootnotes(footnotesXml: string | null, styles?: StyleMap |
|
|
|
67
67
|
* @returns EndnoteMap with all endnotes
|
|
68
68
|
*/
|
|
69
69
|
declare function parseEndnotes(endnotesXml: string | null, styles?: StyleMap | null, theme?: document_d_exports.Theme | null, numbering?: NumberingMap | null, rels?: document_d_exports.RelationshipMap | null, media?: Map<string, document_d_exports.MediaFile> | null, context?: ParseContext, previews?: PreviewLedger): EndnoteMap;
|
|
70
|
-
/**
|
|
71
|
-
* Get plain text content of a footnote.
|
|
72
|
-
*
|
|
73
|
-
* Uses the accepted tracked-change view and recurses through every note block.
|
|
74
|
-
*/
|
|
75
|
-
declare function getFootnoteText(footnote: document_d_exports.Footnote): string;
|
|
76
|
-
/**
|
|
77
|
-
* Get plain text content of an endnote.
|
|
78
|
-
*/
|
|
79
|
-
declare function getEndnoteText(endnote: document_d_exports.Endnote): string;
|
|
80
70
|
/**
|
|
81
71
|
* Check if a footnote is a separator (not regular content)
|
|
82
72
|
*/
|
|
@@ -102,4 +92,4 @@ declare function mergeFootnoteMaps(...maps: FootnoteMap[]): FootnoteMap;
|
|
|
102
92
|
*/
|
|
103
93
|
declare function mergeEndnoteMaps(...maps: EndnoteMap[]): EndnoteMap;
|
|
104
94
|
//#endregion
|
|
105
|
-
export { EndnoteMap, FootnoteMap, createEmptyEndnoteMap, createEmptyFootnoteMap,
|
|
95
|
+
export { EndnoteMap, FootnoteMap, createEmptyEndnoteMap, createEmptyFootnoteMap, isSeparatorEndnote, isSeparatorFootnote, mergeEndnoteMaps, mergeFootnoteMaps, parseEndnoteProperties, parseEndnotes, parseFootnoteProperties, parseFootnotes };
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { blockPlainText } from "./blockPlainText.js";
|
|
2
1
|
import { parseEndnoteProperties, parseFootnoteProperties } from "./notePropertiesParser.js";
|
|
3
2
|
import { parseParagraph } from "./paragraphParser.js";
|
|
4
3
|
import { standalonePreviewLedger } from "./previewBudget.js";
|
|
@@ -196,20 +195,6 @@ function createEndnoteMap(byId, endnotes) {
|
|
|
196
195
|
};
|
|
197
196
|
}
|
|
198
197
|
/**
|
|
199
|
-
* Get plain text content of a footnote.
|
|
200
|
-
*
|
|
201
|
-
* Uses the accepted tracked-change view and recurses through every note block.
|
|
202
|
-
*/
|
|
203
|
-
function getFootnoteText(footnote) {
|
|
204
|
-
return blockPlainText(footnote.content);
|
|
205
|
-
}
|
|
206
|
-
/**
|
|
207
|
-
* Get plain text content of an endnote.
|
|
208
|
-
*/
|
|
209
|
-
function getEndnoteText(endnote) {
|
|
210
|
-
return blockPlainText(endnote.content);
|
|
211
|
-
}
|
|
212
|
-
/**
|
|
213
198
|
* Check if a footnote is a separator (not regular content)
|
|
214
199
|
*/
|
|
215
200
|
function isSeparatorFootnote(footnote) {
|
|
@@ -258,4 +243,4 @@ function mergeEndnoteMaps(...maps) {
|
|
|
258
243
|
return createEndnoteMap(byId, endnotes);
|
|
259
244
|
}
|
|
260
245
|
//#endregion
|
|
261
|
-
export { createEmptyEndnoteMap, createEmptyFootnoteMap,
|
|
246
|
+
export { createEmptyEndnoteMap, createEmptyFootnoteMap, isSeparatorEndnote, isSeparatorFootnote, mergeEndnoteMaps, mergeFootnoteMaps, parseEndnoteProperties, parseEndnotes, parseFootnoteProperties, parseFootnotes };
|
|
@@ -81,14 +81,6 @@ declare function createEmptyHeaderFooterMap(): HeaderFooterMap;
|
|
|
81
81
|
* @returns HeaderFooterMap with all parsed headers/footers
|
|
82
82
|
*/
|
|
83
83
|
declare function buildHeaderFooterMap(references: (document_d_exports.HeaderReference | document_d_exports.FooterReference)[], xmlContents: Map<string, string>, isHeader: boolean, styles?: StyleMap | null, theme?: document_d_exports.Theme | null, numbering?: NumberingMap | null, rels?: document_d_exports.RelationshipMap | null, media?: Map<string, document_d_exports.MediaFile> | null): HeaderFooterMap;
|
|
84
|
-
/**
|
|
85
|
-
* Get plain text content of a header/footer.
|
|
86
|
-
*
|
|
87
|
-
* Shares one walk with the note stories: this used to read only text runs, so a
|
|
88
|
-
* header's fields, hyperlinks, tabs and breaks were silently absent from its
|
|
89
|
-
* text while the same paragraph in a footnote read in full.
|
|
90
|
-
*/
|
|
91
|
-
declare function getHeaderFooterText(hf: document_d_exports.HeaderFooter): string;
|
|
92
84
|
/**
|
|
93
85
|
* Check if header/footer is empty (no content)
|
|
94
86
|
*/
|
|
@@ -129,4 +121,4 @@ declare function hasImages(hf: document_d_exports.HeaderFooter): boolean;
|
|
|
129
121
|
*/
|
|
130
122
|
declare function hasTables(hf: document_d_exports.HeaderFooter): boolean;
|
|
131
123
|
//#endregion
|
|
132
|
-
export { HeaderFooterMap, buildHeaderFooterMap, createEmptyHeaderFooterMap, getFooterForPage,
|
|
124
|
+
export { HeaderFooterMap, buildHeaderFooterMap, createEmptyHeaderFooterMap, getFooterForPage, getHeaderForPage, hasImages, hasPageNumberField, hasTables, headerFooterMapToTypeMap, isEmptyHeaderFooter, parseFooter, parseFooterReference, parseFooterReferences, parseHeader, parseHeaderFooter, parseHeaderReference, parseHeaderReferences };
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { parseBlockContent } from "./blockContentParser.js";
|
|
2
|
-
import { blockPlainText } from "./blockPlainText.js";
|
|
3
2
|
import { parseFooterReference, parseFooterReferences, parseHeaderReference, parseHeaderReferences } from "./headerFooterRefParser.js";
|
|
4
3
|
import { assignHeaderFooterVerbatimXml } from "./headerFooterVerbatim.js";
|
|
5
4
|
import { cloneParagraphWithPropertySource } from "./paragraphPropertySource.js";
|
|
@@ -150,16 +149,6 @@ function buildHeaderFooterMap(references, xmlContents, isHeader, styles = null,
|
|
|
150
149
|
return createHeaderFooterMap(byId);
|
|
151
150
|
}
|
|
152
151
|
/**
|
|
153
|
-
* Get plain text content of a header/footer.
|
|
154
|
-
*
|
|
155
|
-
* Shares one walk with the note stories: this used to read only text runs, so a
|
|
156
|
-
* header's fields, hyperlinks, tabs and breaks were silently absent from its
|
|
157
|
-
* text while the same paragraph in a footnote read in full.
|
|
158
|
-
*/
|
|
159
|
-
function getHeaderFooterText(hf) {
|
|
160
|
-
return blockPlainText(hf.content);
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
152
|
* Check if header/footer is empty (no content)
|
|
164
153
|
*/
|
|
165
154
|
function isEmptyHeaderFooter(hf) {
|
|
@@ -254,4 +243,4 @@ function hasTables(hf) {
|
|
|
254
243
|
return false;
|
|
255
244
|
}
|
|
256
245
|
//#endregion
|
|
257
|
-
export { buildHeaderFooterMap, createEmptyHeaderFooterMap, getFooterForPage,
|
|
246
|
+
export { buildHeaderFooterMap, createEmptyHeaderFooterMap, getFooterForPage, getHeaderForPage, hasImages, hasPageNumberField, hasTables, headerFooterMapToTypeMap, isEmptyHeaderFooter, parseFooter, parseFooterReference, parseFooterReferences, parseHeader, parseHeaderFooter, parseHeaderReference, parseHeaderReferences };
|
|
@@ -1,9 +1,47 @@
|
|
|
1
1
|
import { document_d_exports } from "../types/document.js";
|
|
2
2
|
//#region src/docx/headerFooterVerbatim.d.ts
|
|
3
|
+
type HeaderFooterSourceBaseline = {
|
|
4
|
+
type: "missing";
|
|
5
|
+
} | {
|
|
6
|
+
type: "mismatch";
|
|
7
|
+
} | {
|
|
8
|
+
type: "captured";
|
|
9
|
+
content: readonly document_d_exports.BlockContent[];
|
|
10
|
+
};
|
|
11
|
+
declare const captureHeaderFooterPackageBaselines: (document: document_d_exports.Document) => void;
|
|
12
|
+
/**
|
|
13
|
+
* Transfer body, header and footer capture handles across a trusted
|
|
14
|
+
* document graph clone. `structuredClone` drops symbol-keyed properties, so a
|
|
15
|
+
* clone would otherwise read an edited part as uncaptured ("missing") rather
|
|
16
|
+
* than as a mismatch against its source.
|
|
17
|
+
*/
|
|
18
|
+
declare const copyHeaderFooterBaselineHandles: (target: document_d_exports.Document, source: document_d_exports.Document) => void;
|
|
19
|
+
/** Transfer the parsed package registry only across a trusted document graph clone. */
|
|
20
|
+
declare const copyHeaderFooterPackageBaselines: (target: document_d_exports.Document, source: document_d_exports.Document) => void;
|
|
21
|
+
declare const getHeaderFooterSourceBaseline: (hf: document_d_exports.HeaderFooter, originalBuffer?: ArrayBuffer) => HeaderFooterSourceBaseline;
|
|
22
|
+
declare const canReplayHeaderFooterBlocks: (hf: document_d_exports.HeaderFooter, baselineContent: readonly document_d_exports.BlockContent[]) => boolean;
|
|
3
23
|
declare const getHeaderFooterVerbatimXml: (hf: document_d_exports.HeaderFooter) => string | undefined;
|
|
4
24
|
declare const canReplayHeaderFooterVerbatim: (hf: document_d_exports.HeaderFooter) => boolean;
|
|
5
25
|
declare const assignHeaderFooterVerbatimXml: (hf: document_d_exports.HeaderFooter, xml: string) => void;
|
|
6
26
|
declare const refreshHeaderFooterVerbatimFingerprint: (hf: document_d_exports.HeaderFooter) => void;
|
|
7
27
|
declare const clearHeaderFooterVerbatimXml: (hf: document_d_exports.HeaderFooter) => void;
|
|
28
|
+
/** Capture the body in the same trusted package registry as secondary stories. */
|
|
29
|
+
declare const captureDocumentSourceBaseline: (document: document_d_exports.Document, xml: string) => void;
|
|
30
|
+
declare const getDocumentSourceBaseline: (document: document_d_exports.Document) => {
|
|
31
|
+
type: "missing";
|
|
32
|
+
} | {
|
|
33
|
+
type: "mismatch";
|
|
34
|
+
} | {
|
|
35
|
+
type: "captured";
|
|
36
|
+
body: document_d_exports.Document["package"]["document"];
|
|
37
|
+
xml: string;
|
|
38
|
+
fingerprint: string;
|
|
39
|
+
resourceStyles: document_d_exports.Document["package"]["styles"];
|
|
40
|
+
resourceRelationships: document_d_exports.Document["package"]["relationships"];
|
|
41
|
+
resourceMedia: ReadonlyMap<string, {
|
|
42
|
+
data: ArrayBuffer;
|
|
43
|
+
mimeType: string;
|
|
44
|
+
}>;
|
|
45
|
+
};
|
|
8
46
|
//#endregion
|
|
9
|
-
export { assignHeaderFooterVerbatimXml, canReplayHeaderFooterVerbatim, clearHeaderFooterVerbatimXml, getHeaderFooterVerbatimXml, refreshHeaderFooterVerbatimFingerprint };
|
|
47
|
+
export { assignHeaderFooterVerbatimXml, canReplayHeaderFooterBlocks, canReplayHeaderFooterVerbatim, captureDocumentSourceBaseline, captureHeaderFooterPackageBaselines, clearHeaderFooterVerbatimXml, copyHeaderFooterBaselineHandles, copyHeaderFooterPackageBaselines, getDocumentSourceBaseline, getHeaderFooterSourceBaseline, getHeaderFooterVerbatimXml, refreshHeaderFooterVerbatimFingerprint };
|
|
@@ -1,5 +1,117 @@
|
|
|
1
|
+
import { canonicalJson } from "../utils/canonicalJson.js";
|
|
2
|
+
import { Result } from "better-result";
|
|
1
3
|
//#region src/docx/headerFooterVerbatim.ts
|
|
4
|
+
const fingerprintBaselines = /* @__PURE__ */ new WeakMap();
|
|
5
|
+
const readFingerprint = (hf) => {
|
|
6
|
+
const fingerprint = hf.verbatimFingerprint;
|
|
7
|
+
if (!fingerprint) return void 0;
|
|
8
|
+
const cached = fingerprintBaselines.get(hf);
|
|
9
|
+
if (cached?.fingerprint === fingerprint) return cached.value;
|
|
10
|
+
const parsed = Result.try(() => JSON.parse(fingerprint));
|
|
11
|
+
const value = parsed.isOk() ? parsed.value : void 0;
|
|
12
|
+
fingerprintBaselines.set(hf, {
|
|
13
|
+
fingerprint,
|
|
14
|
+
value
|
|
15
|
+
});
|
|
16
|
+
return value;
|
|
17
|
+
};
|
|
18
|
+
const BASELINE_HANDLE = Symbol("package-source-baseline");
|
|
19
|
+
const contentBaselines = /* @__PURE__ */ new WeakMap();
|
|
20
|
+
const captureContentBaseline = (hf) => {
|
|
21
|
+
const fingerprint = hf.verbatimFingerprint;
|
|
22
|
+
if (fingerprint === void 0) return;
|
|
23
|
+
const handle = {};
|
|
24
|
+
const content = structuredClone(hf.content);
|
|
25
|
+
contentBaselines.set(handle, {
|
|
26
|
+
type: "headerFooter",
|
|
27
|
+
fingerprint,
|
|
28
|
+
xml: hf.verbatimXml,
|
|
29
|
+
contentFingerprint: canonicalJson(content),
|
|
30
|
+
content
|
|
31
|
+
});
|
|
32
|
+
Object.defineProperty(hf, BASELINE_HANDLE, {
|
|
33
|
+
value: handle,
|
|
34
|
+
enumerable: true,
|
|
35
|
+
configurable: true
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
const packageBaselines = /* @__PURE__ */ new WeakMap();
|
|
39
|
+
const captureHeaderFooterPackageBaselines = (document) => {
|
|
40
|
+
if (!document.originalBuffer) return;
|
|
41
|
+
const handles = /* @__PURE__ */ new Map();
|
|
42
|
+
for (const parts of [document.package.headers, document.package.footers]) for (const hf of parts?.values() ?? []) {
|
|
43
|
+
if (!(BASELINE_HANDLE in hf) || typeof hf[BASELINE_HANDLE] !== "object" || hf[BASELINE_HANDLE] === null || hf.verbatimFingerprint === void 0 || hf.verbatimXml === void 0) continue;
|
|
44
|
+
const bySource = handles.get(hf.verbatimFingerprint) ?? /* @__PURE__ */ new Map();
|
|
45
|
+
bySource.set(hf.verbatimXml, hf[BASELINE_HANDLE]);
|
|
46
|
+
handles.set(hf.verbatimFingerprint, bySource);
|
|
47
|
+
}
|
|
48
|
+
packageBaselines.set(document.originalBuffer, handles);
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Transfer body, header and footer capture handles across a trusted
|
|
52
|
+
* document graph clone. `structuredClone` drops symbol-keyed properties, so a
|
|
53
|
+
* clone would otherwise read an edited part as uncaptured ("missing") rather
|
|
54
|
+
* than as a mismatch against its source.
|
|
55
|
+
*/
|
|
56
|
+
const copyHeaderFooterBaselineHandles = (target, source) => {
|
|
57
|
+
const sourceBody = source.package.document;
|
|
58
|
+
if (BASELINE_HANDLE in sourceBody) Object.defineProperty(target.package.document, BASELINE_HANDLE, {
|
|
59
|
+
value: sourceBody[BASELINE_HANDLE],
|
|
60
|
+
enumerable: true,
|
|
61
|
+
configurable: true
|
|
62
|
+
});
|
|
63
|
+
for (const kind of ["headers", "footers"]) {
|
|
64
|
+
const targets = target.package[kind];
|
|
65
|
+
for (const [rId, sourcePart] of source.package[kind] ?? []) {
|
|
66
|
+
if (!(BASELINE_HANDLE in sourcePart)) continue;
|
|
67
|
+
const targetPart = targets?.get(rId);
|
|
68
|
+
if (!targetPart) continue;
|
|
69
|
+
Object.defineProperty(targetPart, BASELINE_HANDLE, {
|
|
70
|
+
value: sourcePart[BASELINE_HANDLE],
|
|
71
|
+
enumerable: true,
|
|
72
|
+
configurable: true
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
/** Transfer the parsed package registry only across a trusted document graph clone. */
|
|
78
|
+
const copyHeaderFooterPackageBaselines = (target, source) => {
|
|
79
|
+
if (!target.originalBuffer || !source.originalBuffer) return;
|
|
80
|
+
const baselines = packageBaselines.get(source.originalBuffer);
|
|
81
|
+
if (baselines) packageBaselines.set(target.originalBuffer, baselines);
|
|
82
|
+
};
|
|
83
|
+
const getHeaderFooterSourceBaseline = (hf, originalBuffer) => {
|
|
84
|
+
let handle;
|
|
85
|
+
if (BASELINE_HANDLE in hf) handle = hf[BASELINE_HANDLE];
|
|
86
|
+
else if (originalBuffer && hf.verbatimFingerprint !== void 0 && hf.verbatimXml !== void 0) handle = packageBaselines.get(originalBuffer)?.get(hf.verbatimFingerprint)?.get(hf.verbatimXml);
|
|
87
|
+
if (handle === void 0 && !(BASELINE_HANDLE in hf)) return { type: "missing" };
|
|
88
|
+
if (typeof handle !== "object" || handle === null) return { type: "mismatch" };
|
|
89
|
+
const baseline = contentBaselines.get(handle);
|
|
90
|
+
if (!baseline || baseline.type !== "headerFooter" || baseline.fingerprint !== hf.verbatimFingerprint || baseline.xml !== hf.verbatimXml || baseline.contentFingerprint !== canonicalJson(baseline.content)) return { type: "mismatch" };
|
|
91
|
+
return {
|
|
92
|
+
type: "captured",
|
|
93
|
+
content: baseline.content
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
const canReplayHeaderFooterBlocks = (hf, baselineContent) => {
|
|
97
|
+
if (hf.rawWatermarkXml !== void 0) {
|
|
98
|
+
const index = hf.watermarkBlockIndex;
|
|
99
|
+
if (index === void 0 || !Number.isInteger(index) || index < 0 || index >= baselineContent.length || baselineContent.length !== hf.content.length || canonicalJson(baselineContent.at(index)) !== canonicalJson(hf.content.at(index))) return false;
|
|
100
|
+
}
|
|
101
|
+
const baseline = readFingerprint(hf);
|
|
102
|
+
if (baseline === null || typeof baseline !== "object" || !("type" in baseline) || baseline.type !== hf.type) return false;
|
|
103
|
+
return canonicalJson({
|
|
104
|
+
watermark: "watermark" in baseline ? baseline.watermark : void 0,
|
|
105
|
+
watermarkBlockIndex: "watermarkBlockIndex" in baseline ? baseline.watermarkBlockIndex : void 0,
|
|
106
|
+
rawWatermarkXml: "rawWatermarkXml" in baseline ? baseline.rawWatermarkXml : void 0
|
|
107
|
+
}) === canonicalJson({
|
|
108
|
+
watermark: hf.watermark,
|
|
109
|
+
watermarkBlockIndex: hf.watermarkBlockIndex,
|
|
110
|
+
rawWatermarkXml: hf.rawWatermarkXml
|
|
111
|
+
});
|
|
112
|
+
};
|
|
2
113
|
const headerFooterSerializationFingerprint = (hf) => JSON.stringify({
|
|
114
|
+
type: hf.type,
|
|
3
115
|
content: hf.content,
|
|
4
116
|
watermark: hf.watermark,
|
|
5
117
|
watermarkBlockIndex: hf.watermarkBlockIndex,
|
|
@@ -9,22 +121,81 @@ const getHeaderFooterVerbatimXml = (hf) => hf.verbatimXml;
|
|
|
9
121
|
const canReplayHeaderFooterVerbatim = (hf) => {
|
|
10
122
|
const ext = hf;
|
|
11
123
|
if (!ext.verbatimXml || !ext.verbatimFingerprint) return false;
|
|
12
|
-
return
|
|
124
|
+
return canonicalJson(readFingerprint(hf)) === canonicalJson({
|
|
125
|
+
type: hf.type,
|
|
126
|
+
content: hf.content,
|
|
127
|
+
watermark: hf.watermark,
|
|
128
|
+
watermarkBlockIndex: hf.watermarkBlockIndex,
|
|
129
|
+
rawWatermarkXml: hf.rawWatermarkXml
|
|
130
|
+
});
|
|
13
131
|
};
|
|
14
132
|
const assignHeaderFooterVerbatimXml = (hf, xml) => {
|
|
15
133
|
const ext = hf;
|
|
16
134
|
ext.verbatimXml = xml;
|
|
17
135
|
ext.verbatimFingerprint = headerFooterSerializationFingerprint(hf);
|
|
136
|
+
captureContentBaseline(hf);
|
|
18
137
|
};
|
|
19
138
|
const refreshHeaderFooterVerbatimFingerprint = (hf) => {
|
|
20
139
|
const ext = hf;
|
|
21
140
|
if (!ext.verbatimXml) return;
|
|
22
141
|
ext.verbatimFingerprint = headerFooterSerializationFingerprint(hf);
|
|
142
|
+
captureContentBaseline(hf);
|
|
23
143
|
};
|
|
24
144
|
const clearHeaderFooterVerbatimXml = (hf) => {
|
|
25
145
|
const ext = hf;
|
|
26
146
|
delete ext.verbatimXml;
|
|
27
147
|
delete ext.verbatimFingerprint;
|
|
148
|
+
Reflect.deleteProperty(hf, BASELINE_HANDLE);
|
|
149
|
+
};
|
|
150
|
+
/** Capture the body in the same trusted package registry as secondary stories. */
|
|
151
|
+
const captureDocumentSourceBaseline = (document, xml) => {
|
|
152
|
+
const body = structuredClone(document.package.document);
|
|
153
|
+
const handle = {};
|
|
154
|
+
contentBaselines.set(handle, {
|
|
155
|
+
type: "body",
|
|
156
|
+
fingerprint: { type: "pending" },
|
|
157
|
+
xml,
|
|
158
|
+
body,
|
|
159
|
+
resourceStyles: structuredClone(document.package.styles),
|
|
160
|
+
resourceRelationships: structuredClone(document.package.relationships),
|
|
161
|
+
resourceMedia: new Map([...document.package.media ?? []].map(([path, media]) => [path, {
|
|
162
|
+
data: media.data,
|
|
163
|
+
mimeType: media.mimeType
|
|
164
|
+
}]))
|
|
165
|
+
});
|
|
166
|
+
Object.defineProperty(document.package.document, BASELINE_HANDLE, {
|
|
167
|
+
value: handle,
|
|
168
|
+
enumerable: true,
|
|
169
|
+
configurable: true
|
|
170
|
+
});
|
|
171
|
+
if (document.originalBuffer) {
|
|
172
|
+
const registry = packageBaselines.get(document.originalBuffer) ?? /* @__PURE__ */ new Map();
|
|
173
|
+
registry.set("word/document.xml", /* @__PURE__ */ new Map([["body", handle]]));
|
|
174
|
+
packageBaselines.set(document.originalBuffer, registry);
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
const getDocumentSourceBaseline = (document) => {
|
|
178
|
+
const body = document.package.document;
|
|
179
|
+
const handle = BASELINE_HANDLE in body ? body[BASELINE_HANDLE] : document.originalBuffer && packageBaselines.get(document.originalBuffer)?.get("word/document.xml")?.get("body");
|
|
180
|
+
if (handle === void 0) return { type: "missing" };
|
|
181
|
+
if (typeof handle !== "object" || handle === null) return { type: "mismatch" };
|
|
182
|
+
const baseline = contentBaselines.get(handle);
|
|
183
|
+
if (!baseline || baseline.type !== "body") return { type: "mismatch" };
|
|
184
|
+
const fingerprint = JSON.stringify(baseline.body);
|
|
185
|
+
if (baseline.fingerprint.type === "pending") baseline.fingerprint = {
|
|
186
|
+
type: "captured",
|
|
187
|
+
value: fingerprint
|
|
188
|
+
};
|
|
189
|
+
if (baseline.fingerprint.value !== fingerprint) return { type: "mismatch" };
|
|
190
|
+
return {
|
|
191
|
+
type: "captured",
|
|
192
|
+
body: baseline.body,
|
|
193
|
+
xml: baseline.xml,
|
|
194
|
+
fingerprint,
|
|
195
|
+
resourceStyles: baseline.resourceStyles,
|
|
196
|
+
resourceRelationships: baseline.resourceRelationships,
|
|
197
|
+
resourceMedia: baseline.resourceMedia
|
|
198
|
+
};
|
|
28
199
|
};
|
|
29
200
|
//#endregion
|
|
30
|
-
export { assignHeaderFooterVerbatimXml, canReplayHeaderFooterVerbatim, clearHeaderFooterVerbatimXml, getHeaderFooterVerbatimXml, refreshHeaderFooterVerbatimFingerprint };
|
|
201
|
+
export { assignHeaderFooterVerbatimXml, canReplayHeaderFooterBlocks, canReplayHeaderFooterVerbatim, captureDocumentSourceBaseline, captureHeaderFooterPackageBaselines, clearHeaderFooterVerbatimXml, copyHeaderFooterBaselineHandles, copyHeaderFooterPackageBaselines, getDocumentSourceBaseline, getHeaderFooterSourceBaseline, getHeaderFooterVerbatimXml, refreshHeaderFooterVerbatimFingerprint };
|
|
@@ -22,6 +22,18 @@ declare function resolveImageData(rId: string | undefined, rels: document_d_expo
|
|
|
22
22
|
mimeType?: string;
|
|
23
23
|
filename?: string;
|
|
24
24
|
};
|
|
25
|
+
type ImageDerivedFactsOptions = {
|
|
26
|
+
id: string | undefined;
|
|
27
|
+
pictureNames: NonNullable<document_d_exports.Image["pictureNames"]>;
|
|
28
|
+
imageData: ReturnType<typeof resolveImageData>;
|
|
29
|
+
};
|
|
30
|
+
/** Facts the parser obtains from exported drawing markup and image relationships. */
|
|
31
|
+
declare const imageDerivedFactsOf: ({ id, pictureNames, imageData }: ImageDerivedFactsOptions) => {
|
|
32
|
+
filename?: string;
|
|
33
|
+
mimeType?: string;
|
|
34
|
+
pictureNames?: import("@stll/docx-core/model").NonVisualDrawingNames;
|
|
35
|
+
id?: string;
|
|
36
|
+
};
|
|
25
37
|
/**
|
|
26
38
|
* Parse a w:drawing element
|
|
27
39
|
*
|
|
@@ -97,4 +109,4 @@ declare function getWrapDistancesPx(image: document_d_exports.Image): {
|
|
|
97
109
|
*/
|
|
98
110
|
declare function needsTextWrapping(image: document_d_exports.Image): boolean;
|
|
99
111
|
//#endregion
|
|
100
|
-
export { DECORATIVE_EXTENSION_URI, DECORATIVE_NAMESPACE, getImageDimensionsPx, getImageHeightPx, getImageWidthPx, getWrapDistancesPx, hasAltText, isBehindText, isDecorativeImage, isFloatingImage, isInFrontOfText, isInlineImage, needsTextWrapping, parseDrawing, parseImage, resolveImageData };
|
|
112
|
+
export { DECORATIVE_EXTENSION_URI, DECORATIVE_NAMESPACE, getImageDimensionsPx, getImageHeightPx, getImageWidthPx, getWrapDistancesPx, hasAltText, imageDerivedFactsOf, isBehindText, isDecorativeImage, isFloatingImage, isInFrontOfText, isInlineImage, needsTextWrapping, parseDrawing, parseImage, resolveImageData };
|