@usejunior/docx-core 0.9.0 → 0.10.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/.tsbuildinfo +1 -1
- package/dist/atomizer.d.ts +49 -0
- package/dist/atomizer.d.ts.map +1 -1
- package/dist/atomizer.js +90 -0
- package/dist/atomizer.js.map +1 -1
- package/dist/baselines/atomizer/documentReconstructor.d.ts.map +1 -1
- package/dist/baselines/atomizer/documentReconstructor.js +289 -92
- 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 +189 -0
- package/dist/baselines/atomizer/inPlaceModifier-wrappers.d.ts.map +1 -0
- package/dist/baselines/atomizer/inPlaceModifier-wrappers.js +427 -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 +76 -1
- package/dist/baselines/atomizer/pipeline.d.ts.map +1 -1
- package/dist/baselines/atomizer/pipeline.js +445 -108
- 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 +56 -160
- package/dist/baselines/atomizer/trackChangesAcceptorAst.js.map +1 -1
- package/dist/compare-types.d.ts +151 -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/index.d.ts +6 -150
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/integration/libreoffice-oracle.d.ts +41 -0
- package/dist/integration/libreoffice-oracle.d.ts.map +1 -0
- package/dist/integration/libreoffice-oracle.js +282 -0
- package/dist/integration/libreoffice-oracle.js.map +1 -0
- package/dist/integration/synthetic-docx-fixture.d.ts +62 -0
- package/dist/integration/synthetic-docx-fixture.d.ts.map +1 -0
- package/dist/integration/synthetic-docx-fixture.js +171 -0
- package/dist/integration/synthetic-docx-fixture.js.map +1 -0
- package/dist/primitives/accept_changes.d.ts +2 -2
- package/dist/primitives/accept_changes.d.ts.map +1 -1
- package/dist/primitives/accept_changes.js +24 -79
- 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 +56 -15
- package/dist/primitives/document.d.ts.map +1 -1
- package/dist/primitives/document.js +303 -32
- 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 +159 -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 +137 -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 +134 -301
- 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 +6 -0
- package/dist/primitives/formatting_tags.d.ts.map +1 -1
- package/dist/primitives/formatting_tags.js +6 -1
- package/dist/primitives/formatting_tags.js.map +1 -1
- package/dist/primitives/index.d.ts +6 -0
- package/dist/primitives/index.d.ts.map +1 -1
- package/dist/primitives/index.js +5 -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 +32 -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/namespaces.d.ts +6 -0
- package/dist/primitives/namespaces.d.ts.map +1 -1
- package/dist/primitives/namespaces.js +9 -0
- package/dist/primitives/namespaces.js.map +1 -1
- package/dist/primitives/reject_changes.d.ts +2 -2
- package/dist/primitives/reject_changes.d.ts.map +1 -1
- package/dist/primitives/reject_changes.js +24 -81
- package/dist/primitives/reject_changes.js.map +1 -1
- 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 +21 -3
- package/dist/primitives/semantic_tags.js.map +1 -1
- package/dist/primitives/serialize_html.d.ts +36 -0
- package/dist/primitives/serialize_html.d.ts.map +1 -0
- package/dist/primitives/serialize_html.js +393 -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.js +22 -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 +139 -0
- package/dist/primitives/track-changes-emitter.d.ts.map +1 -0
- package/dist/primitives/track-changes-emitter.js +241 -0
- package/dist/primitives/track-changes-emitter.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/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 +7 -6
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LibreOffice accept/reject oracle — a committed, reproducible reference voter.
|
|
3
|
+
*
|
|
4
|
+
* Drives LibreOffice headless as a track-changes accept/reject implementation so the
|
|
5
|
+
* production engine's paragraph-collapse behavior (the G3/G4/G5 differential cases) can be
|
|
6
|
+
* validated against a real word processor, not just Lean↔TS self-consistency. LibreOffice is
|
|
7
|
+
* the native engine for the .uno:AcceptAllTrackedChanges / .uno:RejectAllTrackedChanges
|
|
8
|
+
* dispatches, so its paragraph-structure output is authoritative ground truth for the
|
|
9
|
+
* mark-based rule (an untracked paragraph mark is kept on accept/reject; a PPR-INS/PPR-DEL mark
|
|
10
|
+
* is dropped).
|
|
11
|
+
*
|
|
12
|
+
* Mechanism (macOS-portable; also works on Linux): pyuno from a terminal is blocked on macOS by
|
|
13
|
+
* Launch Constraints, so this injects a Basic macro into a throwaway user profile and invokes it
|
|
14
|
+
* with a bare `macro:///` URL. The order matters — a fresh profile regenerates the Standard Basic
|
|
15
|
+
* library on first launch, clobbering any hand-placed Module1.xba — so we (1) init the profile via
|
|
16
|
+
* a throwaway convert, (2) THEN overwrite Module1.xba, (3) THEN run the macro. See
|
|
17
|
+
* reference_libreoffice_macos_oracle.
|
|
18
|
+
*
|
|
19
|
+
* This module is gated by callers: when `resolveSoffice()` returns null the oracle is skipped.
|
|
20
|
+
* CI does not install LibreOffice, so the oracle voter is a local developer check.
|
|
21
|
+
*/
|
|
22
|
+
import { execFile } from 'node:child_process';
|
|
23
|
+
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
24
|
+
import os from 'node:os';
|
|
25
|
+
import path from 'node:path';
|
|
26
|
+
import { pathToFileURL } from 'node:url';
|
|
27
|
+
import { promisify } from 'node:util';
|
|
28
|
+
import { createZipBuffer, readZipText } from '../primitives/zip.js';
|
|
29
|
+
import { parseXml } from '../primitives/xml.js';
|
|
30
|
+
const execFileAsync = promisify(execFile);
|
|
31
|
+
const W_NS = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
|
|
32
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
33
|
+
/** Run soffice, capturing stdout/stderr; never throws (the macro terminates the desktop, so a
|
|
34
|
+
* nonzero exit is expected). */
|
|
35
|
+
async function runSoffice(soffice, args, timeout) {
|
|
36
|
+
try {
|
|
37
|
+
const r = await execFileAsync(soffice, args, { timeout, killSignal: 'SIGKILL', maxBuffer: 8 * 1024 * 1024 });
|
|
38
|
+
return { stdout: String(r.stdout ?? ''), stderr: String(r.stderr ?? '') };
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
const e = err;
|
|
42
|
+
return { stdout: String(e.stdout ?? ''), stderr: String(e.stderr ?? e.message ?? '') };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* LibreOffice's single-instance model forwards a new `soffice` invocation to an existing instance
|
|
47
|
+
* that shares the same UserInstallation — so the init-convert process MUST be fully gone before the
|
|
48
|
+
* macro launch, or the `macro:///` command is delivered to the dying init instance (which has no
|
|
49
|
+
* Module1 yet) and never runs. The instance lock is `<profile>/.lock`. LibreOffice often leaves a
|
|
50
|
+
* STALE lock after `--convert-to` exits, so we wait a short bounded window for it to self-clear and
|
|
51
|
+
* then remove it unconditionally; the macro launch's own retry backstops a slow init exit.
|
|
52
|
+
*/
|
|
53
|
+
async function settleProfile(profile, timeoutMs = 1_500) {
|
|
54
|
+
const lock = path.join(profile, '.lock');
|
|
55
|
+
const deadline = Date.now() + timeoutMs;
|
|
56
|
+
while (existsSync(lock) && Date.now() < deadline)
|
|
57
|
+
await sleep(150);
|
|
58
|
+
if (existsSync(lock)) {
|
|
59
|
+
try {
|
|
60
|
+
rmSync(lock, { force: true });
|
|
61
|
+
}
|
|
62
|
+
catch { /* best effort — fresh launch will relock */ }
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** Resolve a LibreOffice binary, or null if none is available (callers skip the oracle). */
|
|
66
|
+
export function resolveSoffice() {
|
|
67
|
+
const candidates = [
|
|
68
|
+
process.env.SAFE_DOCX_SOFFICE_BIN,
|
|
69
|
+
process.env.ODF_SOFFICE_BIN,
|
|
70
|
+
'/opt/homebrew/bin/soffice',
|
|
71
|
+
'/usr/bin/soffice',
|
|
72
|
+
'/usr/local/bin/soffice',
|
|
73
|
+
'/Applications/LibreOffice.app/Contents/MacOS/soffice',
|
|
74
|
+
].filter(Boolean);
|
|
75
|
+
return candidates.find((c) => existsSync(c)) ?? null;
|
|
76
|
+
}
|
|
77
|
+
const CONTENT_TYPES = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
78
|
+
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
|
|
79
|
+
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
|
|
80
|
+
<Default Extension="xml" ContentType="application/xml"/>
|
|
81
|
+
<Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
|
|
82
|
+
</Types>`;
|
|
83
|
+
const RELS = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
84
|
+
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
85
|
+
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
|
|
86
|
+
</Relationships>`;
|
|
87
|
+
const DOC_RELS = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
88
|
+
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"/>`;
|
|
89
|
+
/** Pack a bare `word/document.xml` string into a minimal valid .docx package. */
|
|
90
|
+
export async function packMinimalDocx(documentXml) {
|
|
91
|
+
return createZipBuffer({
|
|
92
|
+
'[Content_Types].xml': CONTENT_TYPES,
|
|
93
|
+
'_rels/.rels': RELS,
|
|
94
|
+
'word/_rels/document.xml.rels': DOC_RELS,
|
|
95
|
+
'word/document.xml': documentXml,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
/** Read `word/document.xml` back out of a .docx package. */
|
|
99
|
+
export async function extractDocumentXml(docx) {
|
|
100
|
+
const xml = await readZipText(docx, 'word/document.xml');
|
|
101
|
+
if (xml == null)
|
|
102
|
+
throw new Error('word/document.xml not found in oracle output');
|
|
103
|
+
return xml;
|
|
104
|
+
}
|
|
105
|
+
const SCRIPT_XLC = `<?xml version="1.0" encoding="UTF-8"?>
|
|
106
|
+
<!DOCTYPE library:libraries PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "libraries.dtd">
|
|
107
|
+
<library:libraries xmlns:library="http://openoffice.org/2000/library" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
108
|
+
<library:library library:name="Standard" xlink:href="$(USER)/basic/Standard/script.xlb/" xlink:type="simple" library:link="false"/>
|
|
109
|
+
</library:libraries>`;
|
|
110
|
+
const SCRIPT_XLB = `<?xml version="1.0" encoding="UTF-8"?>
|
|
111
|
+
<!DOCTYPE library:library PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "library.dtd">
|
|
112
|
+
<library:library xmlns:library="http://openoffice.org/2000/library" library:name="Standard" library:readonly="false" library:passwordprotected="false">
|
|
113
|
+
<library:element library:name="Module1"/>
|
|
114
|
+
</library:library>`;
|
|
115
|
+
const REGMOD = `<?xml version="1.0" encoding="UTF-8"?>
|
|
116
|
+
<oor:items xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
117
|
+
<item oor:path="/org.openoffice.Office.Common/Security/Scripting"><prop oor:name="MacroSecurityLevel" oor:op="fuse"><value>0</value></prop></item>
|
|
118
|
+
<item oor:path="/org.openoffice.Office.Common/Misc"><prop oor:name="FirstRun" oor:op="fuse"><value>false</value></prop></item>
|
|
119
|
+
</oor:items>`;
|
|
120
|
+
/** The Basic macro: load each doc Hidden, dispatch accept/reject-all (or, for `identity`,
|
|
121
|
+
* dispatch nothing at all), save with the job's filter. */
|
|
122
|
+
function module1Xba(jobsPath, markerPath) {
|
|
123
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
124
|
+
<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
|
|
125
|
+
<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Module1" script:language="StarBasic">
|
|
126
|
+
Sub RunOracle
|
|
127
|
+
Dim iFile As Integer, sLine As String, parts() As String, m As Integer
|
|
128
|
+
m = FreeFile : Open "${markerPath}" For Output As #m : Print #m, "started" : Close #m
|
|
129
|
+
iFile = FreeFile
|
|
130
|
+
Open "${jobsPath}" For Input As #iFile
|
|
131
|
+
Do While Not EOF(iFile)
|
|
132
|
+
Line Input #iFile, sLine
|
|
133
|
+
If Len(Trim(sLine)) > 0 Then
|
|
134
|
+
parts = Split(sLine, "|")
|
|
135
|
+
ProcessOne(parts(0), ConvertToURL(parts(1)), ConvertToURL(parts(2)), parts(3))
|
|
136
|
+
End If
|
|
137
|
+
Loop
|
|
138
|
+
Close #iFile
|
|
139
|
+
StarDesktop.terminate()
|
|
140
|
+
End Sub
|
|
141
|
+
|
|
142
|
+
Sub ProcessOne(op As String, inUrl As String, outUrl As String, filterName As String)
|
|
143
|
+
Dim oDoc As Object, oFrame As Object, oDisp As Object
|
|
144
|
+
Dim loadArgs(0) As New com.sun.star.beans.PropertyValue
|
|
145
|
+
loadArgs(0).Name = "Hidden" : loadArgs(0).Value = True
|
|
146
|
+
oDoc = StarDesktop.loadComponentFromURL(inUrl, "_blank", 0, loadArgs())
|
|
147
|
+
oFrame = oDoc.getCurrentController().getFrame()
|
|
148
|
+
oDisp = createUnoService("com.sun.star.frame.DispatchHelper")
|
|
149
|
+
Dim noArgs()
|
|
150
|
+
If op = "accept" Then
|
|
151
|
+
oDisp.executeDispatch(oFrame, ".uno:AcceptAllTrackedChanges", "", 0, noArgs())
|
|
152
|
+
ElseIf op = "reject" Then
|
|
153
|
+
oDisp.executeDispatch(oFrame, ".uno:RejectAllTrackedChanges", "", 0, noArgs())
|
|
154
|
+
End If
|
|
155
|
+
' op = "identity": no dispatch — a plain load->save, exposing LibreOffice's own DOCX
|
|
156
|
+
' import/export of UNRESOLVED tracked changes (the oracle trust-boundary check).
|
|
157
|
+
Dim saveArgs(0) As New com.sun.star.beans.PropertyValue
|
|
158
|
+
saveArgs(0).Name = "FilterName" : saveArgs(0).Value = filterName
|
|
159
|
+
oDoc.storeToURL(outUrl, saveArgs())
|
|
160
|
+
oDoc.close(False)
|
|
161
|
+
End Sub
|
|
162
|
+
</script:module>`;
|
|
163
|
+
}
|
|
164
|
+
function isOdtJob(job) {
|
|
165
|
+
return 'odt' in job;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Run LibreOffice over a batch of jobs in ONE headless launch and return each job's resulting
|
|
169
|
+
* main XML part — `word/document.xml` for DOCX jobs, `content.xml` for ODT jobs. Throws if the
|
|
170
|
+
* binary is missing or the macro did not run.
|
|
171
|
+
*/
|
|
172
|
+
export async function runLibreOfficeOracle(jobs, soffice = resolveSoffice()) {
|
|
173
|
+
if (!soffice)
|
|
174
|
+
throw new Error('runLibreOfficeOracle: no soffice binary (call resolveSoffice() and skip)');
|
|
175
|
+
if (jobs.length === 0)
|
|
176
|
+
return [];
|
|
177
|
+
const work = mkdtempSync(path.join(os.tmpdir(), 'lo-oracle-'));
|
|
178
|
+
const profile = path.join(work, 'profile');
|
|
179
|
+
const userDir = path.join(profile, 'user');
|
|
180
|
+
const basicDir = path.join(userDir, 'basic', 'Standard');
|
|
181
|
+
const inDir = path.join(work, 'in');
|
|
182
|
+
const outDir = path.join(work, 'out');
|
|
183
|
+
const marker = path.join(work, 'macro_ran.txt');
|
|
184
|
+
const jobsPath = path.join(work, 'jobs.txt');
|
|
185
|
+
const profileUrl = pathToFileURL(profile).href;
|
|
186
|
+
let keepWork = false;
|
|
187
|
+
try {
|
|
188
|
+
for (const d of [userDir, basicDir, inDir, outDir])
|
|
189
|
+
mkdirSync(d, { recursive: true });
|
|
190
|
+
// Write each job's input package and build the jobs file (op|inPath|outPath|filter).
|
|
191
|
+
const outPaths = [];
|
|
192
|
+
const jobLines = [];
|
|
193
|
+
for (let i = 0; i < jobs.length; i++) {
|
|
194
|
+
const job = jobs[i];
|
|
195
|
+
const ext = isOdtJob(job) ? 'odt' : 'docx';
|
|
196
|
+
const filter = isOdtJob(job) ? 'writer8' : 'MS Word 2007 XML';
|
|
197
|
+
const inPath = path.join(inDir, `job${i}.${ext}`);
|
|
198
|
+
const outPath = path.join(outDir, `job${i}.${ext}`);
|
|
199
|
+
writeFileSync(inPath, isOdtJob(job) ? new Uint8Array(job.odt) : new Uint8Array(await packMinimalDocx(job.documentXml)));
|
|
200
|
+
outPaths.push(outPath);
|
|
201
|
+
jobLines.push(`${job.op}|${inPath}|${outPath}|${filter}`);
|
|
202
|
+
}
|
|
203
|
+
writeFileSync(jobsPath, jobLines.join('\n') + '\n');
|
|
204
|
+
// Macro security level 0 so the Standard-library macro runs headless.
|
|
205
|
+
writeFileSync(path.join(userDir, 'registrymodifications.xcu'), REGMOD);
|
|
206
|
+
const baseArgs = ['--headless', '--norestore', '--nologo', `-env:UserInstallation=${profileUrl}`];
|
|
207
|
+
const diag = [];
|
|
208
|
+
// (1) INIT the profile: a throwaway convert makes soffice populate user/basic/Standard
|
|
209
|
+
// (which would otherwise clobber a pre-placed Module1.xba on first real launch).
|
|
210
|
+
const init = await runSoffice(soffice, [...baseArgs, '--convert-to', 'txt', '--outdir', path.join(work, 'init'), path.join(inDir, 'job0.docx')], 20_000);
|
|
211
|
+
diag.push(`[init] ${(init.stderr || init.stdout || '(no output)').trim()}`);
|
|
212
|
+
// (2) Overwrite the Basic library with our macro.
|
|
213
|
+
mkdirSync(basicDir, { recursive: true });
|
|
214
|
+
writeFileSync(path.join(userDir, 'basic', 'script.xlc'), SCRIPT_XLC);
|
|
215
|
+
writeFileSync(path.join(basicDir, 'script.xlb'), SCRIPT_XLB);
|
|
216
|
+
writeFileSync(path.join(basicDir, 'Module1.xba'), module1Xba(jobsPath, marker));
|
|
217
|
+
// (3) Run the macro via a bare macro:/// URL — but only once the init instance has fully
|
|
218
|
+
// released the profile, so LibreOffice's single-instance model can't forward our macro command
|
|
219
|
+
// to the dying init process. Retry once: the first macro launch can still race a slow init exit.
|
|
220
|
+
for (let attempt = 1; attempt <= 2 && !existsSync(marker); attempt++) {
|
|
221
|
+
await settleProfile(profile);
|
|
222
|
+
const run = await runSoffice(soffice, [...baseArgs, 'macro:///Standard.Module1.RunOracle'], 45_000);
|
|
223
|
+
diag.push(`[macro attempt ${attempt}] ${(run.stderr || run.stdout || '(no output)').trim()}`);
|
|
224
|
+
if (!existsSync(marker))
|
|
225
|
+
await sleep(400);
|
|
226
|
+
}
|
|
227
|
+
if (!existsSync(marker)) {
|
|
228
|
+
keepWork = Boolean(process.env.SAFE_DOCX_ORACLE_DEBUG);
|
|
229
|
+
throw new Error('LibreOffice oracle macro did not run (no marker file) after 2 attempts.\nsoffice output:\n' +
|
|
230
|
+
diag.join('\n') +
|
|
231
|
+
(keepWork ? `\n(profile kept for debugging at ${work})` : ' (set SAFE_DOCX_ORACLE_DEBUG=1 to keep the profile)'));
|
|
232
|
+
}
|
|
233
|
+
return Promise.all(outPaths.map(async (p, i) => {
|
|
234
|
+
if (!existsSync(p))
|
|
235
|
+
throw new Error(`LibreOffice oracle produced no output for ${path.basename(p)}`);
|
|
236
|
+
if (isOdtJob(jobs[i])) {
|
|
237
|
+
const contentXml = await readZipText(readFileSync(p), 'content.xml');
|
|
238
|
+
if (contentXml == null)
|
|
239
|
+
throw new Error(`content.xml not found in oracle output ${path.basename(p)}`);
|
|
240
|
+
return contentXml;
|
|
241
|
+
}
|
|
242
|
+
return extractDocumentXml(readFileSync(p));
|
|
243
|
+
}));
|
|
244
|
+
}
|
|
245
|
+
finally {
|
|
246
|
+
if (!keepWork)
|
|
247
|
+
rmSync(work, { recursive: true, force: true });
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Structural projection of a `word/document.xml`: one entry per top-level body paragraph,
|
|
252
|
+
* recording whether it carries visible text (a non-whitespace `w:t` descendant). This captures
|
|
253
|
+
* the paragraph-collapse claim the oracle is authoritative for — how many paragraphs survive and
|
|
254
|
+
* which collapsed to empty — without depending on revision-markup or formatting details (which
|
|
255
|
+
* LibreOffice rewrites). `[]`-length is the paragraph count.
|
|
256
|
+
*/
|
|
257
|
+
export function paragraphShape(documentXml) {
|
|
258
|
+
const doc = parseXml(documentXml);
|
|
259
|
+
const body = doc.getElementsByTagNameNS(W_NS, 'body').item(0) ?? doc.documentElement;
|
|
260
|
+
if (!body)
|
|
261
|
+
return [];
|
|
262
|
+
const shape = [];
|
|
263
|
+
for (let i = 0; i < body.childNodes.length; i++) {
|
|
264
|
+
const node = body.childNodes[i];
|
|
265
|
+
if (node.nodeType !== 1)
|
|
266
|
+
continue;
|
|
267
|
+
const el = node;
|
|
268
|
+
if (el.namespaceURI !== W_NS || el.localName !== 'p')
|
|
269
|
+
continue; // skip w:sectPr etc.
|
|
270
|
+
const texts = el.getElementsByTagNameNS(W_NS, 't');
|
|
271
|
+
let hasText = false;
|
|
272
|
+
for (let j = 0; j < texts.length; j++) {
|
|
273
|
+
if ((texts.item(j).textContent ?? '').trim().length > 0) {
|
|
274
|
+
hasText = true;
|
|
275
|
+
break;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
shape.push(hasText);
|
|
279
|
+
}
|
|
280
|
+
return shape;
|
|
281
|
+
}
|
|
282
|
+
//# sourceMappingURL=libreoffice-oracle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"libreoffice-oracle.js","sourceRoot":"","sources":["../../src/integration/libreoffice-oracle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export interface SyntheticDocxOptions {
|
|
2
|
+
paragraphs: string[];
|
|
3
|
+
footnoteOnParagraph?: number;
|
|
4
|
+
footnoteText?: string;
|
|
5
|
+
commentOnParagraph?: number;
|
|
6
|
+
commentText?: string;
|
|
7
|
+
commentAuthor?: string;
|
|
8
|
+
commentAncillaryParts?: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Threaded reply to the root comment (w:id="1"). Emits a second
|
|
11
|
+
* <w:comment w:id="2"> with paraId 00000002 and, when commentAncillaryParts
|
|
12
|
+
* is also set, a <w15:commentEx w15:paraIdParent="00000001"> linkage and a
|
|
13
|
+
* second <w15:person> for the reply author. Reply comments deliberately
|
|
14
|
+
* have NO <w:commentReference> in document.xml — that's the issue #108
|
|
15
|
+
* shape: replies are discoverable only via paraIdParent threading.
|
|
16
|
+
*/
|
|
17
|
+
replyText?: string;
|
|
18
|
+
replyAuthor?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Cross-paragraph comment span. The comment opens at the start of
|
|
21
|
+
* paragraphs[start] and closes at the end of paragraphs[end]. The
|
|
22
|
+
* commentReference run is appended to paragraphs[end].
|
|
23
|
+
*
|
|
24
|
+
* Mutually exclusive with commentOnParagraph.
|
|
25
|
+
*/
|
|
26
|
+
commentSpanParagraphs?: {
|
|
27
|
+
start: number;
|
|
28
|
+
end: number;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Bookmark spanning a single paragraph (start and end inside the same w:p).
|
|
32
|
+
* Used to verify paragraph-internal bookmark preservation through rebuild.
|
|
33
|
+
*/
|
|
34
|
+
bookmarkOnParagraph?: {
|
|
35
|
+
paragraph: number;
|
|
36
|
+
name: string;
|
|
37
|
+
id?: number;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Body-level (sibling of <w:p>) bookmark inserted between
|
|
41
|
+
* paragraphs[index - 1] and paragraphs[index]. Used to verify scaffold
|
|
42
|
+
* markers do not leak into reconstructed paragraphs.
|
|
43
|
+
*/
|
|
44
|
+
siblingBookmarkBefore?: {
|
|
45
|
+
index: number;
|
|
46
|
+
name: string;
|
|
47
|
+
id?: number;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export declare function buildSyntheticDocx(opts: SyntheticDocxOptions): Promise<Buffer>;
|
|
51
|
+
export interface SyntheticResultParts {
|
|
52
|
+
documentXml: string;
|
|
53
|
+
footnotesXml: string | null;
|
|
54
|
+
endnotesXml: string | null;
|
|
55
|
+
commentsXml: string | null;
|
|
56
|
+
commentsExtendedXml: string | null;
|
|
57
|
+
peopleXml: string | null;
|
|
58
|
+
contentTypesXml: string | null;
|
|
59
|
+
relsXml: string | null;
|
|
60
|
+
}
|
|
61
|
+
export declare function getResultParts(resultBuffer: Buffer): Promise<SyntheticResultParts>;
|
|
62
|
+
//# sourceMappingURL=synthetic-docx-fixture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"synthetic-docx-fixture.d.ts","sourceRoot":"","sources":["../../src/integration/synthetic-docx-fixture.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IAGvB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACvD;;;OAGG;IACH,mBAAmB,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACvE;;;;OAIG;IACH,qBAAqB,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACtE;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,CAAC,CA4MpF;AAED,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,wBAAsB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAYxF"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import JSZip from 'jszip';
|
|
2
|
+
import { DocxArchive } from '../shared/docx/DocxArchive.js';
|
|
3
|
+
export async function buildSyntheticDocx(opts) {
|
|
4
|
+
const hasFootnote = opts.footnoteOnParagraph != null;
|
|
5
|
+
const hasComment = opts.commentOnParagraph != null;
|
|
6
|
+
const hasCommentSpan = opts.commentSpanParagraphs != null;
|
|
7
|
+
const hasBookmark = opts.bookmarkOnParagraph != null;
|
|
8
|
+
const hasSiblingBookmark = opts.siblingBookmarkBefore != null;
|
|
9
|
+
if (hasComment && hasCommentSpan) {
|
|
10
|
+
throw new Error('commentOnParagraph and commentSpanParagraphs are mutually exclusive');
|
|
11
|
+
}
|
|
12
|
+
const bookmarkId = opts.bookmarkOnParagraph?.id ?? 100;
|
|
13
|
+
const siblingBookmarkId = opts.siblingBookmarkBefore?.id ?? 200;
|
|
14
|
+
const spanStart = opts.commentSpanParagraphs?.start;
|
|
15
|
+
const spanEnd = opts.commentSpanParagraphs?.end;
|
|
16
|
+
const paragraphParts = opts.paragraphs.map((text, idx) => {
|
|
17
|
+
const escaped = text
|
|
18
|
+
.replaceAll('&', '&')
|
|
19
|
+
.replaceAll('<', '<')
|
|
20
|
+
.replaceAll('>', '>');
|
|
21
|
+
let extra = '';
|
|
22
|
+
if (hasFootnote && idx === opts.footnoteOnParagraph) {
|
|
23
|
+
extra += `<w:r><w:rPr><w:rStyle w:val="FootnoteReference"/></w:rPr><w:footnoteReference w:id="1"/></w:r>`;
|
|
24
|
+
}
|
|
25
|
+
if (hasComment && idx === opts.commentOnParagraph) {
|
|
26
|
+
extra =
|
|
27
|
+
`<w:commentRangeStart w:id="1"/>` +
|
|
28
|
+
`<w:r><w:t>${escaped}</w:t></w:r>` +
|
|
29
|
+
`<w:commentRangeEnd w:id="1"/>` +
|
|
30
|
+
`<w:r><w:rPr><w:rStyle w:val="CommentReference"/></w:rPr><w:commentReference w:id="1"/></w:r>`;
|
|
31
|
+
return `<w:p>${extra}</w:p>`;
|
|
32
|
+
}
|
|
33
|
+
if (hasCommentSpan && (idx === spanStart || idx === spanEnd)) {
|
|
34
|
+
const before = idx === spanStart ? `<w:commentRangeStart w:id="1"/>` : '';
|
|
35
|
+
const after = idx === spanEnd
|
|
36
|
+
? `<w:commentRangeEnd w:id="1"/>` +
|
|
37
|
+
`<w:r><w:rPr><w:rStyle w:val="CommentReference"/></w:rPr><w:commentReference w:id="1"/></w:r>`
|
|
38
|
+
: '';
|
|
39
|
+
return `<w:p>${before}<w:r><w:t>${escaped}</w:t></w:r>${after}${extra}</w:p>`;
|
|
40
|
+
}
|
|
41
|
+
if (hasBookmark && idx === opts.bookmarkOnParagraph.paragraph) {
|
|
42
|
+
const name = opts.bookmarkOnParagraph.name;
|
|
43
|
+
return (`<w:p>` +
|
|
44
|
+
`<w:bookmarkStart w:id="${bookmarkId}" w:name="${name}"/>` +
|
|
45
|
+
`<w:r><w:t>${escaped}</w:t></w:r>` +
|
|
46
|
+
`<w:bookmarkEnd w:id="${bookmarkId}"/>` +
|
|
47
|
+
extra +
|
|
48
|
+
`</w:p>`);
|
|
49
|
+
}
|
|
50
|
+
return `<w:p><w:r><w:t>${escaped}</w:t></w:r>${extra}</w:p>`;
|
|
51
|
+
});
|
|
52
|
+
// Inject a body-level (sibling of <w:p>) bookmark before paragraphs[index].
|
|
53
|
+
// Bookmark*Start*/End placed as sibling of <w:p> per ECMA-376 §17.13.5.
|
|
54
|
+
if (hasSiblingBookmark) {
|
|
55
|
+
const { index, name } = opts.siblingBookmarkBefore;
|
|
56
|
+
const sibling = `<w:bookmarkStart w:id="${siblingBookmarkId}" w:name="${name}"/>` +
|
|
57
|
+
`<w:bookmarkEnd w:id="${siblingBookmarkId}"/>`;
|
|
58
|
+
paragraphParts.splice(index, 0, sibling);
|
|
59
|
+
}
|
|
60
|
+
const paragraphsXml = paragraphParts.join('\n ');
|
|
61
|
+
const documentXml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` +
|
|
62
|
+
`<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"` +
|
|
63
|
+
` xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml">` +
|
|
64
|
+
`<w:body>${paragraphsXml}<w:sectPr/></w:body></w:document>`;
|
|
65
|
+
const contentTypeParts = [
|
|
66
|
+
`<Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>`,
|
|
67
|
+
];
|
|
68
|
+
const docRelEntries = [];
|
|
69
|
+
let rIdCounter = 1;
|
|
70
|
+
const zip = new JSZip();
|
|
71
|
+
if (hasFootnote) {
|
|
72
|
+
const fnText = opts.footnoteText ?? 'Test footnote';
|
|
73
|
+
const footnotesXml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` +
|
|
74
|
+
`<w:footnotes xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">` +
|
|
75
|
+
`<w:footnote w:type="separator" w:id="-1"><w:p><w:r><w:separator/></w:r></w:p></w:footnote>` +
|
|
76
|
+
`<w:footnote w:type="continuationSeparator" w:id="0"><w:p><w:r><w:continuationSeparator/></w:r></w:p></w:footnote>` +
|
|
77
|
+
`<w:footnote w:id="1"><w:p><w:r><w:t>${fnText}</w:t></w:r></w:p></w:footnote>` +
|
|
78
|
+
`</w:footnotes>`;
|
|
79
|
+
zip.file('word/footnotes.xml', footnotesXml);
|
|
80
|
+
contentTypeParts.push(`<Override PartName="/word/footnotes.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml"/>`);
|
|
81
|
+
rIdCounter++;
|
|
82
|
+
docRelEntries.push(`<Relationship Id="rId${rIdCounter}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes" Target="footnotes.xml"/>`);
|
|
83
|
+
}
|
|
84
|
+
if (hasComment || hasCommentSpan) {
|
|
85
|
+
const cText = opts.commentText ?? 'Test comment';
|
|
86
|
+
const cAuthor = opts.commentAuthor ?? 'Author';
|
|
87
|
+
const hasReply = opts.replyText != null;
|
|
88
|
+
const replyAuthor = opts.replyAuthor ?? 'Replier';
|
|
89
|
+
const replyEntry = hasReply
|
|
90
|
+
? `<w:comment w:id="2" w:author="${replyAuthor}" w:date="2025-01-02T00:00:00Z">` +
|
|
91
|
+
`<w:p w14:paraId="00000002"><w:r><w:t>${opts.replyText}</w:t></w:r></w:p>` +
|
|
92
|
+
`</w:comment>`
|
|
93
|
+
: '';
|
|
94
|
+
const commentsXml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` +
|
|
95
|
+
`<w:comments xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"` +
|
|
96
|
+
` xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml">` +
|
|
97
|
+
`<w:comment w:id="1" w:author="${cAuthor}" w:date="2025-01-01T00:00:00Z">` +
|
|
98
|
+
`<w:p w14:paraId="00000001"><w:r><w:t>${cText}</w:t></w:r></w:p>` +
|
|
99
|
+
`</w:comment>` +
|
|
100
|
+
replyEntry +
|
|
101
|
+
`</w:comments>`;
|
|
102
|
+
zip.file('word/comments.xml', commentsXml);
|
|
103
|
+
contentTypeParts.push(`<Override PartName="/word/comments.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml"/>`);
|
|
104
|
+
rIdCounter++;
|
|
105
|
+
docRelEntries.push(`<Relationship Id="rId${rIdCounter}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments" Target="comments.xml"/>`);
|
|
106
|
+
if (opts.commentAncillaryParts) {
|
|
107
|
+
const replyExEntry = hasReply
|
|
108
|
+
? `<w15:commentEx w15:paraId="00000002" w15:paraIdParent="00000001" w15:done="0"/>`
|
|
109
|
+
: '';
|
|
110
|
+
const commentsExtendedXml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` +
|
|
111
|
+
`<w15:commentsEx xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml">` +
|
|
112
|
+
`<w15:commentEx w15:paraId="00000001" w15:done="0"/>` +
|
|
113
|
+
replyExEntry +
|
|
114
|
+
`</w15:commentsEx>`;
|
|
115
|
+
zip.file('word/commentsExtended.xml', commentsExtendedXml);
|
|
116
|
+
contentTypeParts.push(`<Override PartName="/word/commentsExtended.xml" ContentType="application/vnd.ms-word.commentsExtended+xml"/>`);
|
|
117
|
+
rIdCounter++;
|
|
118
|
+
docRelEntries.push(`<Relationship Id="rId${rIdCounter}" Type="http://schemas.microsoft.com/office/2011/relationships/commentsExtended" Target="commentsExtended.xml"/>`);
|
|
119
|
+
const replyPersonEntry = hasReply
|
|
120
|
+
? `<w15:person w15:author="${replyAuthor}">` +
|
|
121
|
+
`<w15:presenceInfo w15:providerId="None" w15:userId="${replyAuthor}@example.com"/>` +
|
|
122
|
+
`</w15:person>`
|
|
123
|
+
: '';
|
|
124
|
+
const peopleXml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` +
|
|
125
|
+
`<w15:people xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml"` +
|
|
126
|
+
` xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">` +
|
|
127
|
+
`<w15:person w15:author="${cAuthor}">` +
|
|
128
|
+
`<w15:presenceInfo w15:providerId="None" w15:userId="${cAuthor}@example.com"/>` +
|
|
129
|
+
`</w15:person>` +
|
|
130
|
+
replyPersonEntry +
|
|
131
|
+
`</w15:people>`;
|
|
132
|
+
zip.file('word/people.xml', peopleXml);
|
|
133
|
+
contentTypeParts.push(`<Override PartName="/word/people.xml" ContentType="application/vnd.ms-word.people+xml"/>`);
|
|
134
|
+
rIdCounter++;
|
|
135
|
+
docRelEntries.push(`<Relationship Id="rId${rIdCounter}" Type="http://schemas.microsoft.com/office/2011/relationships/people" Target="people.xml"/>`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const contentTypesXml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` +
|
|
139
|
+
`<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">` +
|
|
140
|
+
`<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>` +
|
|
141
|
+
`<Default Extension="xml" ContentType="application/xml"/>` +
|
|
142
|
+
contentTypeParts.join('') +
|
|
143
|
+
`</Types>`;
|
|
144
|
+
const rootRelsXml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` +
|
|
145
|
+
`<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">` +
|
|
146
|
+
`<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>` +
|
|
147
|
+
`</Relationships>`;
|
|
148
|
+
const docRelsXml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` +
|
|
149
|
+
`<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">` +
|
|
150
|
+
docRelEntries.join('') +
|
|
151
|
+
`</Relationships>`;
|
|
152
|
+
zip.file('[Content_Types].xml', contentTypesXml);
|
|
153
|
+
zip.file('_rels/.rels', rootRelsXml);
|
|
154
|
+
zip.file('word/document.xml', documentXml);
|
|
155
|
+
zip.file('word/_rels/document.xml.rels', docRelsXml);
|
|
156
|
+
return (await zip.generateAsync({ type: 'nodebuffer' }));
|
|
157
|
+
}
|
|
158
|
+
export async function getResultParts(resultBuffer) {
|
|
159
|
+
const archive = await DocxArchive.load(resultBuffer);
|
|
160
|
+
return {
|
|
161
|
+
documentXml: await archive.getDocumentXml(),
|
|
162
|
+
footnotesXml: await archive.getFile('word/footnotes.xml'),
|
|
163
|
+
endnotesXml: await archive.getFile('word/endnotes.xml'),
|
|
164
|
+
commentsXml: await archive.getFile('word/comments.xml'),
|
|
165
|
+
commentsExtendedXml: await archive.getFile('word/commentsExtended.xml'),
|
|
166
|
+
peopleXml: await archive.getFile('word/people.xml'),
|
|
167
|
+
contentTypesXml: await archive.getFile('[Content_Types].xml'),
|
|
168
|
+
relsXml: await archive.getFile('word/_rels/document.xml.rels'),
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=synthetic-docx-fixture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"synthetic-docx-fixture.js","sourceRoot":"","sources":["../../src/integration/synthetic-docx-fixture.ts"],"names":[],"mappings":"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"}
|
|
@@ -20,8 +20,8 @@ export type AcceptChangesResult = {
|
|
|
20
20
|
propertyChangesResolved: number;
|
|
21
21
|
};
|
|
22
22
|
/**
|
|
23
|
-
* Accept all tracked changes in the document body, producing a
|
|
24
|
-
* document with no revision markup.
|
|
23
|
+
* Accept all tracked changes in the document body or story root, producing a
|
|
24
|
+
* clean document with no revision markup.
|
|
25
25
|
*
|
|
26
26
|
* Mutates the Document in place (same convention as simplifyRedlines
|
|
27
27
|
* and mergeRuns).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"accept_changes.d.ts","sourceRoot":"","sources":["../../src/primitives/accept_changes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,MAAM,MAAM,mBAAmB,GAAG;IAChC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,uBAAuB,EAAE,MAAM,CAAC;CACjC,CAAC;
|
|
1
|
+
{"version":3,"file":"accept_changes.d.ts","sourceRoot":"","sources":["../../src/primitives/accept_changes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,MAAM,MAAM,mBAAmB,GAAG;IAChC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,uBAAuB,EAAE,MAAM,CAAC;CACjC,CAAC;AAoFF;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,QAAQ,GAAG,mBAAmB,CA4FhE"}
|