@stll/folio-core 0.55.0 → 0.57.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 +214 -52
- package/dist/ai-edits/batch-claims.d.ts +3 -1
- package/dist/ai-edits/batch-claims.js +25 -1
- package/dist/ai-edits/headless.js +2 -2
- package/dist/ai-edits/table-row-column-mutations.js +17 -3
- package/dist/ai-edits/types.d.ts +7 -1
- package/dist/ai-suggestions/apply.js +20 -1
- package/dist/compare/compare.js +1 -0
- package/dist/compare/inline-atoms.js +40 -16
- package/dist/compare/inline-provenance.js +12 -5
- package/dist/compare/reproducible-package.d.ts +0 -17
- package/dist/compare/reproducible-package.js +12 -18
- package/dist/compat/eigenpal.d.ts +2 -1
- package/dist/compat/eigenpal.js +2 -1
- package/dist/controller/canonicalClipboard.d.ts +23 -0
- package/dist/controller/canonicalClipboard.js +482 -0
- package/dist/controller/canonicalClipboardResources.d.ts +21 -0
- package/dist/controller/canonicalClipboardResources.js +382 -0
- package/dist/controller/canonicalComments.d.ts +41 -0
- package/dist/controller/canonicalComments.js +152 -0
- package/dist/controller/canonicalComposition.d.ts +24 -3
- package/dist/controller/canonicalComposition.js +208 -48
- package/dist/controller/canonicalInlineProjection.d.ts +118 -0
- package/dist/controller/canonicalInlineProjection.js +476 -0
- package/dist/controller/canonicalInput.d.ts +13 -4
- package/dist/controller/canonicalInput.js +62 -14
- package/dist/controller/canonicalInputTimer.d.ts +16 -0
- package/dist/controller/canonicalInputTimer.js +34 -0
- package/dist/controller/canonicalPublicOperations.d.ts +48 -0
- package/dist/controller/canonicalPublicOperations.js +648 -0
- package/dist/controller/canonicalSelection.d.ts +18 -0
- package/dist/controller/canonicalSelection.js +32 -0
- package/dist/controller/canonicalSession.d.ts +27 -6
- package/dist/controller/canonicalSession.js +298 -116
- package/dist/controller/canonicalStoryEditor.d.ts +7 -3
- package/dist/controller/canonicalStoryEditor.js +27 -2
- package/dist/controller/canonicalStructure.js +57 -4
- package/dist/controller/canonicalTocSelection.d.ts +11 -0
- package/dist/controller/canonicalTocSelection.js +43 -0
- package/dist/controller/folioEditor.d.ts +2 -9
- package/dist/controller/folioEditor.js +18 -4
- package/dist/controller/headerFooterEditorManager.d.ts +2 -1
- package/dist/controller/headerFooterEditorManager.js +26 -11
- package/dist/controller/hiddenEditorApi.d.ts +24 -3
- package/dist/controller/hiddenEditorApi.js +8 -0
- package/dist/controller/hiddenEditorManager.d.ts +5 -1
- package/dist/controller/hiddenEditorManager.js +378 -43
- package/dist/controller/noteEditorManager.d.ts +2 -1
- package/dist/controller/noteEditorManager.js +29 -13
- package/dist/document-operations.d.ts +8 -1
- package/dist/document-operations.js +6 -4
- package/dist/docx/blockPlainText.d.ts +1 -1
- package/dist/docx/blockPlainText.js +11 -3
- package/dist/docx/builtInStyles.js +13 -6
- 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/canonicalStoryRepack.d.ts +1 -1
- package/dist/docx/canonicalStoryRepack.js +38 -5
- package/dist/docx/containerChildren.gen.d.ts +3 -1
- package/dist/docx/containerChildren.gen.js +33 -1
- package/dist/docx/documentParser.d.ts +1 -13
- package/dist/docx/documentParser.js +1 -47
- package/dist/docx/ensureParaIds.js +10 -4
- package/dist/docx/fieldParser.js +14 -2
- 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 +26 -1
- package/dist/docx/headerFooterVerbatim.js +81 -3
- package/dist/docx/hyperlinkParser.d.ts +1 -1
- package/dist/docx/hyperlinkParser.js +20 -1
- package/dist/docx/imageParser.d.ts +13 -1
- package/dist/docx/imageParser.js +20 -11
- package/dist/docx/inlineWrapperContent.d.ts +4 -4
- package/dist/docx/inlineWrapperContent.js +4 -4
- package/dist/docx/linkedSdtPreservation.d.ts +10 -0
- package/dist/docx/linkedSdtPreservation.js +37 -0
- package/dist/docx/metadataPrivacy.js +6 -1
- package/dist/docx/packageParts.js +9 -3
- package/dist/docx/paragraphParser.js +88 -67
- package/dist/docx/paragraphPropertySource.d.ts +22 -1
- package/dist/docx/paragraphPropertySource.js +109 -2
- package/dist/docx/parser.js +2 -1
- package/dist/docx/preservedRunContent.js +2 -1
- package/dist/docx/relsParser.js +26 -2
- package/dist/docx/removeHeaderFooterParts.js +17 -6
- package/dist/docx/rezip.d.ts +49 -5
- package/dist/docx/rezip.js +754 -235
- package/dist/docx/saveDiagnostics.d.ts +11 -0
- package/dist/docx/selectiveSave.d.ts +2 -1
- package/dist/docx/selectiveSave.js +42 -11
- package/dist/docx/selectiveXmlPatch.js +7 -5
- package/dist/docx/serializer/commentSerializer.d.ts +4 -1
- package/dist/docx/serializer/commentSerializer.js +7 -3
- package/dist/docx/serializer/documentSerializer.d.ts +9 -2
- package/dist/docx/serializer/documentSerializer.js +29 -10
- package/dist/docx/serializer/paragraphSerializer.js +207 -94
- package/dist/docx/server/applyDocxXmlPatchProposal.js +14 -9
- package/dist/docx/server/materializeYjsDocx.js +14 -6
- package/dist/docx/server/migrateYjsAttrSchema.js +17 -5
- package/dist/docx/storyBlockReplay.d.ts +21 -1
- package/dist/docx/storyBlockReplay.js +113 -9
- package/dist/docx/storyPlainText.d.ts +20 -0
- package/dist/docx/storyPlainText.js +23 -0
- package/dist/docx/structuralXmlPatch.js +10 -22
- 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/i18n/messages/ar.gen.js +4 -0
- package/dist/i18n/messages/catalogs.gen.d.ts +68 -0
- package/dist/i18n/messages/catalogs.gen.js +68 -0
- package/dist/i18n/messages/cs.gen.js +4 -0
- package/dist/i18n/messages/de.gen.js +4 -0
- package/dist/i18n/messages/en.gen.js +4 -0
- package/dist/i18n/messages/es.gen.js +4 -0
- package/dist/i18n/messages/et.gen.js +4 -0
- package/dist/i18n/messages/fr.gen.js +4 -0
- package/dist/i18n/messages/he.gen.js +4 -0
- package/dist/i18n/messages/hi.gen.js +4 -0
- package/dist/i18n/messages/hu.gen.js +4 -0
- package/dist/i18n/messages/lt.gen.js +4 -0
- package/dist/i18n/messages/lv.gen.js +4 -0
- package/dist/i18n/messages/messages.gen.d.ts +4 -0
- package/dist/i18n/messages/pl.gen.js +4 -0
- package/dist/i18n/messages/pt-BR.gen.js +4 -0
- package/dist/i18n/messages/sk.gen.js +4 -0
- package/dist/i18n/messages/tr.gen.js +4 -0
- package/dist/i18n/messages/zh-CN.gen.js +4 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/internal/acceptedBlockProjection.d.ts +12 -0
- package/dist/internal/acceptedBlockProjection.js +45 -0
- package/dist/internal/revisionResolutionInline.js +25 -3
- package/dist/managers/DocumentLoaderManager.js +2 -1
- package/dist/markdown/escape.d.ts +3 -1
- package/dist/markdown/escape.js +9 -2
- package/dist/markdown/renderBlock.js +5 -120
- package/dist/markdown/renderParagraph.js +4 -2
- package/dist/markdown/renderRuns.d.ts +7 -1
- package/dist/markdown/renderRuns.js +33 -24
- package/dist/panel-layout.d.ts +11 -9
- package/dist/panel-layout.js +13 -9
- package/dist/prosemirror/addTrackedDeletionMark.d.ts +18 -0
- package/dist/prosemirror/addTrackedDeletionMark.js +87 -0
- package/dist/prosemirror/attrs/index.js +5 -0
- package/dist/prosemirror/canonicalCommands.d.ts +28 -4
- package/dist/prosemirror/canonicalCommands.js +11 -4
- 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/comments.js +60 -35
- package/dist/prosemirror/commands/pageBreak.js +2 -2
- package/dist/prosemirror/commands/pastePlainText.js +2 -1
- package/dist/prosemirror/commands/propertyChangeScope.js +3 -6
- package/dist/prosemirror/commands/resolveParagraphProperties.js +22 -13
- package/dist/prosemirror/commentOps.js +15 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +22 -3
- package/dist/prosemirror/conversion/hyphenTextCarriers.d.ts +8 -0
- package/dist/prosemirror/conversion/hyphenTextCarriers.js +8 -0
- package/dist/prosemirror/conversion/toProseDoc.d.ts +7 -1
- package/dist/prosemirror/conversion/toProseDoc.js +124 -22
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +61 -35
- package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +74 -25
- package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +11 -0
- package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +65 -29
- package/dist/prosemirror/extensions/marks/markUtils.js +11 -8
- package/dist/prosemirror/extensions/marks/noteReferenceDeletion.js +5 -2
- package/dist/prosemirror/fieldRepresentation.d.ts +8 -0
- package/dist/prosemirror/fieldRepresentation.js +18 -0
- package/dist/prosemirror/hyperlinkRemoval.d.ts +13 -1
- package/dist/prosemirror/hyperlinkRemoval.js +28 -9
- package/dist/prosemirror/insertOperations.js +2 -1
- package/dist/prosemirror/listNumbering.js +11 -5
- package/dist/prosemirror/noteReferenceOccurrenceId.d.ts +5 -0
- package/dist/prosemirror/noteReferenceOccurrenceId.js +5 -0
- package/dist/prosemirror/noteReferenceOccurrences.d.ts +21 -0
- package/dist/prosemirror/noteReferenceOccurrences.js +185 -0
- package/dist/prosemirror/noteReferenceReview.js +14 -1
- package/dist/prosemirror/paragraphPropertyCarry.d.ts +7 -1
- package/dist/prosemirror/paragraphPropertyCarry.js +8 -3
- package/dist/prosemirror/plugins/documentStyles.d.ts +4 -1
- package/dist/prosemirror/plugins/documentStyles.js +17 -10
- package/dist/prosemirror/plugins/suggestionMode.js +48 -48
- package/dist/prosemirror/preservedXmlReview.d.ts +6 -0
- package/dist/prosemirror/preservedXmlReview.js +35 -0
- package/dist/prosemirror/runFormattingFromMarks.js +2 -2
- package/dist/prosemirror/runFormattingReconciliation.js +5 -4
- package/dist/prosemirror/runPropertyChangeResolution.d.ts +8 -1
- package/dist/prosemirror/runPropertyChangeResolution.js +24 -2
- package/dist/prosemirror/runStyleFormatting.d.ts +3 -1
- package/dist/prosemirror/runStyleFormatting.js +3 -1
- package/dist/prosemirror/schema/marks.d.ts +1 -0
- package/dist/prosemirror/schema/nodes.d.ts +2 -0
- package/dist/prosemirror/styles/paragraphStyleCascade.js +4 -1
- package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +15 -15
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +69 -28
- package/dist/prosemirror/textInput.d.ts +5 -1
- package/dist/prosemirror/textInput.js +3 -3
- package/dist/prosemirror/trackedRevisionPath.d.ts +5 -1
- package/dist/prosemirror/trackedRevisionPath.js +39 -1
- package/dist/prosemirror/validation.js +3 -5
- package/dist/prosemirror/yjsDocumentMetadata.d.ts +9 -3
- package/dist/prosemirror/yjsDocumentMetadata.js +37 -8
- package/dist/types/canonicalCapabilities.d.ts +201 -0
- package/dist/types/canonicalCapabilities.js +198 -0
- package/dist/types/canonicalComments.d.ts +51 -0
- package/dist/types/canonicalComments.js +0 -0
- package/dist/types/canonicalSave.d.ts +11 -0
- package/dist/types/canonicalSave.js +0 -0
- package/dist/types/canonicalSections.d.ts +12 -0
- package/dist/types/canonicalSections.js +0 -0
- package/dist/types/docxSerialization.d.ts +14 -0
- package/dist/types/docxSerialization.js +7 -0
- package/dist/utils/headingCollector.js +45 -4
- package/dist/utils/outlineDepth.d.ts +9 -0
- package/dist/utils/outlineDepth.js +9 -0
- package/package.json +4 -4
|
@@ -1,8 +1,19 @@
|
|
|
1
|
+
import { CANONICAL_GAP } from "../types/canonicalCapabilities.js";
|
|
1
2
|
//#region src/docx/saveDiagnostics.d.ts
|
|
2
3
|
/** Save diagnostics describe fidelity fallbacks without including document content. */
|
|
3
4
|
type SaveDiagnostic = {
|
|
4
5
|
type: "sourceReplayMismatch";
|
|
5
6
|
part: string;
|
|
7
|
+
} | {
|
|
8
|
+
type: "selectiveSaveRefused";
|
|
9
|
+
part: string;
|
|
10
|
+
} | {
|
|
11
|
+
type: "sourceReplayUnavailable";
|
|
12
|
+
part: string;
|
|
13
|
+
} | {
|
|
14
|
+
type: "canonicalResourceReplacement";
|
|
15
|
+
gap: typeof CANONICAL_GAP.resourceReplacement;
|
|
16
|
+
part: string;
|
|
6
17
|
};
|
|
7
18
|
type SaveDiagnosticOptions = {
|
|
8
19
|
onDiagnostic?: ((diagnostic: SaveDiagnostic) => void) | undefined;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { document_d_exports } from "../types/document.js";
|
|
2
2
|
import { SaveDiagnosticOptions } from "./saveDiagnostics.js";
|
|
3
|
+
import { DocumentBodyAuthorityOptions } from "./serializer/documentSerializer.js";
|
|
3
4
|
//#region src/docx/selectiveSave.d.ts
|
|
4
|
-
type SelectiveSaveOptions = SaveDiagnosticOptions & {
|
|
5
|
+
type SelectiveSaveOptions = SaveDiagnosticOptions & DocumentBodyAuthorityOptions & {
|
|
5
6
|
/** Changed paragraph IDs to selectively patch */
|
|
6
7
|
changedParaIds: Set<string>;
|
|
7
8
|
/** Whether paragraph membership, order, or block structure changed. */
|
|
@@ -7,16 +7,17 @@ import { parseNumbering } from "./numberingParser.js";
|
|
|
7
7
|
import { normalizeImportedNumericIds } from "./numericIdNormalization.js";
|
|
8
8
|
import { isUnsafePackagePath } from "./packageParts.js";
|
|
9
9
|
import { RELATIONSHIP_TYPES } from "./relsParser.js";
|
|
10
|
-
import { COMMENTS_CONTENT_TYPE, COMMENTS_EXTENDED_PART_LOWER, addCommentsExtendedOverride, addCommentsExtendedRelationship, applyUpdatesToZip, collectHeaderFooterUpdates, findMaxRId, hasModelDrivenPictureWatermark, hasUnmaterializedHeaderFooter, hasUnmaterializedInlineResources, updateCoreProperties, withoutAttachedTemplate } from "./rezip.js";
|
|
10
|
+
import { COMMENTS_CONTENT_TYPE, COMMENTS_EXTENDED_PART_LOWER, addCommentsExtendedOverride, addCommentsExtendedRelationship, applyUpdatesToZip, collectHeaderFooterUpdates, findMaxRId, hasModelDrivenPictureWatermark, hasUnmaterializedHeaderFooter, hasUnmaterializedHyperlinkBindings, hasUnmaterializedInlineResources, planAddedStyles, publishCanonicalImageResources, updateCoreProperties, withoutAttachedTemplate } from "./rezip.js";
|
|
11
11
|
import "./selectiveSaveFlags.js";
|
|
12
12
|
import { buildPatchedDocumentXml, buildPatchedNoteXml, collectAddedNumberingDefs, collectParaIds, patchNumberingDefinitions } from "./selectiveXmlPatch.js";
|
|
13
|
-
import { planCommentParts, serializeComments, serializeCommentsExtended } from "./serializer/commentSerializer.js";
|
|
13
|
+
import { hasOwnedCommentsPart, planCommentParts, serializeComments, serializeCommentsExtended } from "./serializer/commentSerializer.js";
|
|
14
14
|
import { serializeDocument } from "./serializer/documentSerializer.js";
|
|
15
15
|
import { serializeEndnotes, serializeFootnotes } from "./serializer/noteSerializer.js";
|
|
16
16
|
import { serializeNumberingXml } from "./serializer/numberingSerializer.js";
|
|
17
17
|
import { readRootNamespaceBindings } from "./serializer/partNamespaces.js";
|
|
18
18
|
import { buildStructuralDocumentPatch } from "./structuralXmlPatch.js";
|
|
19
19
|
import { DOCX_CONFORMANCE_CLASSES } from "@stll/docx-core/model";
|
|
20
|
+
import { writeZipPart } from "@stll/docx-core/zip";
|
|
20
21
|
//#region src/docx/selectiveSave.ts
|
|
21
22
|
/**
|
|
22
23
|
* Splice edited footnote/endnote paragraphs into their parts and return the
|
|
@@ -200,9 +201,11 @@ async function attemptSelectiveSave(doc, originalBuffer, options) {
|
|
|
200
201
|
if (!validateFolioDocumentModel(doc).valid) return null;
|
|
201
202
|
const comments = doc.package.document.comments ?? [];
|
|
202
203
|
const hasComments = comments.length > 0;
|
|
204
|
+
const ownsCommentsPart = hasOwnedCommentsPart(doc);
|
|
203
205
|
const commentPlan = planCommentParts(comments);
|
|
204
206
|
try {
|
|
205
207
|
const zip = await (await import("jszip")).default.loadAsync(originalBuffer);
|
|
208
|
+
if (await hasUnmaterializedHyperlinkBindings(doc, zip)) return null;
|
|
206
209
|
for (const [path, file] of Object.entries(zip.files)) if (!file.dir && isUnsafePackagePath(path)) return null;
|
|
207
210
|
if (originalBuffer !== doc.originalBuffer) {
|
|
208
211
|
const sourceParts = /* @__PURE__ */ new Map();
|
|
@@ -211,14 +214,27 @@ async function attemptSelectiveSave(doc, originalBuffer, options) {
|
|
|
211
214
|
if (file.dir || !lowerPath.startsWith("word/") || !lowerPath.endsWith(".xml")) continue;
|
|
212
215
|
sourceParts.set(path, await file.async("text"));
|
|
213
216
|
}
|
|
214
|
-
for (const [path, xml] of normalizeImportedNumericIds(sourceParts)) if (xml !== sourceParts.get(path))
|
|
217
|
+
for (const [path, xml] of normalizeImportedNumericIds(sourceParts)) if (xml !== sourceParts.get(path)) writeZipPart({
|
|
218
|
+
zip,
|
|
219
|
+
path,
|
|
220
|
+
data: xml
|
|
221
|
+
});
|
|
215
222
|
}
|
|
223
|
+
if (options.bodyAuthority === "canonical") await publishCanonicalImageResources({
|
|
224
|
+
document: doc,
|
|
225
|
+
zip,
|
|
226
|
+
compressionLevel: 6
|
|
227
|
+
});
|
|
216
228
|
const updates = /* @__PURE__ */ new Map();
|
|
217
229
|
if (changedParaIds.size > 0 || structuralChange) {
|
|
218
230
|
const docXmlFile = zip.file("word/document.xml");
|
|
219
231
|
if (!docXmlFile) return null;
|
|
220
232
|
const originalDocXml = await docXmlFile.async("text");
|
|
221
|
-
const serializedDocXml = serializeDocument(doc, readRootNamespaceBindings(originalDocXml)
|
|
233
|
+
const serializedDocXml = serializeDocument(doc, readRootNamespaceBindings(originalDocXml), {
|
|
234
|
+
xml: originalDocXml,
|
|
235
|
+
bodyAuthority: options.bodyAuthority,
|
|
236
|
+
onDiagnostic: options.onDiagnostic
|
|
237
|
+
});
|
|
222
238
|
const bodyParaIds = collectParaIds(serializedDocXml);
|
|
223
239
|
const originalBodyParaIds = structuralChange ? collectParaIds(originalDocXml) : void 0;
|
|
224
240
|
if (structuralChange && doc.package.numbering) {
|
|
@@ -244,30 +260,45 @@ async function attemptSelectiveSave(doc, originalBuffer, options) {
|
|
|
244
260
|
updates.set("word/document.xml", patchedDocXml);
|
|
245
261
|
}
|
|
246
262
|
}
|
|
247
|
-
const sourceCommentsFile = zip
|
|
248
|
-
|
|
263
|
+
const sourceCommentsFile = findZipEntryCaseInsensitive(zip, "word/comments.xml");
|
|
264
|
+
const commentsPartPath = sourceCommentsFile?.name ?? "word/comments.xml";
|
|
265
|
+
if (hasComments || ownsCommentsPart || sourceCommentsFile) {
|
|
249
266
|
const sourceCommentsXml = sourceCommentsFile ? await sourceCommentsFile.async("text") : void 0;
|
|
250
267
|
const commentsXml = serializeComments(commentPlan, sourceCommentsXml === void 0 ? void 0 : readRootNamespaceBindings(sourceCommentsXml));
|
|
251
|
-
if (commentsXml !== sourceCommentsXml) updates.set(
|
|
268
|
+
if (commentsXml !== sourceCommentsXml) updates.set(commentsPartPath, commentsXml);
|
|
252
269
|
}
|
|
253
|
-
if (hasComments) {
|
|
270
|
+
if (hasComments || ownsCommentsPart) {
|
|
254
271
|
const ctFile = zip.file("[Content_Types].xml");
|
|
255
272
|
if (ctFile) {
|
|
256
273
|
const ctXml = await ctFile.async("text");
|
|
257
|
-
if (!ctXml.includes("/word/comments.xml")) updates.set("[Content_Types].xml", ctXml.replace("</Types>", `<Override PartName="
|
|
274
|
+
if (!ctXml.toLowerCase().includes("/word/comments.xml")) updates.set("[Content_Types].xml", ctXml.replace("</Types>", `<Override PartName="/${commentsPartPath}" ContentType="${COMMENTS_CONTENT_TYPE}"/></Types>`));
|
|
258
275
|
}
|
|
259
276
|
const relsPath = "word/_rels/document.xml.rels";
|
|
260
277
|
const relsFile = zip.file(relsPath);
|
|
261
278
|
if (relsFile) {
|
|
262
279
|
const relsXml = await relsFile.async("text");
|
|
263
|
-
if (!relsXml.includes("comments.xml")) {
|
|
280
|
+
if (!relsXml.toLowerCase().includes("comments.xml")) {
|
|
264
281
|
const maxId = findMaxRId(relsXml);
|
|
265
|
-
updates.set(relsPath, relsXml.replace("</Relationships>", `<Relationship Id="rId${maxId + 1}" Type="${RELATIONSHIP_TYPES.comments}" Target="
|
|
282
|
+
updates.set(relsPath, relsXml.replace("</Relationships>", `<Relationship Id="rId${maxId + 1}" Type="${RELATIONSHIP_TYPES.comments}" Target="${commentsPartPath.slice(5)}"/></Relationships>`));
|
|
266
283
|
}
|
|
267
284
|
}
|
|
268
285
|
}
|
|
269
286
|
if (!await patchCommentsExtended(zip, commentPlan, updates)) return null;
|
|
270
287
|
if (!await patchNumberingPart(zip, doc, updates)) return null;
|
|
288
|
+
const styles = await planAddedStyles(doc, zip);
|
|
289
|
+
switch (styles.type) {
|
|
290
|
+
case "unchanged": break;
|
|
291
|
+
case "patch":
|
|
292
|
+
updates.set(styles.path, styles.xml);
|
|
293
|
+
break;
|
|
294
|
+
case "materialize":
|
|
295
|
+
options.onDiagnostic?.({
|
|
296
|
+
type: "selectiveSaveRefused",
|
|
297
|
+
part: "word/styles.xml"
|
|
298
|
+
});
|
|
299
|
+
return null;
|
|
300
|
+
default: return styles;
|
|
301
|
+
}
|
|
271
302
|
for (const [path, xml] of await collectHeaderFooterUpdates(doc, {
|
|
272
303
|
sourceZip: zip,
|
|
273
304
|
onDiagnostic: options.onDiagnostic
|
|
@@ -35,7 +35,7 @@ function isXmlNameBoundary(char) {
|
|
|
35
35
|
*/
|
|
36
36
|
function findParagraphOffsets(xml, paraId) {
|
|
37
37
|
const escaped = escapeRegExp(paraId);
|
|
38
|
-
const pattern = new RegExp(`<w:p[\\s][^>]*w14:paraId
|
|
38
|
+
const pattern = new RegExp(`<w:p[\\s][^>]*w14:paraId\\s*=\\s*(["'])${escaped}\\1`, "gu");
|
|
39
39
|
const matches = [];
|
|
40
40
|
let match;
|
|
41
41
|
while ((match = pattern.exec(xml)) !== null) matches.push(match.index);
|
|
@@ -191,7 +191,7 @@ function scanParagraphs(xml) {
|
|
|
191
191
|
const tagEnd = xml.indexOf(">", tagStart);
|
|
192
192
|
if (tagEnd === -1) break;
|
|
193
193
|
const openTag = xml.slice(tagStart, tagEnd + 1);
|
|
194
|
-
const paraId = /\bw14:paraId
|
|
194
|
+
const paraId = /\bw14:paraId\s*=\s*(?<quote>["'])(?<id>[^"']+)\k<quote>/u.exec(openTag)?.groups?.["id"];
|
|
195
195
|
const container = {
|
|
196
196
|
inFallback: depth.fallback > 0,
|
|
197
197
|
inAlternateContent: depth.alternateContent > 0,
|
|
@@ -236,7 +236,7 @@ function countParagraphElements(xml) {
|
|
|
236
236
|
*/
|
|
237
237
|
function collectParaIds(xml) {
|
|
238
238
|
const ids = /* @__PURE__ */ new Map();
|
|
239
|
-
const pattern = /w14:paraId
|
|
239
|
+
const pattern = /w14:paraId\s*=\s*(?<quote>["'])(?<id>[^"']+)\k<quote>/gu;
|
|
240
240
|
let match;
|
|
241
241
|
while ((match = pattern.exec(xml)) !== null) {
|
|
242
242
|
const id = match.groups["id"];
|
|
@@ -245,7 +245,7 @@ function collectParaIds(xml) {
|
|
|
245
245
|
return ids;
|
|
246
246
|
}
|
|
247
247
|
/** Paragraph ids folio writes and this module may have to remove again. */
|
|
248
|
-
const MINTED_PARA_ID_ATTRIBUTE = /\sw14:(
|
|
248
|
+
const MINTED_PARA_ID_ATTRIBUTE = /\sw14:(paraId|textId)="[^"]*"/gu;
|
|
249
249
|
/**
|
|
250
250
|
* The replacement for a paragraph whose source open tag carries no paraId.
|
|
251
251
|
*
|
|
@@ -262,7 +262,9 @@ const MINTED_PARA_ID_ATTRIBUTE = /\sw14:(?:para|text)Id="[^"]*"/gu;
|
|
|
262
262
|
const withoutMintedIds = (paragraphXml, sourceOpenTag) => {
|
|
263
263
|
const tagEnd = paragraphXml.indexOf(">");
|
|
264
264
|
if (tagEnd === -1) return paragraphXml;
|
|
265
|
-
return paragraphXml.slice(0, tagEnd + 1).replace(MINTED_PARA_ID_ATTRIBUTE, (attribute) =>
|
|
265
|
+
return paragraphXml.slice(0, tagEnd + 1).replace(MINTED_PARA_ID_ATTRIBUTE, (attribute, name) => {
|
|
266
|
+
return new RegExp(`\\bw14:${name}\\s*=\\s*(["'])[^"']*\\1`, "u").test(sourceOpenTag) ? attribute : "";
|
|
267
|
+
}) + paragraphXml.slice(tagEnd + 1);
|
|
266
268
|
};
|
|
267
269
|
const storyOf = ({ textBoxDepth }) => textBoxDepth > 0 ? "text-box" : "main";
|
|
268
270
|
const sameContainer = (a, b) => a.inAlternateContent === b.inAlternateContent && a.textBoxDepth === b.textBoxDepth && a.tableDepth === b.tableDepth;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { document_d_exports } from "../../types/document.js";
|
|
1
2
|
import { Comment } from "../../types/content.js";
|
|
2
3
|
//#region src/docx/serializer/commentSerializer.d.ts
|
|
4
|
+
/** An owned empty part survives deletion of its final thread. */
|
|
5
|
+
declare const hasOwnedCommentsPart: (document: document_d_exports.Document) => boolean;
|
|
3
6
|
/**
|
|
4
7
|
* What every comment part is written from: one ordered list of comment ids, and
|
|
5
8
|
* the facts each id carries.
|
|
@@ -52,4 +55,4 @@ declare function serializeComments({ order, byId }: CommentPartPlan, sourceBindi
|
|
|
52
55
|
*/
|
|
53
56
|
declare function serializeCommentsExtended(plan: CommentPartPlan): string | null;
|
|
54
57
|
//#endregion
|
|
55
|
-
export { CommentPartPlan, planCommentParts, serializeComments, serializeCommentsExtended };
|
|
58
|
+
export { CommentPartPlan, hasOwnedCommentsPart, planCommentParts, serializeComments, serializeCommentsExtended };
|
|
@@ -5,12 +5,15 @@ import { serializeParagraph } from "./paragraphSerializer.js";
|
|
|
5
5
|
import { serializePartElement } from "./partNamespaces.js";
|
|
6
6
|
import { serializeTextFormatting } from "./textFormattingSerializer.js";
|
|
7
7
|
import { escapeXmlAttribute } from "@stll/docx-core";
|
|
8
|
+
import { COMMENT_PART_RELATIONSHIPS } from "@stll/docx-core/model";
|
|
8
9
|
//#region src/docx/serializer/commentSerializer.ts
|
|
9
10
|
/**
|
|
10
11
|
* Comment Serializer
|
|
11
12
|
*
|
|
12
13
|
* Serializes Comment[] to OOXML comments.xml format.
|
|
13
14
|
*/
|
|
15
|
+
/** An owned empty part survives deletion of its final thread. */
|
|
16
|
+
const hasOwnedCommentsPart = (document) => [...document.package.relationships?.values() ?? []].some(({ type }) => type === COMMENT_PART_RELATIONSHIPS.comments.type);
|
|
14
17
|
const DEFAULT_ANNOTATION_REFERENCE_PROPERTIES = "<w:rPr><w:rStyle w:val=\"CommentReference\"/></w:rPr>";
|
|
15
18
|
const PARAGRAPH_PROPERTIES_END = "</w:pPr>";
|
|
16
19
|
const serializeAnnotationReference = (formatting) => {
|
|
@@ -169,7 +172,7 @@ function buildCommentExtendedEntries({ order, byId, threadParaIdById, threadedId
|
|
|
169
172
|
entries.push({
|
|
170
173
|
paraId,
|
|
171
174
|
...parentParaId !== void 0 ? { paraIdParent: parentParaId } : {},
|
|
172
|
-
done: done
|
|
175
|
+
...done === void 0 ? {} : { done }
|
|
173
176
|
});
|
|
174
177
|
}
|
|
175
178
|
return entries.length > 0 ? entries : null;
|
|
@@ -185,7 +188,8 @@ function serializeCommentsExtended(plan) {
|
|
|
185
188
|
if (!entries) return null;
|
|
186
189
|
const body = entries.map((entry) => {
|
|
187
190
|
const parentAttr = entry.paraIdParent !== void 0 ? ` w15:paraIdParent="${escapeXmlAttribute(entry.paraIdParent)}"` : "";
|
|
188
|
-
|
|
191
|
+
const doneAttr = entry.done === void 0 ? "" : ` w15:done="${entry.done ? "1" : "0"}"`;
|
|
192
|
+
return `<w15:commentEx w15:paraId="${escapeXmlAttribute(entry.paraId)}"${parentAttr}${doneAttr}/>`;
|
|
189
193
|
}).join("");
|
|
190
194
|
return XML_DECLARATION + serializePartElement({
|
|
191
195
|
partPath: "word/commentsExtended.xml",
|
|
@@ -196,4 +200,4 @@ function serializeCommentsExtended(plan) {
|
|
|
196
200
|
});
|
|
197
201
|
}
|
|
198
202
|
//#endregion
|
|
199
|
-
export { planCommentParts, serializeComments, serializeCommentsExtended };
|
|
203
|
+
export { hasOwnedCommentsPart, planCommentParts, serializeComments, serializeCommentsExtended };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { document_d_exports } from "../../types/document.js";
|
|
2
|
+
import { SaveDiagnosticOptions } from "../saveDiagnostics.js";
|
|
2
3
|
//#region src/docx/serializer/documentSerializer.d.ts
|
|
3
4
|
/**
|
|
4
5
|
* Serialize a DocumentBody to document.xml body content
|
|
@@ -15,7 +16,13 @@ declare function serializeDocumentBody(body: document_d_exports.DocumentBody): s
|
|
|
15
16
|
* prefix only the source document bound keeps its URI
|
|
16
17
|
* @returns Complete XML string for document.xml
|
|
17
18
|
*/
|
|
18
|
-
|
|
19
|
+
type DocumentBodyAuthorityOptions = {
|
|
20
|
+
/** Canonical saves preserve trusted source blocks; default saves serialize the model. */
|
|
21
|
+
bodyAuthority?: "canonical" | "model" | undefined;
|
|
22
|
+
};
|
|
23
|
+
declare function serializeDocument(doc: document_d_exports.Document, sourceBindings?: ReadonlyMap<string, string>, source?: SaveDiagnosticOptions & DocumentBodyAuthorityOptions & {
|
|
24
|
+
xml?: string | undefined;
|
|
25
|
+
}): string;
|
|
19
26
|
/**
|
|
20
27
|
* Serialize just the document body (useful for partial updates)
|
|
21
28
|
*
|
|
@@ -59,4 +66,4 @@ declare function createSimpleDocument(paragraphs: {
|
|
|
59
66
|
styleId?: string;
|
|
60
67
|
}[]): document_d_exports.Document;
|
|
61
68
|
//#endregion
|
|
62
|
-
export { createEmptyDocument, createSimpleDocument, getDocumentContentCount, getDocumentParagraphCount, getDocumentTableCount, hasDocumentContent, hasDocumentSections, hasSectionProperties, serializeDocument, serializeDocumentBody, serializeDocumentBodyElement };
|
|
69
|
+
export { DocumentBodyAuthorityOptions, createEmptyDocument, createSimpleDocument, getDocumentContentCount, getDocumentParagraphCount, getDocumentTableCount, hasDocumentContent, hasDocumentSections, hasSectionProperties, serializeDocument, serializeDocumentBody, serializeDocumentBodyElement };
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { getDocumentSourceBaseline } from "../headerFooterVerbatim.js";
|
|
2
|
+
import { buildDocumentBlockReplay, canReplayDocumentSource } from "../storyBlockReplay.js";
|
|
1
3
|
import { serializeBlockCustomXml } from "./blockCustomXmlSerializer.js";
|
|
2
4
|
import { serializeBlockSdt } from "./blockSdtSerializer.js";
|
|
3
5
|
import { serializeBookmarkMarker } from "./markupRangeAttributes.js";
|
|
@@ -84,24 +86,41 @@ function serializeDocumentBody(body) {
|
|
|
84
86
|
if (body.finalSectionProperties) parts.push(serializeSectionProperties(body.finalSectionProperties));
|
|
85
87
|
return parts.join("");
|
|
86
88
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
*
|
|
90
|
-
* @param doc - The document to serialize
|
|
91
|
-
* @param sourceBindings - Root `xmlns:*` of the part being replaced, so a
|
|
92
|
-
* prefix only the source document bound keeps its URI
|
|
93
|
-
* @returns Complete XML string for document.xml
|
|
94
|
-
*/
|
|
95
|
-
function serializeDocument(doc, sourceBindings) {
|
|
89
|
+
const replayableDocumentSources = /* @__PURE__ */ new WeakMap();
|
|
90
|
+
function serializeDocument(doc, sourceBindings, source) {
|
|
96
91
|
resetAutoIdCounter();
|
|
92
|
+
const baseline = source?.bodyAuthority === "canonical" ? getDocumentSourceBaseline(doc) : { type: "missing" };
|
|
93
|
+
const sourceMatches = baseline.type === "captured" && (source?.xml === void 0 || source.xml === baseline.xml);
|
|
94
|
+
if (baseline.type === "captured" && sourceMatches && JSON.stringify(doc.package.document) === baseline.fingerprint) {
|
|
95
|
+
if (replayableDocumentSources.get(baseline.body) === baseline.xml) return baseline.xml;
|
|
96
|
+
if (canReplayDocumentSource(baseline.xml, baseline.body)) {
|
|
97
|
+
replayableDocumentSources.set(baseline.body, baseline.xml);
|
|
98
|
+
return baseline.xml;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
97
101
|
const body = serializeDocumentBackground(doc.package.document.background) + `<w:body>${serializeDocumentBody(doc.package.document)}</w:body>`;
|
|
98
|
-
|
|
102
|
+
const serializedXml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" + serializePartElement({
|
|
99
103
|
partPath: "word/document.xml",
|
|
100
104
|
rootName: "w:document",
|
|
101
105
|
baselinePrefixes: DOCUMENT_BASELINE_PREFIXES,
|
|
102
106
|
sourceBindings,
|
|
103
107
|
body
|
|
104
108
|
});
|
|
109
|
+
if (baseline.type === "missing") return serializedXml;
|
|
110
|
+
if (baseline.type === "captured" && sourceMatches) {
|
|
111
|
+
const replay = buildDocumentBlockReplay({
|
|
112
|
+
sourceXml: baseline.xml,
|
|
113
|
+
baseline: baseline.body,
|
|
114
|
+
current: doc.package.document,
|
|
115
|
+
serializedXml
|
|
116
|
+
});
|
|
117
|
+
if (replay !== null) return replay;
|
|
118
|
+
}
|
|
119
|
+
source?.onDiagnostic?.({
|
|
120
|
+
type: "sourceReplayMismatch",
|
|
121
|
+
part: "word/document.xml"
|
|
122
|
+
});
|
|
123
|
+
return serializedXml;
|
|
105
124
|
}
|
|
106
125
|
/**
|
|
107
126
|
* Serialize just the document body (useful for partial updates)
|