@usejunior/docx-core 0.9.1 → 0.11.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/LICENSE +202 -21
- package/NOTICE +2 -0
- package/README.md +2 -2
- package/dist/.tsbuildinfo +1 -1
- package/dist/atomizer.d.ts +28 -8
- package/dist/atomizer.d.ts.map +1 -1
- package/dist/atomizer.js +96 -25
- package/dist/atomizer.js.map +1 -1
- package/dist/baselines/atomizer/auxiliaryIdCollision.d.ts +99 -0
- package/dist/baselines/atomizer/auxiliaryIdCollision.d.ts.map +1 -0
- package/dist/baselines/atomizer/auxiliaryIdCollision.js +415 -0
- package/dist/baselines/atomizer/auxiliaryIdCollision.js.map +1 -0
- package/dist/baselines/atomizer/documentReconstructor.d.ts.map +1 -1
- package/dist/baselines/atomizer/documentReconstructor.js +333 -112
- package/dist/baselines/atomizer/documentReconstructor.js.map +1 -1
- package/dist/baselines/atomizer/formattingFidelity.d.ts +99 -0
- package/dist/baselines/atomizer/formattingFidelity.d.ts.map +1 -0
- package/dist/baselines/atomizer/formattingFidelity.js +449 -0
- package/dist/baselines/atomizer/formattingFidelity.js.map +1 -0
- package/dist/baselines/atomizer/inPlaceModifier-bookmarks.d.ts +37 -0
- package/dist/baselines/atomizer/inPlaceModifier-bookmarks.d.ts.map +1 -0
- package/dist/baselines/atomizer/inPlaceModifier-bookmarks.js +189 -0
- package/dist/baselines/atomizer/inPlaceModifier-bookmarks.js.map +1 -0
- package/dist/baselines/atomizer/inPlaceModifier-containers.d.ts +74 -0
- package/dist/baselines/atomizer/inPlaceModifier-containers.d.ts.map +1 -0
- package/dist/baselines/atomizer/inPlaceModifier-containers.js +171 -0
- package/dist/baselines/atomizer/inPlaceModifier-containers.js.map +1 -0
- package/dist/baselines/atomizer/inPlaceModifier-deletion.d.ts +88 -0
- package/dist/baselines/atomizer/inPlaceModifier-deletion.d.ts.map +1 -0
- package/dist/baselines/atomizer/inPlaceModifier-deletion.js +326 -0
- package/dist/baselines/atomizer/inPlaceModifier-deletion.js.map +1 -0
- package/dist/baselines/atomizer/inPlaceModifier-postprocess.d.ts +85 -0
- package/dist/baselines/atomizer/inPlaceModifier-postprocess.d.ts.map +1 -0
- package/dist/baselines/atomizer/inPlaceModifier-postprocess.js +402 -0
- package/dist/baselines/atomizer/inPlaceModifier-postprocess.js.map +1 -0
- package/dist/baselines/atomizer/inPlaceModifier-presplit.d.ts +39 -0
- package/dist/baselines/atomizer/inPlaceModifier-presplit.d.ts.map +1 -0
- package/dist/baselines/atomizer/inPlaceModifier-presplit.js +265 -0
- package/dist/baselines/atomizer/inPlaceModifier-presplit.js.map +1 -0
- package/dist/baselines/atomizer/inPlaceModifier-shared.d.ts +62 -0
- package/dist/baselines/atomizer/inPlaceModifier-shared.d.ts.map +1 -0
- package/dist/baselines/atomizer/inPlaceModifier-shared.js +139 -0
- package/dist/baselines/atomizer/inPlaceModifier-shared.js.map +1 -0
- package/dist/baselines/atomizer/inPlaceModifier-wrappers.d.ts +198 -0
- package/dist/baselines/atomizer/inPlaceModifier-wrappers.d.ts.map +1 -0
- package/dist/baselines/atomizer/inPlaceModifier-wrappers.js +475 -0
- package/dist/baselines/atomizer/inPlaceModifier-wrappers.js.map +1 -0
- package/dist/baselines/atomizer/inPlaceModifier.d.ts +6 -290
- package/dist/baselines/atomizer/inPlaceModifier.d.ts.map +1 -1
- package/dist/baselines/atomizer/inPlaceModifier.js +23 -1828
- package/dist/baselines/atomizer/inPlaceModifier.js.map +1 -1
- package/dist/baselines/atomizer/pipeline.d.ts +36 -2
- package/dist/baselines/atomizer/pipeline.d.ts.map +1 -1
- package/dist/baselines/atomizer/pipeline.js +216 -144
- package/dist/baselines/atomizer/pipeline.js.map +1 -1
- package/dist/baselines/atomizer/trackChangesAcceptorAst.d.ts.map +1 -1
- package/dist/baselines/atomizer/trackChangesAcceptorAst.js +199 -173
- package/dist/baselines/atomizer/trackChangesAcceptorAst.js.map +1 -1
- package/dist/baselines/wmlcomparer/DotnetCli.d.ts.map +1 -1
- package/dist/baselines/wmlcomparer/DotnetCli.js +7 -0
- package/dist/baselines/wmlcomparer/DotnetCli.js.map +1 -1
- package/dist/cli/compare-two.d.ts.map +1 -1
- package/dist/cli/compare-two.js +3 -1
- package/dist/cli/compare-two.js.map +1 -1
- package/dist/cli/conformance-adapter.d.ts +3 -0
- package/dist/cli/conformance-adapter.d.ts.map +1 -0
- package/dist/cli/conformance-adapter.js +93 -0
- package/dist/cli/conformance-adapter.js.map +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +5 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/compare-types.d.ts +197 -0
- package/dist/compare-types.d.ts.map +1 -0
- package/dist/compare-types.js +2 -0
- package/dist/compare-types.js.map +1 -0
- package/dist/core-types.d.ts +5 -1
- package/dist/core-types.d.ts.map +1 -1
- package/dist/core-types.js +5 -1
- package/dist/core-types.js.map +1 -1
- package/dist/footnotes.d.ts +8 -3
- package/dist/footnotes.d.ts.map +1 -1
- package/dist/footnotes.js +8 -3
- package/dist/footnotes.js.map +1 -1
- package/dist/generation/compile.d.ts +21 -0
- package/dist/generation/compile.d.ts.map +1 -0
- package/dist/generation/compile.js +46 -0
- package/dist/generation/compile.js.map +1 -0
- package/dist/generation/context.d.ts +42 -0
- package/dist/generation/context.d.ts.map +1 -0
- package/dist/generation/context.js +65 -0
- package/dist/generation/context.js.map +1 -0
- package/dist/generation/emit/comments-part.d.ts +36 -0
- package/dist/generation/emit/comments-part.d.ts.map +1 -0
- package/dist/generation/emit/comments-part.js +116 -0
- package/dist/generation/emit/comments-part.js.map +1 -0
- package/dist/generation/emit/document-part.d.ts +24 -0
- package/dist/generation/emit/document-part.d.ts.map +1 -0
- package/dist/generation/emit/document-part.js +60 -0
- package/dist/generation/emit/document-part.js.map +1 -0
- package/dist/generation/emit/emit-context.d.ts +26 -0
- package/dist/generation/emit/emit-context.d.ts.map +1 -0
- package/dist/generation/emit/emit-context.js +19 -0
- package/dist/generation/emit/emit-context.js.map +1 -0
- package/dist/generation/emit/header-footer-part.d.ts +23 -0
- package/dist/generation/emit/header-footer-part.d.ts.map +1 -0
- package/dist/generation/emit/header-footer-part.js +57 -0
- package/dist/generation/emit/header-footer-part.js.map +1 -0
- package/dist/generation/emit/numbering-part.d.ts +29 -0
- package/dist/generation/emit/numbering-part.d.ts.map +1 -0
- package/dist/generation/emit/numbering-part.js +100 -0
- package/dist/generation/emit/numbering-part.js.map +1 -0
- package/dist/generation/emit/package-parts.d.ts +24 -0
- package/dist/generation/emit/package-parts.d.ts.map +1 -0
- package/dist/generation/emit/package-parts.js +121 -0
- package/dist/generation/emit/package-parts.js.map +1 -0
- package/dist/generation/emit/paragraph.d.ts +24 -0
- package/dist/generation/emit/paragraph.d.ts.map +1 -0
- package/dist/generation/emit/paragraph.js +63 -0
- package/dist/generation/emit/paragraph.js.map +1 -0
- package/dist/generation/emit/properties.d.ts +34 -0
- package/dist/generation/emit/properties.d.ts.map +1 -0
- package/dist/generation/emit/properties.js +138 -0
- package/dist/generation/emit/properties.js.map +1 -0
- package/dist/generation/emit/run.d.ts +15 -0
- package/dist/generation/emit/run.d.ts.map +1 -0
- package/dist/generation/emit/run.js +71 -0
- package/dist/generation/emit/run.js.map +1 -0
- package/dist/generation/emit/section.d.ts +29 -0
- package/dist/generation/emit/section.d.ts.map +1 -0
- package/dist/generation/emit/section.js +117 -0
- package/dist/generation/emit/section.js.map +1 -0
- package/dist/generation/emit/settings-part.d.ts +13 -0
- package/dist/generation/emit/settings-part.d.ts.map +1 -0
- package/dist/generation/emit/settings-part.js +24 -0
- package/dist/generation/emit/settings-part.js.map +1 -0
- package/dist/generation/emit/styles-part.d.ts +16 -0
- package/dist/generation/emit/styles-part.d.ts.map +1 -0
- package/dist/generation/emit/styles-part.js +80 -0
- package/dist/generation/emit/styles-part.js.map +1 -0
- package/dist/generation/emit/table.d.ts +26 -0
- package/dist/generation/emit/table.d.ts.map +1 -0
- package/dist/generation/emit/table.js +196 -0
- package/dist/generation/emit/table.js.map +1 -0
- package/dist/generation/errors.d.ts +22 -0
- package/dist/generation/errors.d.ts.map +1 -0
- package/dist/generation/errors.js +29 -0
- package/dist/generation/errors.js.map +1 -0
- package/dist/generation/index.d.ts +13 -0
- package/dist/generation/index.d.ts.map +1 -0
- package/dist/generation/index.js +12 -0
- package/dist/generation/index.js.map +1 -0
- package/dist/generation/ordering.d.ts +46 -0
- package/dist/generation/ordering.d.ts.map +1 -0
- package/dist/generation/ordering.js +119 -0
- package/dist/generation/ordering.js.map +1 -0
- package/dist/generation/recipes.d.ts +47 -0
- package/dist/generation/recipes.d.ts.map +1 -0
- package/dist/generation/recipes.js +84 -0
- package/dist/generation/recipes.js.map +1 -0
- package/dist/generation/structural-checks.d.ts +24 -0
- package/dist/generation/structural-checks.d.ts.map +1 -0
- package/dist/generation/structural-checks.js +318 -0
- package/dist/generation/structural-checks.js.map +1 -0
- package/dist/generation/types.d.ts +217 -0
- package/dist/generation/types.d.ts.map +1 -0
- package/dist/generation/types.js +16 -0
- package/dist/generation/types.js.map +1 -0
- package/dist/generation/validate-spec.d.ts +27 -0
- package/dist/generation/validate-spec.d.ts.map +1 -0
- package/dist/generation/validate-spec.js +307 -0
- package/dist/generation/validate-spec.js.map +1 -0
- package/dist/index.d.ts +9 -150
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -1
- package/dist/integration/generation-probes.d.ts +15 -0
- package/dist/integration/generation-probes.d.ts.map +1 -0
- package/dist/integration/generation-probes.js +84 -0
- package/dist/integration/generation-probes.js.map +1 -0
- package/dist/integration/libreoffice-oracle.d.ts +49 -0
- package/dist/integration/libreoffice-oracle.d.ts.map +1 -0
- package/dist/integration/libreoffice-oracle.js +290 -0
- package/dist/integration/libreoffice-oracle.js.map +1 -0
- package/dist/integration/synthetic-docx-fixture.d.ts +72 -0
- package/dist/integration/synthetic-docx-fixture.d.ts.map +1 -1
- package/dist/integration/synthetic-docx-fixture.js +131 -4
- package/dist/integration/synthetic-docx-fixture.js.map +1 -1
- package/dist/primitives/accept_changes.d.ts +4 -3
- package/dist/primitives/accept_changes.d.ts.map +1 -1
- package/dist/primitives/accept_changes.js +163 -77
- package/dist/primitives/accept_changes.js.map +1 -1
- package/dist/primitives/comments.d.ts +12 -3
- package/dist/primitives/comments.d.ts.map +1 -1
- package/dist/primitives/comments.js +374 -97
- package/dist/primitives/comments.js.map +1 -1
- package/dist/primitives/content_fingerprint.d.ts +29 -0
- package/dist/primitives/content_fingerprint.d.ts.map +1 -0
- package/dist/primitives/content_fingerprint.js +63 -0
- package/dist/primitives/content_fingerprint.js.map +1 -0
- package/dist/primitives/document.d.ts +94 -15
- package/dist/primitives/document.d.ts.map +1 -1
- package/dist/primitives/document.js +373 -36
- package/dist/primitives/document.js.map +1 -1
- package/dist/primitives/document_view-comments.d.ts +18 -0
- package/dist/primitives/document_view-comments.d.ts.map +1 -0
- package/dist/primitives/document_view-comments.js +160 -0
- package/dist/primitives/document_view-comments.js.map +1 -0
- package/dist/primitives/document_view-headings.d.ts +45 -0
- package/dist/primitives/document_view-headings.d.ts.map +1 -0
- package/dist/primitives/document_view-headings.js +247 -0
- package/dist/primitives/document_view-headings.js.map +1 -0
- package/dist/primitives/document_view-styles.d.ts +11 -0
- package/dist/primitives/document_view-styles.d.ts.map +1 -0
- package/dist/primitives/document_view-styles.js +104 -0
- package/dist/primitives/document_view-styles.js.map +1 -0
- package/dist/primitives/document_view-toon.d.ts +37 -0
- package/dist/primitives/document_view-toon.d.ts.map +1 -0
- package/dist/primitives/document_view-toon.js +199 -0
- package/dist/primitives/document_view-toon.js.map +1 -0
- package/dist/primitives/document_view-types.d.ts +152 -0
- package/dist/primitives/document_view-types.d.ts.map +1 -0
- package/dist/primitives/document_view-types.js +2 -0
- package/dist/primitives/document_view-types.js.map +1 -0
- package/dist/primitives/document_view.d.ts +8 -106
- package/dist/primitives/document_view.d.ts.map +1 -1
- package/dist/primitives/document_view.js +153 -312
- package/dist/primitives/document_view.js.map +1 -1
- package/dist/primitives/dom-helpers.d.ts +9 -0
- package/dist/primitives/dom-helpers.d.ts.map +1 -1
- package/dist/primitives/dom-helpers.js +10 -1
- package/dist/primitives/dom-helpers.js.map +1 -1
- package/dist/primitives/footnotes.d.ts +4 -3
- package/dist/primitives/footnotes.d.ts.map +1 -1
- package/dist/primitives/footnotes.js +232 -44
- package/dist/primitives/footnotes.js.map +1 -1
- package/dist/primitives/formatting_tags.d.ts +7 -0
- package/dist/primitives/formatting_tags.d.ts.map +1 -1
- package/dist/primitives/formatting_tags.js +22 -11
- package/dist/primitives/formatting_tags.js.map +1 -1
- package/dist/primitives/index.d.ts +10 -0
- package/dist/primitives/index.d.ts.map +1 -1
- package/dist/primitives/index.js +9 -0
- package/dist/primitives/index.js.map +1 -1
- package/dist/primitives/layout.d.ts +4 -3
- package/dist/primitives/layout.d.ts.map +1 -1
- package/dist/primitives/layout.js +45 -3
- package/dist/primitives/layout.js.map +1 -1
- package/dist/primitives/merge_runs.d.ts +21 -3
- package/dist/primitives/merge_runs.d.ts.map +1 -1
- package/dist/primitives/merge_runs.js +32 -10
- package/dist/primitives/merge_runs.js.map +1 -1
- package/dist/primitives/minimal_save.d.ts +38 -0
- package/dist/primitives/minimal_save.d.ts.map +1 -0
- package/dist/primitives/minimal_save.js +323 -0
- package/dist/primitives/minimal_save.js.map +1 -0
- package/dist/primitives/namespaces.d.ts +47 -0
- package/dist/primitives/namespaces.d.ts.map +1 -1
- package/dist/primitives/namespaces.js +52 -0
- package/dist/primitives/namespaces.js.map +1 -1
- package/dist/primitives/reject_changes.d.ts +6 -4
- package/dist/primitives/reject_changes.d.ts.map +1 -1
- package/dist/primitives/reject_changes.js +187 -91
- package/dist/primitives/reject_changes.js.map +1 -1
- package/dist/primitives/revision-parts.d.ts +7 -0
- package/dist/primitives/revision-parts.d.ts.map +1 -0
- package/dist/primitives/revision-parts.js +27 -0
- package/dist/primitives/revision-parts.js.map +1 -0
- package/dist/primitives/revision-vocabulary.d.ts +7 -0
- package/dist/primitives/revision-vocabulary.d.ts.map +1 -0
- package/dist/primitives/revision-vocabulary.js +39 -0
- package/dist/primitives/revision-vocabulary.js.map +1 -0
- package/dist/primitives/schema-corpus-capture.d.ts +19 -0
- package/dist/primitives/schema-corpus-capture.d.ts.map +1 -0
- package/dist/primitives/schema-corpus-capture.js +29 -0
- package/dist/primitives/schema-corpus-capture.js.map +1 -0
- package/dist/primitives/sectPrAudit.d.ts +19 -0
- package/dist/primitives/sectPrAudit.d.ts.map +1 -0
- package/dist/primitives/sectPrAudit.js +165 -0
- package/dist/primitives/sectPrAudit.js.map +1 -0
- package/dist/primitives/semantic_tags.d.ts +7 -0
- package/dist/primitives/semantic_tags.d.ts.map +1 -1
- package/dist/primitives/semantic_tags.js +23 -4
- package/dist/primitives/semantic_tags.js.map +1 -1
- package/dist/primitives/serialize_html.d.ts +37 -0
- package/dist/primitives/serialize_html.d.ts.map +1 -0
- package/dist/primitives/serialize_html.js +395 -0
- package/dist/primitives/serialize_html.js.map +1 -0
- package/dist/primitives/serialize_markdown.d.ts +16 -0
- package/dist/primitives/serialize_markdown.d.ts.map +1 -0
- package/dist/primitives/serialize_markdown.js +300 -0
- package/dist/primitives/serialize_markdown.js.map +1 -0
- package/dist/primitives/serialize_plaintext.d.ts +15 -0
- package/dist/primitives/serialize_plaintext.d.ts.map +1 -0
- package/dist/primitives/serialize_plaintext.js +154 -0
- package/dist/primitives/serialize_plaintext.js.map +1 -0
- package/dist/primitives/styles.d.ts +15 -0
- package/dist/primitives/styles.d.ts.map +1 -1
- package/dist/primitives/styles.js +33 -22
- package/dist/primitives/styles.js.map +1 -1
- package/dist/primitives/tables.d.ts.map +1 -1
- package/dist/primitives/tables.js +13 -3
- package/dist/primitives/tables.js.map +1 -1
- package/dist/primitives/text.d.ts +2 -1
- package/dist/primitives/text.d.ts.map +1 -1
- package/dist/primitives/text.js +116 -12
- package/dist/primitives/text.js.map +1 -1
- package/dist/primitives/track-changes-emitter.d.ts +148 -0
- package/dist/primitives/track-changes-emitter.d.ts.map +1 -0
- package/dist/primitives/track-changes-emitter.js +291 -0
- package/dist/primitives/track-changes-emitter.js.map +1 -0
- package/dist/primitives/validate_ai_revisions.d.ts +35 -0
- package/dist/primitives/validate_ai_revisions.d.ts.map +1 -0
- package/dist/primitives/validate_ai_revisions.js +323 -0
- package/dist/primitives/validate_ai_revisions.js.map +1 -0
- package/dist/primitives/xml-helpers.d.ts +29 -0
- package/dist/primitives/xml-helpers.d.ts.map +1 -0
- package/dist/primitives/xml-helpers.js +35 -0
- package/dist/primitives/xml-helpers.js.map +1 -0
- package/dist/primitives/xml.d.ts +5 -0
- package/dist/primitives/xml.d.ts.map +1 -1
- package/dist/primitives/xml.js +5 -0
- package/dist/primitives/xml.js.map +1 -1
- package/dist/primitives/zip.d.ts +1 -0
- package/dist/primitives/zip.d.ts.map +1 -1
- package/dist/primitives/zip.js +21 -3
- package/dist/primitives/zip.js.map +1 -1
- package/dist/shared/field-structure.d.ts +14 -0
- package/dist/shared/field-structure.d.ts.map +1 -0
- package/dist/shared/field-structure.js +166 -0
- package/dist/shared/field-structure.js.map +1 -0
- package/dist/shared/ooxml/namespaces.d.ts +4 -1
- package/dist/shared/ooxml/namespaces.d.ts.map +1 -1
- package/dist/shared/ooxml/namespaces.js +4 -1
- package/dist/shared/ooxml/namespaces.js.map +1 -1
- package/package.json +13 -9
|
@@ -1,21 +1,101 @@
|
|
|
1
1
|
import { DocxZip } from './zip.js';
|
|
2
2
|
import { parseXml, serializeXml } from './xml.js';
|
|
3
|
+
import { maybeCaptureEmittedDocumentXml } from './schema-corpus-capture.js';
|
|
3
4
|
import { OOXML, W } from './namespaces.js';
|
|
4
|
-
import { isW, getDirectChildrenByName } from './dom-helpers.js';
|
|
5
|
+
import { createWmlElement, isW, getDirectChildrenByName } from './dom-helpers.js';
|
|
5
6
|
import { findParagraphByBookmarkId, insertParagraphBookmarks, cleanupInternalBookmarks, getParagraphBookmarkId, insertSingleParagraphBookmark, } from './bookmarks.js';
|
|
6
7
|
import { getParagraphRuns, getParagraphText, replaceParagraphTextRange } from './text.js';
|
|
8
|
+
import { allocateRevisionId, createRevisionContainer, } from './track-changes-emitter.js';
|
|
7
9
|
import { buildNodesForDocumentView } from './document_view.js';
|
|
10
|
+
import { serializeToMarkdown } from './serialize_markdown.js';
|
|
11
|
+
import { serializeToHtml } from './serialize_html.js';
|
|
12
|
+
import { serializeToPlainText } from './serialize_plaintext.js';
|
|
13
|
+
import { parseStylesXml } from './styles.js';
|
|
14
|
+
import { parseNumberingXml } from './numbering.js';
|
|
8
15
|
import { findUniqueSubstringMatch } from './matching.js';
|
|
9
16
|
import { parseDocumentRels } from './relationships.js';
|
|
10
17
|
import { setParagraphSpacing, setTableCellPadding, setTableRowHeight, } from './layout.js';
|
|
11
18
|
import { extractTables, } from './tables.js';
|
|
12
19
|
import { mergeRuns } from './merge_runs.js';
|
|
20
|
+
import { restoreUntouchedBlocks } from './minimal_save.js';
|
|
13
21
|
import { simplifyRedlines } from './simplify_redlines.js';
|
|
14
22
|
import { preventDoubleElevation } from './prevent_double_elevation.js';
|
|
15
23
|
import { validateDocument } from './validate_document.js';
|
|
24
|
+
import { validateAiRevisions as validateAiRevisionsImpl, } from './validate_ai_revisions.js';
|
|
25
|
+
import { enumerateRevisionStoryPartPaths, REVISION_STORY_PART_PATHS, } from './revision-parts.js';
|
|
16
26
|
import { acceptChanges as acceptChangesImpl } from './accept_changes.js';
|
|
27
|
+
import { rejectChanges as rejectChangesImpl } from './reject_changes.js';
|
|
17
28
|
import { bootstrapCommentParts, addComment as addCommentImpl, addCommentReply as addCommentReplyImpl, getComments as getCommentsImpl, getComment as getCommentImpl, deleteComment as deleteCommentImpl, } from './comments.js';
|
|
18
29
|
import { bootstrapFootnoteParts, getFootnotes as getFootnotesImpl, getFootnote as getFootnoteImpl, addFootnote as addFootnoteImpl, updateFootnoteText as updateFootnoteTextImpl, deleteFootnote as deleteFootnoteImpl, } from './footnotes.js';
|
|
30
|
+
function emptyAcceptChangesResult() {
|
|
31
|
+
return { insertionsAccepted: 0, deletionsAccepted: 0, movesResolved: 0, propertyChangesResolved: 0 };
|
|
32
|
+
}
|
|
33
|
+
function hasAcceptedChanges(result) {
|
|
34
|
+
return (result.insertionsAccepted > 0 ||
|
|
35
|
+
result.deletionsAccepted > 0 ||
|
|
36
|
+
result.movesResolved > 0 ||
|
|
37
|
+
result.propertyChangesResolved > 0);
|
|
38
|
+
}
|
|
39
|
+
function addAcceptChangesResult(total, result) {
|
|
40
|
+
total.insertionsAccepted += result.insertionsAccepted;
|
|
41
|
+
total.deletionsAccepted += result.deletionsAccepted;
|
|
42
|
+
total.movesResolved += result.movesResolved;
|
|
43
|
+
total.propertyChangesResolved += result.propertyChangesResolved;
|
|
44
|
+
}
|
|
45
|
+
function emptyRejectChangesResult() {
|
|
46
|
+
return { insertionsRemoved: 0, deletionsRestored: 0, movesReverted: 0, propertyChangesReverted: 0 };
|
|
47
|
+
}
|
|
48
|
+
function hasRejectedChanges(result) {
|
|
49
|
+
return (result.insertionsRemoved > 0 ||
|
|
50
|
+
result.deletionsRestored > 0 ||
|
|
51
|
+
result.movesReverted > 0 ||
|
|
52
|
+
result.propertyChangesReverted > 0);
|
|
53
|
+
}
|
|
54
|
+
function addRejectChangesResult(total, result) {
|
|
55
|
+
total.insertionsRemoved += result.insertionsRemoved;
|
|
56
|
+
total.deletionsRestored += result.deletionsRestored;
|
|
57
|
+
total.movesReverted += result.movesReverted;
|
|
58
|
+
total.propertyChangesReverted += result.propertyChangesReverted;
|
|
59
|
+
}
|
|
60
|
+
function parseWId(el) {
|
|
61
|
+
const idStr = el.getAttributeNS(OOXML.W_NS, 'id') ?? el.getAttribute('w:id');
|
|
62
|
+
if (!idStr)
|
|
63
|
+
return null;
|
|
64
|
+
const n = parseInt(idStr, 10);
|
|
65
|
+
return Number.isNaN(n) ? null : n;
|
|
66
|
+
}
|
|
67
|
+
function collectLiveFootnoteRefIds(doc) {
|
|
68
|
+
const ids = new Set();
|
|
69
|
+
const refs = doc.getElementsByTagNameNS(OOXML.W_NS, W.footnoteReference);
|
|
70
|
+
for (let i = 0; i < refs.length; i++) {
|
|
71
|
+
const id = parseWId(refs.item(i));
|
|
72
|
+
if (id !== null)
|
|
73
|
+
ids.add(id);
|
|
74
|
+
}
|
|
75
|
+
return ids;
|
|
76
|
+
}
|
|
77
|
+
// Side-effect of accept/reject on document.xml: a body w:footnoteReference that
|
|
78
|
+
// lived inside a removed w:del (accept) or w:ins (reject) is gone afterwards.
|
|
79
|
+
// The corresponding <w:footnote w:id=N> in footnotes.xml is then unreachable —
|
|
80
|
+
// remove it so the side part matches the post-sweep body. Reserved separator /
|
|
81
|
+
// continuationSeparator entries are preserved unconditionally.
|
|
82
|
+
function pruneOrphanedFootnotes(footnotesDoc, liveRefIds) {
|
|
83
|
+
const entries = Array.from(footnotesDoc.getElementsByTagNameNS(OOXML.W_NS, W.footnote));
|
|
84
|
+
let pruned = 0;
|
|
85
|
+
for (const fn of entries) {
|
|
86
|
+
const typ = fn.getAttributeNS(OOXML.W_NS, 'type') ?? fn.getAttribute('w:type');
|
|
87
|
+
if (typ === W.separator || typ === W.continuationSeparator)
|
|
88
|
+
continue;
|
|
89
|
+
const id = parseWId(fn);
|
|
90
|
+
if (id === null)
|
|
91
|
+
continue;
|
|
92
|
+
if (liveRefIds.has(id))
|
|
93
|
+
continue;
|
|
94
|
+
fn.parentNode?.removeChild(fn);
|
|
95
|
+
pruned++;
|
|
96
|
+
}
|
|
97
|
+
return pruned;
|
|
98
|
+
}
|
|
19
99
|
function prevElementSibling(node) {
|
|
20
100
|
let cur = node?.previousSibling ?? null;
|
|
21
101
|
while (cur) {
|
|
@@ -228,7 +308,13 @@ export class DocxDocument {
|
|
|
228
308
|
relsMap;
|
|
229
309
|
dirty;
|
|
230
310
|
documentViewCache;
|
|
231
|
-
|
|
311
|
+
/**
|
|
312
|
+
* Raw document.xml text as loaded, before normalize()/edits mutate the DOM.
|
|
313
|
+
* Reference for minimal re-serialization in toBuffer(); null for instances
|
|
314
|
+
* not created via load().
|
|
315
|
+
*/
|
|
316
|
+
originalDocumentXmlText;
|
|
317
|
+
constructor(zip, documentXml, stylesXml, numberingXml, footnotesXml, relsMap, originalDocumentXmlText = null) {
|
|
232
318
|
this.zip = zip;
|
|
233
319
|
this.documentXml = documentXml;
|
|
234
320
|
this.stylesXml = stylesXml;
|
|
@@ -237,6 +323,7 @@ export class DocxDocument {
|
|
|
237
323
|
this.relsMap = relsMap;
|
|
238
324
|
this.dirty = false;
|
|
239
325
|
this.documentViewCache = null;
|
|
326
|
+
this.originalDocumentXmlText = originalDocumentXmlText;
|
|
240
327
|
}
|
|
241
328
|
static async load(buffer) {
|
|
242
329
|
const zip = await DocxZip.load(buffer);
|
|
@@ -253,7 +340,7 @@ export class DocxDocument {
|
|
|
253
340
|
// Load document relationships for hyperlink resolution.
|
|
254
341
|
const relsText = await zip.readTextOrNull('word/_rels/document.xml.rels');
|
|
255
342
|
const relsMap = relsText ? parseDocumentRels(parseXml(relsText)) : new Map();
|
|
256
|
-
return new DocxDocument(zip, doc, stylesXml, numberingXml, footnotesXml, relsMap);
|
|
343
|
+
return new DocxDocument(zip, doc, stylesXml, numberingXml, footnotesXml, relsMap, xml);
|
|
257
344
|
}
|
|
258
345
|
getParagraphs() {
|
|
259
346
|
const body = this.documentXml.getElementsByTagNameNS(OOXML.W_NS, W.body).item(0);
|
|
@@ -310,20 +397,96 @@ export class DocxDocument {
|
|
|
310
397
|
validate() {
|
|
311
398
|
return validateDocument(this.documentXml);
|
|
312
399
|
}
|
|
400
|
+
async validateAiRevisions(aiAuthor, touched) {
|
|
401
|
+
const stories = [{ part: 'word/document.xml', doc: this.documentXml }];
|
|
402
|
+
for (const partPath of enumerateRevisionStoryPartPaths(this.zip)) {
|
|
403
|
+
const xml = await this.zip.readTextOrNull(partPath);
|
|
404
|
+
if (!xml)
|
|
405
|
+
continue;
|
|
406
|
+
stories.push({ part: partPath, doc: parseXml(xml) });
|
|
407
|
+
}
|
|
408
|
+
return validateAiRevisionsImpl({
|
|
409
|
+
aiAuthor,
|
|
410
|
+
stories,
|
|
411
|
+
packageZip: this.zip,
|
|
412
|
+
touched,
|
|
413
|
+
});
|
|
414
|
+
}
|
|
313
415
|
/**
|
|
314
|
-
* Accept all tracked changes in
|
|
315
|
-
*
|
|
416
|
+
* Accept all tracked changes in document.xml plus supported revisionable
|
|
417
|
+
* side-story parts, producing clean XML with no revision markup.
|
|
316
418
|
*/
|
|
317
|
-
acceptChanges() {
|
|
318
|
-
const
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
419
|
+
async acceptChanges() {
|
|
420
|
+
const total = emptyAcceptChangesResult();
|
|
421
|
+
const bodyResult = acceptChangesImpl(this.documentXml);
|
|
422
|
+
addAcceptChangesResult(total, bodyResult);
|
|
423
|
+
// After accepting, footnotes whose body reference lived inside a removed
|
|
424
|
+
// w:del are orphaned. Only worth checking when the body sweep removed
|
|
425
|
+
// deletions (the only operation that can drop a footnoteReference).
|
|
426
|
+
const liveFootnoteRefIds = bodyResult.deletionsAccepted > 0
|
|
427
|
+
? collectLiveFootnoteRefIds(this.documentXml)
|
|
428
|
+
: null;
|
|
429
|
+
for (const partPath of REVISION_STORY_PART_PATHS) {
|
|
430
|
+
const xml = await this.zip.readTextOrNull(partPath);
|
|
431
|
+
if (!xml)
|
|
432
|
+
continue;
|
|
433
|
+
const partDoc = parseXml(xml);
|
|
434
|
+
const partResult = acceptChangesImpl(partDoc);
|
|
435
|
+
addAcceptChangesResult(total, partResult);
|
|
436
|
+
let footnotesPruned = 0;
|
|
437
|
+
if (partPath === 'word/footnotes.xml' && liveFootnoteRefIds) {
|
|
438
|
+
footnotesPruned = pruneOrphanedFootnotes(partDoc, liveFootnoteRefIds);
|
|
439
|
+
}
|
|
440
|
+
if (hasAcceptedChanges(partResult) || footnotesPruned > 0) {
|
|
441
|
+
this.zip.writeText(partPath, serializeXml(partDoc));
|
|
442
|
+
if (partPath === 'word/footnotes.xml') {
|
|
443
|
+
this.footnotesXml = partDoc;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
if (hasAcceptedChanges(total)) {
|
|
323
448
|
this.dirty = true;
|
|
324
449
|
this.documentViewCache = null;
|
|
325
450
|
}
|
|
326
|
-
return
|
|
451
|
+
return total;
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Reject all tracked changes in document.xml plus supported revisionable
|
|
455
|
+
* side-story parts, restoring their pre-edit state where possible.
|
|
456
|
+
*/
|
|
457
|
+
async rejectChanges() {
|
|
458
|
+
const total = emptyRejectChangesResult();
|
|
459
|
+
const bodyResult = rejectChangesImpl(this.documentXml);
|
|
460
|
+
addRejectChangesResult(total, bodyResult);
|
|
461
|
+
// After rejecting, footnotes whose body reference lived inside a removed
|
|
462
|
+
// w:ins are orphaned. Only worth checking when the body sweep removed
|
|
463
|
+
// insertions (the only operation that can drop a footnoteReference).
|
|
464
|
+
const liveFootnoteRefIds = bodyResult.insertionsRemoved > 0
|
|
465
|
+
? collectLiveFootnoteRefIds(this.documentXml)
|
|
466
|
+
: null;
|
|
467
|
+
for (const partPath of REVISION_STORY_PART_PATHS) {
|
|
468
|
+
const xml = await this.zip.readTextOrNull(partPath);
|
|
469
|
+
if (!xml)
|
|
470
|
+
continue;
|
|
471
|
+
const partDoc = parseXml(xml);
|
|
472
|
+
const partResult = rejectChangesImpl(partDoc);
|
|
473
|
+
addRejectChangesResult(total, partResult);
|
|
474
|
+
let footnotesPruned = 0;
|
|
475
|
+
if (partPath === 'word/footnotes.xml' && liveFootnoteRefIds) {
|
|
476
|
+
footnotesPruned = pruneOrphanedFootnotes(partDoc, liveFootnoteRefIds);
|
|
477
|
+
}
|
|
478
|
+
if (hasRejectedChanges(partResult) || footnotesPruned > 0) {
|
|
479
|
+
this.zip.writeText(partPath, serializeXml(partDoc));
|
|
480
|
+
if (partPath === 'word/footnotes.xml') {
|
|
481
|
+
this.footnotesXml = partDoc;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
if (hasRejectedChanges(total)) {
|
|
486
|
+
this.dirty = true;
|
|
487
|
+
this.documentViewCache = null;
|
|
488
|
+
}
|
|
489
|
+
return total;
|
|
327
490
|
}
|
|
328
491
|
removeJuniorBookmarks() {
|
|
329
492
|
const removed = cleanupInternalBookmarks(this.documentXml);
|
|
@@ -360,6 +523,23 @@ export class DocxDocument {
|
|
|
360
523
|
const endIdx = typeof limit === 'number' ? Math.min(total, startIdx + limit) : total;
|
|
361
524
|
return { paragraphs: all.slice(startIdx, endIdx), totalParagraphs: total };
|
|
362
525
|
}
|
|
526
|
+
/**
|
|
527
|
+
* Parsed `word/numbering.xml` model (abstract numberings + instances), or null when the
|
|
528
|
+
* document has no numbering part. The document view's `numbering` field only carries
|
|
529
|
+
* `num_id`/`ilvl`; semantic converters (DOCX → ODT) need `numFmt`/`lvlText`/`start` to
|
|
530
|
+
* synthesize target-format list styles, so the full model is exposed here.
|
|
531
|
+
*/
|
|
532
|
+
getNumberingModel() {
|
|
533
|
+
return this.numberingXml ? parseNumberingXml(this.numberingXml) : null;
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Parsed named-style model of the loaded document (empty when the package has no
|
|
537
|
+
* `word/styles.xml`). Semantic converters (DOCX → ODT) resolve heading/body style chains
|
|
538
|
+
* through it to seed their own style templates from the source's definitions.
|
|
539
|
+
*/
|
|
540
|
+
getStylesModel() {
|
|
541
|
+
return parseStylesXml(this.stylesXml);
|
|
542
|
+
}
|
|
363
543
|
buildDocumentView(opts) {
|
|
364
544
|
const includeSemanticTags = opts?.includeSemanticTags ?? true;
|
|
365
545
|
const showFormatting = opts?.showFormatting ?? false;
|
|
@@ -425,7 +605,7 @@ export class DocxDocument {
|
|
|
425
605
|
this.dirty = true;
|
|
426
606
|
this.documentViewCache = null;
|
|
427
607
|
}
|
|
428
|
-
insertParagraph(params) {
|
|
608
|
+
insertParagraph(params, ctx) {
|
|
429
609
|
const { positionalAnchorNodeId, relativePosition, newText, newParagraphId: _newParagraphId, styleSourceId } = params;
|
|
430
610
|
const anchor = findParagraphByBookmarkId(this.documentXml, positionalAnchorNodeId);
|
|
431
611
|
if (!anchor)
|
|
@@ -505,8 +685,86 @@ export class DocxDocument {
|
|
|
505
685
|
continue;
|
|
506
686
|
newP.removeChild(child);
|
|
507
687
|
}
|
|
688
|
+
// sectPr is the section terminator — must stay on the anchor, not propagate to the new paragraph.
|
|
689
|
+
const clonedPPr = getDirectChildrenByName(newP, W.pPr)[0];
|
|
690
|
+
if (clonedPPr) {
|
|
691
|
+
for (const sectPr of getDirectChildrenByName(clonedPPr, 'sectPr')) {
|
|
692
|
+
clonedPPr.removeChild(sectPr);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
508
695
|
return newP;
|
|
509
696
|
}
|
|
697
|
+
function ensureParagraphProperties(paragraph) {
|
|
698
|
+
const existing = getDirectChildrenByName(paragraph, W.pPr)[0];
|
|
699
|
+
if (existing)
|
|
700
|
+
return existing;
|
|
701
|
+
const pPr = createWmlElement(doc, W.pPr);
|
|
702
|
+
paragraph.insertBefore(pPr, paragraph.firstChild);
|
|
703
|
+
return pPr;
|
|
704
|
+
}
|
|
705
|
+
function ensureParagraphRunProperties(pPr) {
|
|
706
|
+
const existing = getDirectChildrenByName(pPr, W.rPr)[0];
|
|
707
|
+
if (existing)
|
|
708
|
+
return existing;
|
|
709
|
+
const rPr = createWmlElement(doc, W.rPr);
|
|
710
|
+
const sectPr = getDirectChildrenByName(pPr, 'sectPr')[0];
|
|
711
|
+
const pPrChange = getDirectChildrenByName(pPr, 'pPrChange')[0];
|
|
712
|
+
const insertBefore = sectPr ?? pPrChange ?? null;
|
|
713
|
+
if (insertBefore) {
|
|
714
|
+
pPr.insertBefore(rPr, insertBefore);
|
|
715
|
+
}
|
|
716
|
+
else {
|
|
717
|
+
pPr.appendChild(rPr);
|
|
718
|
+
}
|
|
719
|
+
return rPr;
|
|
720
|
+
}
|
|
721
|
+
function addParagraphInsertionMarker(paragraph, revisionCtx) {
|
|
722
|
+
const pPr = ensureParagraphProperties(paragraph);
|
|
723
|
+
const rPr = ensureParagraphRunProperties(pPr);
|
|
724
|
+
const marker = createWmlElement(doc, 'ins', {
|
|
725
|
+
'w:id': String(allocateRevisionId(revisionCtx.idState)),
|
|
726
|
+
'w:author': revisionCtx.author,
|
|
727
|
+
'w:date': revisionCtx.date,
|
|
728
|
+
});
|
|
729
|
+
rPr.insertBefore(marker, rPr.firstChild);
|
|
730
|
+
}
|
|
731
|
+
function clearRunPropertyRevisionMarkup(run) {
|
|
732
|
+
const rPr = getDirectChildrenByName(run, W.rPr)[0];
|
|
733
|
+
if (!rPr)
|
|
734
|
+
return;
|
|
735
|
+
for (const child of Array.from(rPr.childNodes)) {
|
|
736
|
+
if (child.nodeType !== 1)
|
|
737
|
+
continue;
|
|
738
|
+
const element = child;
|
|
739
|
+
if (isW(element, 'rPrChange')) {
|
|
740
|
+
rPr.removeChild(element);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
function clearParagraphPropertyRevisionMarkup(paragraph) {
|
|
745
|
+
const pPr = getDirectChildrenByName(paragraph, W.pPr)[0];
|
|
746
|
+
if (!pPr)
|
|
747
|
+
return;
|
|
748
|
+
for (const pPrChange of getDirectChildrenByName(pPr, 'pPrChange')) {
|
|
749
|
+
pPr.removeChild(pPrChange);
|
|
750
|
+
}
|
|
751
|
+
const rPr = getDirectChildrenByName(pPr, W.rPr)[0];
|
|
752
|
+
if (!rPr)
|
|
753
|
+
return;
|
|
754
|
+
for (const child of Array.from(rPr.childNodes)) {
|
|
755
|
+
if (child.nodeType !== 1)
|
|
756
|
+
continue;
|
|
757
|
+
const element = child;
|
|
758
|
+
// CT_ParaRPr revision children: w:ins, w:del, w:moveFrom, w:moveTo, w:rPrChange.
|
|
759
|
+
if (isW(element, 'ins') ||
|
|
760
|
+
isW(element, 'del') ||
|
|
761
|
+
isW(element, 'moveFrom') ||
|
|
762
|
+
isW(element, 'moveTo') ||
|
|
763
|
+
isW(element, 'rPrChange')) {
|
|
764
|
+
rPr.removeChild(element);
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
}
|
|
510
768
|
function getInsertionRefNode() {
|
|
511
769
|
if (relativePosition === 'BEFORE') {
|
|
512
770
|
const prev = prevElementSibling(anchorP);
|
|
@@ -538,7 +796,17 @@ export class DocxDocument {
|
|
|
538
796
|
const newP = cloneParagraphShell(formattingSource);
|
|
539
797
|
const newRun = cloneRunFormattingOnly(templateRun);
|
|
540
798
|
appendTextToRun(newRun, paraText);
|
|
541
|
-
|
|
799
|
+
if (ctx) {
|
|
800
|
+
clearRunPropertyRevisionMarkup(newRun);
|
|
801
|
+
clearParagraphPropertyRevisionMarkup(newP);
|
|
802
|
+
addParagraphInsertionMarker(newP, ctx);
|
|
803
|
+
const insertion = createRevisionContainer(doc, 'ins', ctx);
|
|
804
|
+
insertion.appendChild(newRun);
|
|
805
|
+
newP.appendChild(insertion);
|
|
806
|
+
}
|
|
807
|
+
else {
|
|
808
|
+
newP.appendChild(newRun);
|
|
809
|
+
}
|
|
542
810
|
parent.insertBefore(newP, cursor);
|
|
543
811
|
const id = insertSingleParagraphBookmark(doc, newP);
|
|
544
812
|
insertedIds.push(id);
|
|
@@ -557,24 +825,24 @@ export class DocxDocument {
|
|
|
557
825
|
result.styleSourceFallback = true;
|
|
558
826
|
return result;
|
|
559
827
|
}
|
|
560
|
-
setParagraphSpacing(mutation) {
|
|
561
|
-
const result = setParagraphSpacing(this.documentXml, mutation);
|
|
828
|
+
setParagraphSpacing(mutation, ctx) {
|
|
829
|
+
const result = setParagraphSpacing(this.documentXml, mutation, ctx);
|
|
562
830
|
if (result.affectedParagraphs > 0) {
|
|
563
831
|
this.dirty = true;
|
|
564
832
|
this.documentViewCache = null;
|
|
565
833
|
}
|
|
566
834
|
return result;
|
|
567
835
|
}
|
|
568
|
-
setTableRowHeight(mutation) {
|
|
569
|
-
const result = setTableRowHeight(this.documentXml, mutation);
|
|
836
|
+
setTableRowHeight(mutation, ctx) {
|
|
837
|
+
const result = setTableRowHeight(this.documentXml, mutation, ctx);
|
|
570
838
|
if (result.affectedRows > 0) {
|
|
571
839
|
this.dirty = true;
|
|
572
840
|
this.documentViewCache = null;
|
|
573
841
|
}
|
|
574
842
|
return result;
|
|
575
843
|
}
|
|
576
|
-
setTableCellPadding(mutation) {
|
|
577
|
-
const result = setTableCellPadding(this.documentXml, mutation);
|
|
844
|
+
setTableCellPadding(mutation, ctx) {
|
|
845
|
+
const result = setTableCellPadding(this.documentXml, mutation, ctx);
|
|
578
846
|
if (result.affectedCells > 0) {
|
|
579
847
|
this.dirty = true;
|
|
580
848
|
this.documentViewCache = null;
|
|
@@ -591,9 +859,11 @@ export class DocxDocument {
|
|
|
591
859
|
/**
|
|
592
860
|
* Merge format-identical adjacent runs only (no redline simplification).
|
|
593
861
|
* Useful as a pre-processing step before text search when runs may be fragmented.
|
|
862
|
+
* Pass `{ preserveRsidIdentity: true }` from edit pipelines that must not
|
|
863
|
+
* disturb rsid attributes on runs the caller did not touch (#286).
|
|
594
864
|
*/
|
|
595
|
-
mergeRunsOnly() {
|
|
596
|
-
const result = mergeRuns(this.documentXml);
|
|
865
|
+
mergeRunsOnly(opts = {}) {
|
|
866
|
+
const result = mergeRuns(this.documentXml, opts);
|
|
597
867
|
if (result.runsMerged > 0) {
|
|
598
868
|
this.dirty = true;
|
|
599
869
|
this.documentViewCache = null;
|
|
@@ -606,7 +876,7 @@ export class DocxDocument {
|
|
|
606
876
|
* Bootstraps comment parts if missing (idempotent).
|
|
607
877
|
* Returns the allocated comment ID.
|
|
608
878
|
*/
|
|
609
|
-
async addComment(params) {
|
|
879
|
+
async addComment(params, ctx) {
|
|
610
880
|
const p = findParagraphByBookmarkId(this.documentXml, params.paragraphId);
|
|
611
881
|
if (!p)
|
|
612
882
|
throw new Error(`Paragraph not found: ${params.paragraphId}`);
|
|
@@ -618,7 +888,7 @@ export class DocxDocument {
|
|
|
618
888
|
author: params.author,
|
|
619
889
|
text: params.text,
|
|
620
890
|
initials: params.initials,
|
|
621
|
-
});
|
|
891
|
+
}, ctx);
|
|
622
892
|
this.dirty = true;
|
|
623
893
|
this.documentViewCache = null;
|
|
624
894
|
return result;
|
|
@@ -629,14 +899,14 @@ export class DocxDocument {
|
|
|
629
899
|
* Bootstraps comment parts if missing (idempotent).
|
|
630
900
|
* Returns the allocated comment ID and parent ID.
|
|
631
901
|
*/
|
|
632
|
-
async addCommentReply(params) {
|
|
902
|
+
async addCommentReply(params, ctx) {
|
|
633
903
|
await bootstrapCommentParts(this.zip);
|
|
634
904
|
const result = await addCommentReplyImpl(this.documentXml, this.zip, {
|
|
635
905
|
parentCommentId: params.parentCommentId,
|
|
636
906
|
author: params.author,
|
|
637
907
|
text: params.text,
|
|
638
908
|
initials: params.initials,
|
|
639
|
-
});
|
|
909
|
+
}, ctx);
|
|
640
910
|
this.dirty = true;
|
|
641
911
|
this.documentViewCache = null;
|
|
642
912
|
return result;
|
|
@@ -647,8 +917,8 @@ export class DocxDocument {
|
|
|
647
917
|
async getComment(commentId) {
|
|
648
918
|
return getCommentImpl(this.zip, this.documentXml, commentId);
|
|
649
919
|
}
|
|
650
|
-
async deleteComment(params) {
|
|
651
|
-
await deleteCommentImpl(this.documentXml, this.zip, params);
|
|
920
|
+
async deleteComment(params, ctx) {
|
|
921
|
+
await deleteCommentImpl(this.documentXml, this.zip, params, ctx);
|
|
652
922
|
this.dirty = true;
|
|
653
923
|
this.documentViewCache = null;
|
|
654
924
|
}
|
|
@@ -660,6 +930,47 @@ export class DocxDocument {
|
|
|
660
930
|
async getFootnotes() {
|
|
661
931
|
return getFootnotesImpl(this.zip, this.documentXml);
|
|
662
932
|
}
|
|
933
|
+
/**
|
|
934
|
+
* Serialize the document to GitHub-Flavored Markdown. Convenience wrapper that wires the
|
|
935
|
+
* structured document view (with inline formatting) and footnotes into
|
|
936
|
+
* {@link serializeToMarkdown}. Markdown is intentionally lossy — see that serializer.
|
|
937
|
+
*
|
|
938
|
+
* Async because footnote extraction reads the footnotes part from the zip.
|
|
939
|
+
*/
|
|
940
|
+
async toMarkdown(opts) {
|
|
941
|
+
const { nodes } = this.buildDocumentView({ showFormatting: true });
|
|
942
|
+
const footnotes = await this.getFootnotes();
|
|
943
|
+
return serializeToMarkdown(nodes, footnotes, opts);
|
|
944
|
+
}
|
|
945
|
+
/**
|
|
946
|
+
* Serialize the document to semantic HTML. Convenience wrapper that wires the structured
|
|
947
|
+
* document view (with inline formatting) and footnotes into {@link serializeToHtml}. The
|
|
948
|
+
* default output is a complete `<!DOCTYPE html>` document; pass `{ fragment: true }` for the
|
|
949
|
+
* body-level elements only. This is the semantic tier — exact layout is not reproduced.
|
|
950
|
+
*
|
|
951
|
+
* Async because footnote extraction reads the footnotes part from the zip.
|
|
952
|
+
*/
|
|
953
|
+
async toHtml(opts) {
|
|
954
|
+
const { nodes } = this.buildDocumentView({ showFormatting: true });
|
|
955
|
+
const footnotes = await this.getFootnotes();
|
|
956
|
+
return serializeToHtml(nodes, footnotes, opts);
|
|
957
|
+
}
|
|
958
|
+
/**
|
|
959
|
+
* Serialize the document to plain text (no markup). Convenience wrapper that wires the
|
|
960
|
+
* structured document view and footnotes into {@link serializeToPlainText}. All formatting
|
|
961
|
+
* is stripped; block structure survives as blank-line-separated paragraphs, `- ` bullets,
|
|
962
|
+
* and tab-separated table rows. Intentionally lossy — see that serializer.
|
|
963
|
+
*
|
|
964
|
+
* Uses the same `showFormatting: true` view as {@link toMarkdown} so the block structure
|
|
965
|
+
* and injected `[^n]` footnote markers match; the inline tags it produces are then stripped.
|
|
966
|
+
*
|
|
967
|
+
* Async because footnote extraction reads the footnotes part from the zip.
|
|
968
|
+
*/
|
|
969
|
+
async toPlainText(opts) {
|
|
970
|
+
const { nodes } = this.buildDocumentView({ showFormatting: true });
|
|
971
|
+
const footnotes = await this.getFootnotes();
|
|
972
|
+
return serializeToPlainText(nodes, footnotes, opts);
|
|
973
|
+
}
|
|
663
974
|
async getFootnote(noteId) {
|
|
664
975
|
return getFootnoteImpl(this.zip, this.documentXml, noteId);
|
|
665
976
|
}
|
|
@@ -669,7 +980,7 @@ export class DocxDocument {
|
|
|
669
980
|
* Bootstraps footnote parts if missing (idempotent).
|
|
670
981
|
* Returns the allocated footnote ID.
|
|
671
982
|
*/
|
|
672
|
-
async addFootnote(params) {
|
|
983
|
+
async addFootnote(params, ctx) {
|
|
673
984
|
const p = findParagraphByBookmarkId(this.documentXml, params.paragraphId);
|
|
674
985
|
if (!p)
|
|
675
986
|
throw new Error(`Paragraph not found: ${params.paragraphId}`);
|
|
@@ -678,7 +989,7 @@ export class DocxDocument {
|
|
|
678
989
|
paragraphEl: p,
|
|
679
990
|
afterText: params.afterText,
|
|
680
991
|
text: params.text,
|
|
681
|
-
});
|
|
992
|
+
}, ctx);
|
|
682
993
|
await this.refreshFootnotesXml();
|
|
683
994
|
this.dirty = true;
|
|
684
995
|
this.documentViewCache = null;
|
|
@@ -687,8 +998,8 @@ export class DocxDocument {
|
|
|
687
998
|
/**
|
|
688
999
|
* Update the text content of an existing footnote.
|
|
689
1000
|
*/
|
|
690
|
-
async updateFootnoteText(params) {
|
|
691
|
-
await updateFootnoteTextImpl(this.zip, params);
|
|
1001
|
+
async updateFootnoteText(params, ctx) {
|
|
1002
|
+
await updateFootnoteTextImpl(this.zip, params, ctx);
|
|
692
1003
|
await this.refreshFootnotesXml();
|
|
693
1004
|
this.dirty = true;
|
|
694
1005
|
this.documentViewCache = null;
|
|
@@ -696,8 +1007,8 @@ export class DocxDocument {
|
|
|
696
1007
|
/**
|
|
697
1008
|
* Delete a footnote and its references from the document.
|
|
698
1009
|
*/
|
|
699
|
-
async deleteFootnote(params) {
|
|
700
|
-
await deleteFootnoteImpl(this.documentXml, this.zip, params);
|
|
1010
|
+
async deleteFootnote(params, ctx) {
|
|
1011
|
+
await deleteFootnoteImpl(this.documentXml, this.zip, params, ctx);
|
|
701
1012
|
await this.refreshFootnotesXml();
|
|
702
1013
|
this.dirty = true;
|
|
703
1014
|
this.documentViewCache = null;
|
|
@@ -720,23 +1031,49 @@ export class DocxDocument {
|
|
|
720
1031
|
return null;
|
|
721
1032
|
return parseXml(commentsText);
|
|
722
1033
|
}
|
|
1034
|
+
/**
|
|
1035
|
+
* Serialize the document to a .docx buffer.
|
|
1036
|
+
*
|
|
1037
|
+
* With `minimalReserialization` (requires `cleanBookmarks`), top-level body
|
|
1038
|
+
* blocks that no edit touched are restored element-for-element from the
|
|
1039
|
+
* original document.xml instead of carrying the open-time normalization
|
|
1040
|
+
* (proofErr stripping, run merging) to disk — so output diffs reflect the
|
|
1041
|
+
* actual edit blast radius. Edited/inserted blocks are emitted as-is.
|
|
1042
|
+
* Falls back to full re-serialization (blocksRestored: 0) when no original
|
|
1043
|
+
* text was captured or reconciliation fails.
|
|
1044
|
+
*
|
|
1045
|
+
* @see https://github.com/UseJunior/safe-docx/issues/408
|
|
1046
|
+
*/
|
|
723
1047
|
async toBuffer(opts) {
|
|
724
1048
|
// Always write the latest document.xml when saving.
|
|
725
1049
|
// Important: when cleanBookmarks=true (download), we must NOT mutate session state.
|
|
726
1050
|
const xmlWithBookmarks = serializeXml(this.documentXml);
|
|
1051
|
+
maybeCaptureEmittedDocumentXml(xmlWithBookmarks);
|
|
727
1052
|
this.zip.writeText('word/document.xml', xmlWithBookmarks);
|
|
728
1053
|
if (opts?.cleanBookmarks) {
|
|
729
1054
|
const cloned = parseXml(xmlWithBookmarks);
|
|
730
1055
|
const bookmarksRemoved = cleanupInternalBookmarks(cloned);
|
|
1056
|
+
let blocksRestored = 0;
|
|
1057
|
+
if (opts.minimalReserialization && this.originalDocumentXmlText !== null) {
|
|
1058
|
+
try {
|
|
1059
|
+
blocksRestored = restoreUntouchedBlocks(cloned, this.originalDocumentXmlText);
|
|
1060
|
+
}
|
|
1061
|
+
catch {
|
|
1062
|
+
// Reconciliation is best-effort; the fully re-serialized DOM is
|
|
1063
|
+
// always a correct (if non-minimal) save.
|
|
1064
|
+
blocksRestored = 0;
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
731
1067
|
const cleanedXml = serializeXml(cloned);
|
|
732
1068
|
// Temporarily swap document.xml in the zip for output, then restore.
|
|
1069
|
+
maybeCaptureEmittedDocumentXml(cleanedXml);
|
|
733
1070
|
this.zip.writeText('word/document.xml', cleanedXml);
|
|
734
1071
|
const buffer = await this.zip.toBuffer();
|
|
735
1072
|
this.zip.writeText('word/document.xml', xmlWithBookmarks);
|
|
736
|
-
return { buffer, bookmarksRemoved };
|
|
1073
|
+
return { buffer, bookmarksRemoved, blocksRestored };
|
|
737
1074
|
}
|
|
738
1075
|
const buffer = await this.zip.toBuffer();
|
|
739
|
-
return { buffer, bookmarksRemoved: 0 };
|
|
1076
|
+
return { buffer, bookmarksRemoved: 0, blocksRestored: 0 };
|
|
740
1077
|
}
|
|
741
1078
|
}
|
|
742
1079
|
//# sourceMappingURL=document.js.map
|