@stll/folio-core 0.54.2 → 0.55.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 +22 -1
- package/dist/ai-edits/headless.js +1 -0
- package/dist/compare/content-types.d.ts +3 -15
- package/dist/controller/canonicalComposition.d.ts +36 -0
- package/dist/controller/canonicalComposition.js +168 -0
- package/dist/controller/canonicalInput.d.ts +45 -0
- package/dist/controller/canonicalInput.js +338 -0
- package/dist/controller/canonicalOperations.d.ts +22 -0
- package/dist/controller/canonicalOperations.js +85 -0
- package/dist/controller/canonicalReview.d.ts +12 -0
- package/dist/controller/canonicalReview.js +19 -0
- package/dist/controller/canonicalSession.d.ts +149 -0
- package/dist/controller/canonicalSession.js +1038 -0
- package/dist/controller/canonicalStoryEditor.d.ts +34 -0
- package/dist/controller/canonicalStoryEditor.js +82 -0
- package/dist/controller/canonicalStructure.d.ts +16 -0
- package/dist/controller/canonicalStructure.js +269 -0
- package/dist/controller/folioEditor.d.ts +1 -1
- package/dist/controller/folioEditor.js +9 -0
- package/dist/controller/headerFooterEditorManager.d.ts +4 -0
- package/dist/controller/headerFooterEditorManager.js +71 -3
- package/dist/controller/hiddenEditorApi.d.ts +35 -0
- package/dist/controller/hiddenEditorApi.js +25 -8
- package/dist/controller/hiddenEditorManager.d.ts +11 -2
- package/dist/controller/hiddenEditorManager.js +456 -30
- package/dist/controller/layoutPipeline.d.ts +1 -1
- package/dist/controller/layoutPipeline.js +2 -0
- package/dist/controller/noteEditorManager.d.ts +4 -0
- package/dist/controller/noteEditorManager.js +113 -15
- package/dist/docx/attributeRemainder.js +1 -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 +41 -0
- package/dist/docx/contentTypeRegistry.d.ts +8 -0
- package/dist/docx/contentTypeRegistry.js +64 -0
- package/dist/docx/ensureParaIds.d.ts +7 -1
- package/dist/docx/ensureParaIds.js +163 -211
- package/dist/docx/foldedListNumberFields.d.ts +85 -0
- package/dist/docx/foldedListNumberFields.js +267 -0
- package/dist/docx/headerFooterVerbatim.d.ts +14 -1
- package/dist/docx/headerFooterVerbatim.js +95 -2
- 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 +65 -16
- 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 +76 -22
- package/dist/docx/parser.js +2 -1
- 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 +7 -3
- package/dist/docx/rezip.js +107 -45
- 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 +11 -0
- package/dist/docx/saveDiagnostics.js +0 -0
- package/dist/docx/selectiveSave.d.ts +2 -1
- package/dist/docx/selectiveSave.js +4 -1
- package/dist/docx/selectiveXmlPatch.d.ts +16 -8
- package/dist/docx/selectiveXmlPatch.js +74 -2
- 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/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 +11 -0
- package/dist/docx/storyBlockReplay.js +367 -0
- package/dist/docx/streamingXmlParser.d.ts +22 -1
- package/dist/docx/streamingXmlParser.js +49 -3
- package/dist/docx/structuralXmlPatch.js +8 -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/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 +8 -1
- package/dist/markdown/renderBlock.js +15 -1
- package/dist/markdown/renderParagraph.js +9 -13
- package/dist/markdown/renderRuns.js +3 -2
- 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 +97 -0
- package/dist/prosemirror/canonicalCommands.js +28 -0
- package/dist/prosemirror/commands/pageBreak.js +15 -1
- package/dist/prosemirror/commentReferenceAttrs.d.ts +2 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +91 -19
- package/dist/prosemirror/conversion/listRenderingDefinition.d.ts +6 -0
- package/dist/prosemirror/conversion/listRenderingDefinition.js +97 -0
- package/dist/prosemirror/conversion/toProseDoc.d.ts +4 -3
- package/dist/prosemirror/conversion/toProseDoc.js +51 -11
- 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 +50 -19
- 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/TextColorExtension.js +3 -2
- package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +2 -0
- package/dist/prosemirror/extensions/marks/markUtils.js +70 -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/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/plugins/suggestionMode.js +50 -2
- 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/content.d.ts +2 -2
- package/dist/utils/createDocument.js +2 -2
- package/package.json +14 -2
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { isSeparatorEndnote, isSeparatorFootnote } from "../docx/footnoteParser.js";
|
|
2
|
+
import { cloneDocumentWithParagraphPropertySources } from "../docx/paragraphPropertySource.js";
|
|
3
|
+
import { visitDocxParagraphs, visitParagraphRuns } from "../docx/paragraphTraversal.js";
|
|
2
4
|
import { proseDocToBlocks } from "../prosemirror/conversion/fromProseDoc.js";
|
|
3
5
|
import { footnoteToProseDoc } from "../prosemirror/conversion/toProseDoc.js";
|
|
4
6
|
import { ExtensionManager } from "../prosemirror/extensions/ExtensionManager.js";
|
|
@@ -9,7 +11,9 @@ import { createDocumentNumberingPlugin } from "../prosemirror/plugins/documentNu
|
|
|
9
11
|
import { createDocumentStylesPlugin } from "../prosemirror/plugins/documentStyles.js";
|
|
10
12
|
import { schema } from "../prosemirror/schema/index.js";
|
|
11
13
|
import { storyListNumbering } from "../prosemirror/storyListNumbering.js";
|
|
12
|
-
import {
|
|
14
|
+
import { createCanonicalStoryEditor } from "./canonicalStoryEditor.js";
|
|
15
|
+
import { OP_STORIES } from "@stll/docx-core/ops";
|
|
16
|
+
import { EditorState, TextSelection } from "prosemirror-state";
|
|
13
17
|
import { EditorView } from "prosemirror-view";
|
|
14
18
|
//#region src/controller/noteEditorManager.ts
|
|
15
19
|
/** Framework-neutral lifecycle owner for editable footnote and endnote stories. */
|
|
@@ -28,12 +32,7 @@ const enumerateDocumentNoteStories = (document) => [...(document?.package.footno
|
|
|
28
32
|
const resolveNote = (document, story) => {
|
|
29
33
|
return (story.kind === "footnote" ? document?.package.footnotes : document?.package.endnotes)?.find(({ id }) => id === story.noteId) ?? null;
|
|
30
34
|
};
|
|
31
|
-
const noteToProseDocument = (note,
|
|
32
|
-
const options = {};
|
|
33
|
-
if (styles) options.styles = styles;
|
|
34
|
-
if (theme !== void 0) options.theme = theme;
|
|
35
|
-
return footnoteToProseDoc(note.content, options);
|
|
36
|
-
};
|
|
35
|
+
const noteToProseDocument = (note, options) => footnoteToProseDoc(note.content, options);
|
|
37
36
|
const buildInitialState = (document, styles, numbering, manager, externalPlugins) => {
|
|
38
37
|
return ensureBaseDirectionInState(ensureParaIdsInState(EditorState.create({
|
|
39
38
|
doc: document,
|
|
@@ -46,6 +45,31 @@ const buildInitialState = (document, styles, numbering, manager, externalPlugins
|
|
|
46
45
|
]
|
|
47
46
|
})));
|
|
48
47
|
};
|
|
48
|
+
/** Automatic note marks have no PM width; retain their authored runs on default writeback. */
|
|
49
|
+
const preserveNoteMarkers = ({ source, projected }) => {
|
|
50
|
+
const marks = [];
|
|
51
|
+
visitDocxParagraphs({ documentBody: { content: source } }, (paragraph) => visitParagraphRuns(paragraph, (run) => {
|
|
52
|
+
const content = run.content.filter((child) => child.type === "noteMarker");
|
|
53
|
+
if (content.length > 0) marks.push({
|
|
54
|
+
...run,
|
|
55
|
+
content
|
|
56
|
+
});
|
|
57
|
+
}));
|
|
58
|
+
if (marks.length === 0) return projected;
|
|
59
|
+
let hasMarker = false;
|
|
60
|
+
visitDocxParagraphs({ documentBody: { content: projected } }, (paragraph) => visitParagraphRuns(paragraph, (run) => {
|
|
61
|
+
if (run.content.some((child) => child.type === "noteMarker")) hasMarker = true;
|
|
62
|
+
}));
|
|
63
|
+
if (hasMarker) return projected;
|
|
64
|
+
const owned = cloneDocumentWithParagraphPropertySources({ package: { document: { content: projected } } }).package.document.content;
|
|
65
|
+
const paragraphs = [];
|
|
66
|
+
visitDocxParagraphs({ documentBody: { content: owned } }, (paragraph) => {
|
|
67
|
+
paragraphs.push(paragraph);
|
|
68
|
+
});
|
|
69
|
+
const first = paragraphs.at(0);
|
|
70
|
+
if (first) first.content.unshift(...marks);
|
|
71
|
+
return owned;
|
|
72
|
+
};
|
|
49
73
|
const createNoteEditorManager = (deps) => {
|
|
50
74
|
const mounted = /* @__PURE__ */ new Map();
|
|
51
75
|
let active = null;
|
|
@@ -66,10 +90,16 @@ const createNoteEditorManager = (deps) => {
|
|
|
66
90
|
const sync = () => {
|
|
67
91
|
const host = deps.getHost();
|
|
68
92
|
if (!host) return;
|
|
69
|
-
|
|
93
|
+
if (deps.getExperimentalSession?.() === "canonical" && !deps.getCanonicalApi?.()?.getCanonicalStoryProjection(OP_STORIES.MAIN)) return;
|
|
94
|
+
const document = deps.getExperimentalSession?.() === "canonical" ? deps.getCanonicalApi?.()?.getCanonicalDocument() ?? deps.getDocument() : deps.getDocument();
|
|
70
95
|
const styles = deps.getStyles();
|
|
71
96
|
const theme = deps.getTheme();
|
|
72
97
|
const numbering = document?.package.numbering;
|
|
98
|
+
const proseOptions = {
|
|
99
|
+
...styles ? { styles } : {},
|
|
100
|
+
...theme !== void 0 ? { theme } : {},
|
|
101
|
+
...numbering !== void 0 ? { numbering } : {}
|
|
102
|
+
};
|
|
73
103
|
const externalPlugins = deps.getPlugins?.() ?? EMPTY_PLUGINS;
|
|
74
104
|
const wanted = new Map(enumerateDocumentNoteStories(document).map((story) => [storyMapKey(story), story]));
|
|
75
105
|
const activeKey = active ? storyMapKey(active) : null;
|
|
@@ -85,7 +115,33 @@ const createNoteEditorManager = (deps) => {
|
|
|
85
115
|
const existing = mounted.get(key);
|
|
86
116
|
if (existing) {
|
|
87
117
|
if (existing.mountNode.parentElement !== host) host.append(existing.mountNode);
|
|
88
|
-
|
|
118
|
+
if (deps.getExperimentalSession?.() === "canonical") {
|
|
119
|
+
const projected = deps.getCanonicalApi?.()?.getCanonicalStoryProjection({
|
|
120
|
+
kind: storyKey.kind,
|
|
121
|
+
id: storyKey.noteId
|
|
122
|
+
});
|
|
123
|
+
if (projected && !existing.view.state.doc.eq(projected)) {
|
|
124
|
+
const transaction = existing.view.state.tr.replaceWith(0, existing.view.state.doc.content.size, projected.content);
|
|
125
|
+
const restored = deps.getCanonicalApi?.()?.getCanonicalStorySelection({
|
|
126
|
+
kind: storyKey.kind,
|
|
127
|
+
id: storyKey.noteId
|
|
128
|
+
});
|
|
129
|
+
const anchor = Math.min(existing.view.state.selection.anchor, projected.content.size);
|
|
130
|
+
transaction.setSelection(restored ? TextSelection.create(transaction.doc, restored.anchor, restored.head) : TextSelection.near(transaction.doc.resolve(anchor)));
|
|
131
|
+
transaction.setMeta("addToHistory", false);
|
|
132
|
+
existing.view.updateState(existing.view.state.apply(transaction));
|
|
133
|
+
}
|
|
134
|
+
existing.appliedNote = note;
|
|
135
|
+
existing.appliedContent = note.content;
|
|
136
|
+
existing.appliedProseDocument = existing.view.state.doc;
|
|
137
|
+
existing.appliedStyles = styles;
|
|
138
|
+
existing.appliedTheme = theme;
|
|
139
|
+
existing.appliedNumbering = numbering;
|
|
140
|
+
existing.appliedPlugins = externalPlugins;
|
|
141
|
+
existing.dirty = false;
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
const nextProseDocument = noteToProseDocument(note, proseOptions);
|
|
89
145
|
const contextIsCurrent = existing.appliedStyles === styles && existing.appliedTheme === theme && existing.appliedNumbering === numbering && existing.appliedPlugins === externalPlugins;
|
|
90
146
|
if ((existing.appliedNote === note && existing.appliedContent === note.content || existing.appliedProseDocument.eq(nextProseDocument)) && contextIsCurrent) {
|
|
91
147
|
existing.appliedNote = note;
|
|
@@ -111,10 +167,40 @@ const createNoteEditorManager = (deps) => {
|
|
|
111
167
|
mountNode.dataset["noteKind"] = storyKey.kind;
|
|
112
168
|
mountNode.dataset["noteId"] = String(storyKey.noteId);
|
|
113
169
|
host.append(mountNode);
|
|
114
|
-
const proseDocument = noteToProseDocument(note,
|
|
170
|
+
const proseDocument = noteToProseDocument(note, proseOptions);
|
|
171
|
+
const canonical = createCanonicalStoryEditor({
|
|
172
|
+
story: {
|
|
173
|
+
kind: storyKey.kind,
|
|
174
|
+
id: storyKey.noteId
|
|
175
|
+
},
|
|
176
|
+
getView: () => view,
|
|
177
|
+
getApi: () => deps.getCanonicalApi?.() ?? null,
|
|
178
|
+
enabled: () => deps.getExperimentalSession?.() === "canonical",
|
|
179
|
+
onRefusal: deps.onSessionRefusal,
|
|
180
|
+
onSelectionChange: () => deps.onTransaction?.({
|
|
181
|
+
...storyKey,
|
|
182
|
+
view,
|
|
183
|
+
docChanged: false,
|
|
184
|
+
selectionChanged: true
|
|
185
|
+
})
|
|
186
|
+
});
|
|
187
|
+
const canonicalProjection = deps.getExperimentalSession?.() === "canonical" ? deps.getCanonicalApi?.()?.getCanonicalStoryProjection({
|
|
188
|
+
kind: storyKey.kind,
|
|
189
|
+
id: storyKey.noteId
|
|
190
|
+
}) : null;
|
|
191
|
+
if (deps.getExperimentalSession?.() === "canonical" && !canonicalProjection) {
|
|
192
|
+
manager.destroy();
|
|
193
|
+
mountNode.remove();
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
115
196
|
const view = (deps.createView ?? createEditorView)(mountNode, {
|
|
116
|
-
|
|
197
|
+
...canonical.props,
|
|
198
|
+
state: canonicalProjection ? EditorState.create({
|
|
199
|
+
doc: canonicalProjection,
|
|
200
|
+
plugins: [createDocumentStylesPlugin(styles), createDocumentNumberingPlugin(numbering)]
|
|
201
|
+
}) : buildInitialState(proseDocument, styles, numbering, manager, externalPlugins),
|
|
117
202
|
dispatchTransaction(transaction) {
|
|
203
|
+
if (canonical.dispatch(transaction)) return;
|
|
118
204
|
view.updateState(view.state.apply(transaction));
|
|
119
205
|
const mountedStory = mounted.get(key);
|
|
120
206
|
if (mountedStory && transaction.docChanged) mountedStory.dirty = true;
|
|
@@ -160,6 +246,7 @@ const createNoteEditorManager = (deps) => {
|
|
|
160
246
|
getView: (story) => mounted.get(storyMapKey(story))?.view ?? null,
|
|
161
247
|
listStories: () => enumerateDocumentNoteStories(deps.getDocument()),
|
|
162
248
|
snapshotDocument: (document) => {
|
|
249
|
+
if (deps.getExperimentalSession?.() === "canonical") return deps.getCanonicalApi?.()?.getCanonicalDocument() ?? document;
|
|
163
250
|
let footnotes = document.package.footnotes;
|
|
164
251
|
let endnotes = document.package.endnotes;
|
|
165
252
|
let footnotesChanged = false;
|
|
@@ -169,6 +256,11 @@ const createNoteEditorManager = (deps) => {
|
|
|
169
256
|
if (!story.dirty) continue;
|
|
170
257
|
const lists = storyListNumbering(story.view.state, numbering);
|
|
171
258
|
numbering = lists.numbering;
|
|
259
|
+
const proseOptions = {
|
|
260
|
+
...story.appliedStyles ? { styles: story.appliedStyles } : {},
|
|
261
|
+
...story.appliedTheme !== void 0 ? { theme: story.appliedTheme } : {},
|
|
262
|
+
...numbering !== void 0 ? { numbering } : {}
|
|
263
|
+
};
|
|
172
264
|
if (story.note.kind === "footnote") {
|
|
173
265
|
const index = footnotes?.findIndex(({ id }) => id === story.note.noteId) ?? -1;
|
|
174
266
|
const current = index === -1 ? null : footnotes?.at(index);
|
|
@@ -179,12 +271,15 @@ const createNoteEditorManager = (deps) => {
|
|
|
179
271
|
}
|
|
180
272
|
const updated = {
|
|
181
273
|
...current,
|
|
182
|
-
content:
|
|
274
|
+
content: preserveNoteMarkers({
|
|
275
|
+
source: current.content,
|
|
276
|
+
projected: proseDocToBlocks(lists.doc, current.content, document.package.styles)
|
|
277
|
+
})
|
|
183
278
|
};
|
|
184
279
|
footnotes[index] = updated;
|
|
185
280
|
story.appliedNote = updated;
|
|
186
281
|
story.appliedContent = updated.content;
|
|
187
|
-
story.appliedProseDocument = noteToProseDocument(updated,
|
|
282
|
+
story.appliedProseDocument = noteToProseDocument(updated, proseOptions);
|
|
188
283
|
continue;
|
|
189
284
|
}
|
|
190
285
|
const index = endnotes?.findIndex(({ id }) => id === story.note.noteId) ?? -1;
|
|
@@ -196,12 +291,15 @@ const createNoteEditorManager = (deps) => {
|
|
|
196
291
|
}
|
|
197
292
|
const updated = {
|
|
198
293
|
...current,
|
|
199
|
-
content:
|
|
294
|
+
content: preserveNoteMarkers({
|
|
295
|
+
source: current.content,
|
|
296
|
+
projected: proseDocToBlocks(lists.doc, current.content, document.package.styles)
|
|
297
|
+
})
|
|
200
298
|
};
|
|
201
299
|
endnotes[index] = updated;
|
|
202
300
|
story.appliedNote = updated;
|
|
203
301
|
story.appliedContent = updated.content;
|
|
204
|
-
story.appliedProseDocument = noteToProseDocument(updated,
|
|
302
|
+
story.appliedProseDocument = noteToProseDocument(updated, proseOptions);
|
|
205
303
|
}
|
|
206
304
|
if (!footnotesChanged && !endnotesChanged) return document;
|
|
207
305
|
return {
|
|
@@ -55,6 +55,7 @@ const attributeRemainder = ({ element, modelled }) => {
|
|
|
55
55
|
const name = getLocalName(spelling);
|
|
56
56
|
if (modelled.has(name)) continue;
|
|
57
57
|
const namespace = resolveAttributeNamespaceUri(element, spelling);
|
|
58
|
+
if (namespace === OOXML_NAMESPACES.mc.uri && name === "Ignorable") continue;
|
|
58
59
|
if (namespace !== void 0 && !CANONICAL_PREFIX.has(namespace)) continue;
|
|
59
60
|
remainder.push({
|
|
60
61
|
...namespace === void 0 ? {} : { namespace },
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { DocxInput } from "../utils/docxInput.js";
|
|
2
|
+
//#region src/docx/canonicalSessionInput.d.ts
|
|
3
|
+
declare const CanonicalDocxInputError_base: import("better-result").TaggedErrorClass<"CanonicalDocxInputError">;
|
|
4
|
+
declare class CanonicalDocxInputError extends CanonicalDocxInputError_base<{
|
|
5
|
+
message: string;
|
|
6
|
+
cause?: unknown;
|
|
7
|
+
}> {}
|
|
8
|
+
/** Canonical seeding supports plaintext packages; refuse encryption before ZIP normalization. */
|
|
9
|
+
declare const prepareCanonicalDocxInput: (input: DocxInput) => Promise<import("better-result").Err<ArrayBuffer, CanonicalDocxInputError> | import("better-result").Ok<Uint8Array<ArrayBufferLike>, CanonicalDocxInputError>>;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { CanonicalDocxInputError, prepareCanonicalDocxInput };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { toArrayBuffer } from "../utils/docxInput.js";
|
|
2
|
+
import { DOCX_CONTAINER_TYPES, detectDocxContainerType } from "./encryption/containerFormat.js";
|
|
3
|
+
import { ensureParaIds } from "./ensureParaIds.js";
|
|
4
|
+
import { Result, TaggedError } from "better-result";
|
|
5
|
+
//#region src/docx/canonicalSessionInput.ts
|
|
6
|
+
var CanonicalDocxInputError = class extends TaggedError("CanonicalDocxInputError") {};
|
|
7
|
+
/** Canonical seeding supports plaintext packages; refuse encryption before ZIP normalization. */
|
|
8
|
+
const prepareCanonicalDocxInput = async (input) => {
|
|
9
|
+
const bytes = await Result.tryPromise({
|
|
10
|
+
try: () => toArrayBuffer(input),
|
|
11
|
+
catch: (cause) => new CanonicalDocxInputError({
|
|
12
|
+
message: "Cannot read canonical document bytes.",
|
|
13
|
+
cause
|
|
14
|
+
})
|
|
15
|
+
});
|
|
16
|
+
if (bytes.isErr()) return bytes;
|
|
17
|
+
if (detectDocxContainerType(bytes.value) === DOCX_CONTAINER_TYPES.CFB) return Result.err(new CanonicalDocxInputError({ message: "Password-protected documents are unavailable in the experimental canonical session." }));
|
|
18
|
+
return Result.tryPromise({
|
|
19
|
+
try: async () => (await ensureParaIds(bytes.value)).docx,
|
|
20
|
+
catch: (cause) => new CanonicalDocxInputError({
|
|
21
|
+
message: cause instanceof Error ? cause.message : "Canonical document normalization failed.",
|
|
22
|
+
cause
|
|
23
|
+
})
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
//#endregion
|
|
27
|
+
export { CanonicalDocxInputError, prepareCanonicalDocxInput };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { document_d_exports } from "../types/document.js";
|
|
2
|
+
//#region src/docx/canonicalStoryRepack.d.ts
|
|
3
|
+
type CanonicalStoryRepackOptions<T> = {
|
|
4
|
+
document: document_d_exports.Document;
|
|
5
|
+
repack: () => Promise<T>;
|
|
6
|
+
};
|
|
7
|
+
/** Authorize only references missing from the committed canonical snapshot, with exact multiplicity. */
|
|
8
|
+
declare const repackWithCanonicalStoryRemovals: <T>({ document, repack }: CanonicalStoryRepackOptions<T>) => Promise<T>;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { repackWithCanonicalStoryRemovals };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { withSectionReferenceResolution } from "../internal/sectionReferenceResolution.js";
|
|
2
|
+
import { readDocumentSectionFacts } from "./documentSectionFacts.js";
|
|
3
|
+
import { serializeDocument } from "./serializer/documentSerializer.js";
|
|
4
|
+
import JSZip from "jszip";
|
|
5
|
+
//#region src/docx/canonicalStoryRepack.ts
|
|
6
|
+
/** Canonical snapshots own explicit section references; the PM projection does not. */
|
|
7
|
+
const referenceKey = ({ element, type, rId }) => `${element}:${type}:${rId}`;
|
|
8
|
+
/** Authorize only references missing from the committed canonical snapshot, with exact multiplicity. */
|
|
9
|
+
const repackWithCanonicalStoryRemovals = async ({ document, repack }) => {
|
|
10
|
+
if (!document.originalBuffer) return repack();
|
|
11
|
+
const xml = await (await JSZip.loadAsync(document.originalBuffer)).file("word/document.xml")?.async("text");
|
|
12
|
+
if (!xml) return repack();
|
|
13
|
+
const before = readDocumentSectionFacts(xml);
|
|
14
|
+
const after = readDocumentSectionFacts(serializeDocument(document));
|
|
15
|
+
const remaining = /* @__PURE__ */ new Map();
|
|
16
|
+
for (const reference of after.headerFooterReferences) {
|
|
17
|
+
const key = referenceKey(reference);
|
|
18
|
+
remaining.set(key, (remaining.get(key) ?? 0) + 1);
|
|
19
|
+
}
|
|
20
|
+
const removedReferences = [];
|
|
21
|
+
for (const reference of before.headerFooterReferences) {
|
|
22
|
+
const key = referenceKey(reference);
|
|
23
|
+
const count = remaining.get(key) ?? 0;
|
|
24
|
+
if (count > 0) {
|
|
25
|
+
remaining.set(key, count - 1);
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
removedReferences.push({
|
|
29
|
+
part: reference.element === "headerReference" ? "header" : "footer",
|
|
30
|
+
type: reference.type,
|
|
31
|
+
relationshipId: reference.rId
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return withSectionReferenceResolution({
|
|
35
|
+
document,
|
|
36
|
+
removedReferences,
|
|
37
|
+
repack
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
//#endregion
|
|
41
|
+
export { repackWithCanonicalStoryRemovals };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/docx/contentTypeRegistry.d.ts
|
|
2
|
+
type ContentTypePart = {
|
|
3
|
+
partName: string;
|
|
4
|
+
contentType: string;
|
|
5
|
+
};
|
|
6
|
+
declare const registerContentTypeParts: (xml: string, parts: readonly ContentTypePart[]) => string;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { registerContentTypeParts };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { resolvePackageRelationshipTarget } from "./packageParts.js";
|
|
2
|
+
import { spliceXml } from "./selectiveXmlPatch.js";
|
|
3
|
+
import { getAttribute, getLocalName, getNamespacePrefix, getNamespaceUri, parseXmlDocument } from "./xmlParser.js";
|
|
4
|
+
import { panic } from "better-result";
|
|
5
|
+
import { escapeXmlAttribute } from "@stll/docx-core";
|
|
6
|
+
import { OOXML_NS } from "@stll/docx-utils";
|
|
7
|
+
//#region src/docx/contentTypeRegistry.ts
|
|
8
|
+
/** Register a package part without rewriting authored content-type entries. */
|
|
9
|
+
const registerContentTypeParts = (xml, parts) => {
|
|
10
|
+
const root = parseXmlDocument(xml);
|
|
11
|
+
if (root?.name === void 0 || getLocalName(root.name) !== "Types" || getNamespaceUri(root) !== OOXML_NS.ct) return panic("The package content-type registry must have a valid Types root.");
|
|
12
|
+
const overrides = /* @__PURE__ */ new Map();
|
|
13
|
+
const defaults = /* @__PURE__ */ new Map();
|
|
14
|
+
for (const element of root.elements ?? []) {
|
|
15
|
+
if (getNamespaceUri(element) !== OOXML_NS.ct) continue;
|
|
16
|
+
const type = getAttribute(element, null, "ContentType");
|
|
17
|
+
if (type === null) continue;
|
|
18
|
+
if (getLocalName(element.name) === "Override") {
|
|
19
|
+
const name = getAttribute(element, null, "PartName");
|
|
20
|
+
const path = name === null ? void 0 : resolvePackageRelationshipTarget(name, "_rels/.rels");
|
|
21
|
+
if (path !== void 0) overrides.set(path, type);
|
|
22
|
+
}
|
|
23
|
+
if (getLocalName(element.name) === "Default") {
|
|
24
|
+
const extension = getAttribute(element, null, "Extension");
|
|
25
|
+
if (extension !== null) defaults.set(extension.toLowerCase(), type);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const prefix = getNamespacePrefix(root.name);
|
|
29
|
+
const name = prefix ? `${prefix}:Override` : "Override";
|
|
30
|
+
const additions = [];
|
|
31
|
+
for (const part of parts) {
|
|
32
|
+
const path = resolvePackageRelationshipTarget(part.partName, "_rels/.rels");
|
|
33
|
+
if (path === void 0) return panic("A registered part must have a safe package URI.");
|
|
34
|
+
const type = overrides.get(path);
|
|
35
|
+
if (type !== void 0) {
|
|
36
|
+
if (type !== part.contentType) return panic("A part's registered content type cannot change.");
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const extension = path.slice(path.lastIndexOf(".") + 1);
|
|
40
|
+
if (defaults.get(extension) === part.contentType) continue;
|
|
41
|
+
additions.push(`<${name} PartName="${escapeXmlAttribute(part.partName)}" ContentType="${escapeXmlAttribute(part.contentType)}"/>`);
|
|
42
|
+
overrides.set(path, part.contentType);
|
|
43
|
+
}
|
|
44
|
+
if (additions.length === 0) return xml;
|
|
45
|
+
for (const token of xml.matchAll(/<!--[\s\S]*?-->|<\?[\s\S]*?\?>|<!\[CDATA\[[\s\S]*?\]\]>|<(?:"[^"]*"|'[^']*'|[^'">])*>/gu)) {
|
|
46
|
+
const markup = token[0];
|
|
47
|
+
if (markup.startsWith("</") && markup.slice(2, -1).trim() === root.name) return spliceXml(xml, [{
|
|
48
|
+
start: token.index,
|
|
49
|
+
end: token.index,
|
|
50
|
+
newXml: additions.join("")
|
|
51
|
+
}]) ?? panic("A registry insertion must preserve XML ranges.");
|
|
52
|
+
if (markup.startsWith(`<${root.name}`) && /[\s/>]/u.test(markup.charAt(root.name.length + 1)) && markup.endsWith("/>")) {
|
|
53
|
+
const end = token.index + markup.length - 2;
|
|
54
|
+
return spliceXml(xml, [{
|
|
55
|
+
start: end,
|
|
56
|
+
end: end + 2,
|
|
57
|
+
newXml: ">" + additions.join("") + `</${root.name}>`
|
|
58
|
+
}]) ?? panic("A registry insertion must preserve XML ranges.");
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return panic("A content-type registry needs a closing root boundary.");
|
|
62
|
+
};
|
|
63
|
+
//#endregion
|
|
64
|
+
export { registerContentTypeParts };
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
//#region src/docx/ensureParaIds.d.ts
|
|
2
|
+
declare const ENSURE_PARA_IDS_REASONS: {
|
|
3
|
+
readonly NORMALIZATION_FAILED: "normalization-failed";
|
|
4
|
+
readonly NAMESPACE_INVALID: "namespace-invalid";
|
|
5
|
+
readonly SIGNED_PACKAGE: "signed-package";
|
|
6
|
+
};
|
|
2
7
|
declare const EnsureParaIdsError_base: import("better-result").TaggedErrorClass<"EnsureParaIdsError">;
|
|
3
8
|
/** A malformed or unsupported package prevented paragraph-ID normalization. */
|
|
4
9
|
declare class EnsureParaIdsError extends EnsureParaIdsError_base<{
|
|
5
10
|
message: string;
|
|
11
|
+
reason: (typeof ENSURE_PARA_IDS_REASONS)[keyof typeof ENSURE_PARA_IDS_REASONS];
|
|
6
12
|
cause?: unknown;
|
|
7
13
|
}> {}
|
|
8
14
|
/** Counts and normalized bytes returned by {@link ensureParaIds}. */
|
|
@@ -35,4 +41,4 @@ type EnsureParaIdsOptions = {
|
|
|
35
41
|
*/
|
|
36
42
|
declare const ensureParaIds: (docx: Uint8Array | ArrayBuffer, options?: EnsureParaIdsOptions) => Promise<EnsureParaIdsResult>;
|
|
37
43
|
//#endregion
|
|
38
|
-
export { EnsureParaIdsError, EnsureParaIdsOptions, EnsureParaIdsResult, ensureParaIds };
|
|
44
|
+
export { ENSURE_PARA_IDS_REASONS, EnsureParaIdsError, EnsureParaIdsOptions, EnsureParaIdsResult, ensureParaIds };
|