docxodus 9.9.0 → 11.0.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/README.md +182 -4
- package/dist/canonical.d.ts +7 -0
- package/dist/canonical.d.ts.map +1 -0
- package/dist/canonical.js +56 -0
- package/dist/canonical.js.map +1 -0
- package/dist/docxodus.worker.d.ts +2 -1
- package/dist/docxodus.worker.d.ts.map +1 -1
- package/dist/docxodus.worker.js +250 -41
- package/dist/docxodus.worker.js.map +1 -1
- package/dist/editor.bundle.js +1980 -423
- package/dist/editor.d.ts +22 -2
- package/dist/editor.d.ts.map +1 -1
- package/dist/editor.js +94 -9
- package/dist/editor.js.map +1 -1
- package/dist/embed.bundle.js +2968 -597
- package/dist/embed.d.ts +1 -1
- package/dist/embed.iife.js +2969 -598
- package/dist/embed.js +1 -1
- package/dist/export-assets.json +277 -0
- package/dist/export-browser.bundle.js +7989 -0
- package/dist/export-browser.d.ts +266 -0
- package/dist/export-browser.d.ts.map +1 -0
- package/dist/export-browser.js +2915 -0
- package/dist/export-browser.js.map +1 -0
- package/dist/export-resource-limits-v1.json +57 -0
- package/dist/font-contract.d.ts +150 -0
- package/dist/font-contract.d.ts.map +1 -0
- package/dist/font-contract.js +59 -0
- package/dist/font-contract.js.map +1 -0
- package/dist/font-runtime.d.ts +33 -0
- package/dist/font-runtime.d.ts.map +1 -0
- package/dist/font-runtime.js +1100 -0
- package/dist/font-runtime.js.map +1 -0
- package/dist/index.d.ts +83 -65
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +194 -149
- package/dist/index.js.map +1 -1
- package/dist/page-geometry.d.ts +8 -1
- package/dist/page-geometry.d.ts.map +1 -1
- package/dist/page-geometry.js +37 -11
- package/dist/page-geometry.js.map +1 -1
- package/dist/pagination.bundle.js +1827 -410
- package/dist/pagination.d.ts +249 -15
- package/dist/pagination.d.ts.map +1 -1
- package/dist/pagination.js +1942 -453
- package/dist/pagination.js.map +1 -1
- package/dist/react.d.ts +13 -6
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +38 -5
- package/dist/react.js.map +1 -1
- package/dist/render-report-v2.schema.json +1581 -0
- package/dist/ribbon-chrome.d.ts +2 -2
- package/dist/ribbon-chrome.d.ts.map +1 -1
- package/dist/ribbon-chrome.js +72 -4
- package/dist/ribbon-chrome.js.map +1 -1
- package/dist/ribbon.js +119 -0
- package/dist/ribbon.js.map +1 -1
- package/dist/session.bundle.js +747 -29
- package/dist/session.d.ts +159 -19
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +593 -25
- package/dist/session.js.map +1 -1
- package/dist/types.d.ts +1287 -238
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +9 -75
- package/dist/types.js.map +1 -1
- package/dist/wasm/_framework/DocumentFormat.OpenXml.Framework.wasm +0 -0
- package/dist/wasm/_framework/DocumentFormat.OpenXml.Framework.wasm.br +0 -0
- package/dist/wasm/_framework/DocumentFormat.OpenXml.wasm +0 -0
- package/dist/wasm/_framework/DocumentFormat.OpenXml.wasm.br +0 -0
- package/dist/wasm/_framework/Docxodus.wasm +0 -0
- package/dist/wasm/_framework/Docxodus.wasm.br +0 -0
- package/dist/wasm/_framework/DocxodusWasm.wasm +0 -0
- package/dist/wasm/_framework/DocxodusWasm.wasm.br +0 -0
- package/dist/wasm/_framework/System.Collections.Concurrent.wasm +0 -0
- package/dist/wasm/_framework/System.Collections.Concurrent.wasm.br +0 -0
- package/dist/wasm/_framework/System.Collections.Immutable.wasm +0 -0
- package/dist/wasm/_framework/System.Collections.Immutable.wasm.br +0 -0
- package/dist/wasm/_framework/System.Collections.wasm +0 -0
- package/dist/wasm/_framework/System.Collections.wasm.br +0 -0
- package/dist/wasm/_framework/System.ComponentModel.Primitives.wasm +0 -0
- package/dist/wasm/_framework/System.ComponentModel.Primitives.wasm.br +0 -0
- package/dist/wasm/_framework/System.IO.Compression.wasm +0 -0
- package/dist/wasm/_framework/System.IO.Compression.wasm.br +0 -0
- package/dist/wasm/_framework/System.IO.Packaging.wasm +0 -0
- package/dist/wasm/_framework/System.IO.Packaging.wasm.br +0 -0
- package/dist/wasm/_framework/System.IO.Pipelines.wasm +0 -0
- package/dist/wasm/_framework/System.IO.Pipelines.wasm.br +0 -0
- package/dist/wasm/_framework/System.Linq.wasm +0 -0
- package/dist/wasm/_framework/System.Linq.wasm.br +0 -0
- package/dist/wasm/_framework/System.Private.CoreLib.wasm +0 -0
- package/dist/wasm/_framework/System.Private.CoreLib.wasm.br +0 -0
- package/dist/wasm/_framework/System.Private.Uri.wasm +0 -0
- package/dist/wasm/_framework/System.Private.Uri.wasm.br +0 -0
- package/dist/wasm/_framework/System.Private.Xml.Linq.wasm +0 -0
- package/dist/wasm/_framework/System.Private.Xml.Linq.wasm.br +0 -0
- package/dist/wasm/_framework/System.Private.Xml.wasm +0 -0
- package/dist/wasm/_framework/System.Private.Xml.wasm.br +0 -0
- package/dist/wasm/_framework/System.Runtime.InteropServices.JavaScript.wasm +0 -0
- package/dist/wasm/_framework/System.Runtime.InteropServices.JavaScript.wasm.br +0 -0
- package/dist/wasm/_framework/System.Runtime.wasm +0 -0
- package/dist/wasm/_framework/System.Runtime.wasm.br +0 -0
- package/dist/wasm/_framework/System.Security.Cryptography.wasm +0 -0
- package/dist/wasm/_framework/System.Security.Cryptography.wasm.br +0 -0
- package/dist/wasm/_framework/System.Text.Encodings.Web.wasm +0 -0
- package/dist/wasm/_framework/System.Text.Encodings.Web.wasm.br +0 -0
- package/dist/wasm/_framework/System.Text.Json.wasm +0 -0
- package/dist/wasm/_framework/System.Text.Json.wasm.br +0 -0
- package/dist/wasm/_framework/System.Text.RegularExpressions.wasm +0 -0
- package/dist/wasm/_framework/System.Text.RegularExpressions.wasm.br +0 -0
- package/dist/wasm/_framework/dotnet.boot.js +34 -40
- package/dist/wasm/_framework/dotnet.boot.js.br +0 -0
- package/dist/wasm/_framework/dotnet.native.js +39 -3
- package/dist/wasm/_framework/dotnet.native.js.br +0 -0
- package/dist/wasm/_framework/dotnet.native.wasm +0 -0
- package/dist/wasm/_framework/dotnet.native.wasm.br +0 -0
- package/dist/worker-proxy.bundle.js +198 -32
- package/dist/worker-proxy.d.ts +37 -4
- package/dist/worker-proxy.d.ts.map +1 -1
- package/dist/worker-proxy.js +187 -35
- package/dist/worker-proxy.js.map +1 -1
- package/package.json +22 -6
- package/dist/wasm/_framework/System.Diagnostics.Process.wasm +0 -0
- package/dist/wasm/_framework/System.Diagnostics.Process.wasm.br +0 -0
package/dist/session.bundle.js
CHANGED
|
@@ -47,7 +47,46 @@ var DocxodusSession = (() => {
|
|
|
47
47
|
};
|
|
48
48
|
|
|
49
49
|
// src/session.ts
|
|
50
|
-
|
|
50
|
+
function mutationBatchChangeSet(before, after, key) {
|
|
51
|
+
const beforeGroups = /* @__PURE__ */ new Map();
|
|
52
|
+
const afterGroups = /* @__PURE__ */ new Map();
|
|
53
|
+
const group = (items, target) => {
|
|
54
|
+
items.forEach((item, index) => {
|
|
55
|
+
const identity = key(item);
|
|
56
|
+
const indices = target.get(identity) ?? [];
|
|
57
|
+
indices.push(index);
|
|
58
|
+
target.set(identity, indices);
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
group(before, beforeGroups);
|
|
62
|
+
group(after, afterGroups);
|
|
63
|
+
const beforeMatched = before.map(() => false);
|
|
64
|
+
const afterMatched = after.map(() => false);
|
|
65
|
+
const modified = after.map(() => false);
|
|
66
|
+
for (const [identity, afterIndices] of afterGroups) {
|
|
67
|
+
const beforeIndices = beforeGroups.get(identity) ?? [];
|
|
68
|
+
for (const afterIndex of afterIndices) {
|
|
69
|
+
const beforeIndex = beforeIndices.find((index) => !beforeMatched[index] && JSON.stringify(before[index]) === JSON.stringify(after[afterIndex]));
|
|
70
|
+
if (beforeIndex === void 0) continue;
|
|
71
|
+
beforeMatched[beforeIndex] = true;
|
|
72
|
+
afterMatched[afterIndex] = true;
|
|
73
|
+
}
|
|
74
|
+
const remainingBefore = beforeIndices.filter((index) => !beforeMatched[index]);
|
|
75
|
+
const remainingAfter = afterIndices.filter((index) => !afterMatched[index]);
|
|
76
|
+
const modifiedCount = Math.min(remainingBefore.length, remainingAfter.length);
|
|
77
|
+
for (let index = 0; index < modifiedCount; index++) {
|
|
78
|
+
beforeMatched[remainingBefore[index]] = true;
|
|
79
|
+
afterMatched[remainingAfter[index]] = true;
|
|
80
|
+
modified[remainingAfter[index]] = true;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
added: after.filter((_, index) => !afterMatched[index]),
|
|
85
|
+
removed: before.filter((_, index) => !beforeMatched[index]),
|
|
86
|
+
modified: after.filter((_, index) => modified[index])
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
var DocxSession = class _DocxSession {
|
|
51
90
|
/** @internal */
|
|
52
91
|
constructor(handle, wasm) {
|
|
53
92
|
// ─── Raw escape hatch ────────────────────────────────────────────────
|
|
@@ -63,6 +102,336 @@ var DocxodusSession = (() => {
|
|
|
63
102
|
project() {
|
|
64
103
|
return JSON.parse(this.wasm.Project(this.handle));
|
|
65
104
|
}
|
|
105
|
+
/** Monotonic document version (0 at open; +1 per committed mutation/undo/redo). */
|
|
106
|
+
getVersion() {
|
|
107
|
+
return JSON.parse(this.wasm.GetVersion(this.handle)).version;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Verification manifest for the current logical checkpoint. Unsaved edits are included and
|
|
111
|
+
* the read does not mutate package bytes, caches, history, or the document version.
|
|
112
|
+
*/
|
|
113
|
+
getPackageManifest() {
|
|
114
|
+
return JSON.parse(this.wasm.GetPackageManifest(this.handle));
|
|
115
|
+
}
|
|
116
|
+
/** Register a browser-materialized PageMap without changing the document version. */
|
|
117
|
+
registerPageMap(pageMap, expectedRendererFingerprint) {
|
|
118
|
+
return JSON.parse(this.wasm.RegisterPageMap(
|
|
119
|
+
this.handle,
|
|
120
|
+
JSON.stringify(pageMap),
|
|
121
|
+
expectedRendererFingerprint ?? ""
|
|
122
|
+
));
|
|
123
|
+
}
|
|
124
|
+
getPageMapStatus(request) {
|
|
125
|
+
return JSON.parse(this.wasm.GetPageMapStatus(
|
|
126
|
+
this.handle,
|
|
127
|
+
request ? JSON.stringify(request) : ""
|
|
128
|
+
));
|
|
129
|
+
}
|
|
130
|
+
getPageCitation(anchorId, request) {
|
|
131
|
+
return JSON.parse(this.wasm.GetPageCitation(
|
|
132
|
+
this.handle,
|
|
133
|
+
anchorId,
|
|
134
|
+
JSON.stringify(request)
|
|
135
|
+
));
|
|
136
|
+
}
|
|
137
|
+
/** Evaluate optimistic guards without mutating or advancing the version. */
|
|
138
|
+
checkPreconditions(preconditions) {
|
|
139
|
+
return JSON.parse(
|
|
140
|
+
this.wasm.CheckPreconditions(this.handle, JSON.stringify(preconditions))
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Guard any synchronous mutation. WASM calls are synchronous and single-threaded, so the
|
|
145
|
+
* check and callback form one uninterrupted client-side operation. Prefer a method's native
|
|
146
|
+
* `preconditions` option where it has one (notably replaceTextRange's match-count guard).
|
|
147
|
+
*/
|
|
148
|
+
runWithPreconditions(preconditions, mutation) {
|
|
149
|
+
const checked = this.checkPreconditions(preconditions);
|
|
150
|
+
return checked.success ? mutation() : checked;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Execute synchronous mutations atomically by default. Atomic success is one undo/version
|
|
154
|
+
* unit; any failed or thrown step restores the exact package and history checkpoint.
|
|
155
|
+
*/
|
|
156
|
+
executeBatch(steps, mode = "atomic") {
|
|
157
|
+
if (mode !== "atomic" && mode !== "best_effort") {
|
|
158
|
+
throw new RangeError(`unknown mutation batch mode: ${String(mode)}`);
|
|
159
|
+
}
|
|
160
|
+
const baseVersion = this.getVersion();
|
|
161
|
+
const observationWarnings = [];
|
|
162
|
+
const inspect = (label, read, fallback) => {
|
|
163
|
+
try {
|
|
164
|
+
return read();
|
|
165
|
+
} catch (error) {
|
|
166
|
+
observationWarnings.push(`${label} unavailable: ${error instanceof Error ? error.message : String(error)}`);
|
|
167
|
+
return fallback;
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
const beforeRevisions = inspect("Revision delta inspection", () => this.listRevisions(), []);
|
|
171
|
+
const beforeComments = inspect("Comment delta inspection", () => this.listComments(), []);
|
|
172
|
+
const beforeAnnotations = inspect("Annotation delta inspection", () => this.listAnnotations(), []);
|
|
173
|
+
const complete = (result) => {
|
|
174
|
+
try {
|
|
175
|
+
const revisionChanges = mutationBatchChangeSet(
|
|
176
|
+
beforeRevisions,
|
|
177
|
+
inspect("Revision delta inspection", () => this.listRevisions(), beforeRevisions),
|
|
178
|
+
(revision) => revision.id
|
|
179
|
+
);
|
|
180
|
+
const commentChanges = mutationBatchChangeSet(
|
|
181
|
+
beforeComments,
|
|
182
|
+
inspect("Comment delta inspection", () => this.listComments(), beforeComments),
|
|
183
|
+
(comment) => comment.anchorId
|
|
184
|
+
);
|
|
185
|
+
const annotationChanges = mutationBatchChangeSet(
|
|
186
|
+
beforeAnnotations,
|
|
187
|
+
inspect("Annotation delta inspection", () => this.listAnnotations(), beforeAnnotations),
|
|
188
|
+
(annotation) => annotation.id ?? ""
|
|
189
|
+
);
|
|
190
|
+
const resultVersion = inspect(
|
|
191
|
+
"Result version inspection",
|
|
192
|
+
() => this.getVersion(),
|
|
193
|
+
baseVersion
|
|
194
|
+
);
|
|
195
|
+
const warnings = [...observationWarnings];
|
|
196
|
+
if ([...revisionChanges.added, ...revisionChanges.modified].some((revision) => revision.date !== void 0 && revision.date !== null)) {
|
|
197
|
+
warnings.push("Tracked-revision date attributes may use the execution clock; compare revision ids, authors, types, text, and anchors across separate executions.");
|
|
198
|
+
}
|
|
199
|
+
if ([...commentChanges.added, ...commentChanges.modified].some((comment) => comment.date !== void 0 && comment.date !== null)) {
|
|
200
|
+
warnings.push("Comment date attributes may be generated from the execution clock; supply dates explicitly when byte-identical replay is required.");
|
|
201
|
+
}
|
|
202
|
+
if (annotationChanges.added.some((annotation) => annotation.created !== void 0 && annotation.created !== null)) {
|
|
203
|
+
warnings.push("Auto-generated annotation ids or creation timestamps are execution metadata; supply id and created explicitly when byte-identical replay is required.");
|
|
204
|
+
}
|
|
205
|
+
if (result.steps.some((step) => step.results.some((edit) => edit.created.length > 0))) {
|
|
206
|
+
warnings.push("Created anchors and related OOXML ids may be generated independently on replay; preview/apply equivalence is semantic and packageHash or anchor ids may differ.");
|
|
207
|
+
}
|
|
208
|
+
if (mode === "best_effort" && !result.success) {
|
|
209
|
+
warnings.push("Best-effort execution retains every successful step despite later failures.");
|
|
210
|
+
}
|
|
211
|
+
let packageHash = null;
|
|
212
|
+
if (!this.wasm.GetPackageContentHash) {
|
|
213
|
+
warnings.push("This WASM bundle predates package equivalence hashes; packageHash is unavailable.");
|
|
214
|
+
} else {
|
|
215
|
+
try {
|
|
216
|
+
packageHash = this.wasm.GetPackageContentHash(this.handle);
|
|
217
|
+
} catch (error) {
|
|
218
|
+
warnings.push(`Package equivalence hash unavailable: ${error instanceof Error ? error.message : String(error)}`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return {
|
|
222
|
+
...result,
|
|
223
|
+
preview: false,
|
|
224
|
+
baseVersion,
|
|
225
|
+
resultVersion,
|
|
226
|
+
packageHash,
|
|
227
|
+
revisionChanges,
|
|
228
|
+
commentChanges,
|
|
229
|
+
annotationChanges,
|
|
230
|
+
warnings,
|
|
231
|
+
html: null
|
|
232
|
+
};
|
|
233
|
+
} catch (error) {
|
|
234
|
+
return {
|
|
235
|
+
...result,
|
|
236
|
+
preview: false,
|
|
237
|
+
baseVersion,
|
|
238
|
+
resultVersion: inspect("Result version inspection", () => this.getVersion(), baseVersion),
|
|
239
|
+
packageHash: null,
|
|
240
|
+
revisionChanges: { added: [], removed: [], modified: [] },
|
|
241
|
+
commentChanges: { added: [], removed: [], modified: [] },
|
|
242
|
+
annotationChanges: { added: [], removed: [], modified: [] },
|
|
243
|
+
warnings: [
|
|
244
|
+
...observationWarnings,
|
|
245
|
+
`Batch receipt enrichment unavailable: ${error instanceof Error ? error.message : String(error)}`
|
|
246
|
+
],
|
|
247
|
+
html: null
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
const internalFailure = (value) => ({
|
|
252
|
+
success: false,
|
|
253
|
+
error: { code: "internal_error", message: value instanceof Error ? value.message : String(value) },
|
|
254
|
+
created: [],
|
|
255
|
+
removed: [],
|
|
256
|
+
modified: []
|
|
257
|
+
});
|
|
258
|
+
const run = (step) => {
|
|
259
|
+
try {
|
|
260
|
+
const value = step.mutation();
|
|
261
|
+
const results = Array.isArray(value) ? value : [value];
|
|
262
|
+
if (results.some((result) => result === null || typeof result !== "object" || typeof result.success !== "boolean")) {
|
|
263
|
+
return [internalFailure("batch mutation returned invalid edit results")];
|
|
264
|
+
}
|
|
265
|
+
return results;
|
|
266
|
+
} catch (error) {
|
|
267
|
+
return [internalFailure(error)];
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
const failureOf = (step, rolledBack) => ({
|
|
271
|
+
index: step.index,
|
|
272
|
+
tool: step.tool,
|
|
273
|
+
action: step.action,
|
|
274
|
+
error: step.results.find((result) => !result.success)?.error ?? { code: "internal_error", message: "batch step failed without an error" },
|
|
275
|
+
rolledBack
|
|
276
|
+
});
|
|
277
|
+
const preflightOne = (step) => {
|
|
278
|
+
try {
|
|
279
|
+
return step.preflight?.();
|
|
280
|
+
} catch (error) {
|
|
281
|
+
return internalFailure(error).error;
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
if (mode === "atomic") {
|
|
285
|
+
const preflight = steps.map(preflightOne);
|
|
286
|
+
const failedPreflight = preflight.findIndex((error) => error !== void 0);
|
|
287
|
+
if (failedPreflight >= 0) {
|
|
288
|
+
const source = steps[failedPreflight];
|
|
289
|
+
const failed2 = {
|
|
290
|
+
index: failedPreflight,
|
|
291
|
+
tool: source.tool,
|
|
292
|
+
action: source.action,
|
|
293
|
+
success: false,
|
|
294
|
+
rolledBack: true,
|
|
295
|
+
results: [{ success: false, error: preflight[failedPreflight], created: [], removed: [], modified: [] }]
|
|
296
|
+
};
|
|
297
|
+
return complete({
|
|
298
|
+
mode,
|
|
299
|
+
status: "failed",
|
|
300
|
+
success: false,
|
|
301
|
+
rolledBack: true,
|
|
302
|
+
steps: [failed2],
|
|
303
|
+
failure: failureOf(failed2, true)
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
const transaction = this.wasm.BeginTransaction(this.handle);
|
|
307
|
+
const completed2 = [];
|
|
308
|
+
try {
|
|
309
|
+
for (let index = 0; index < steps.length; index++) {
|
|
310
|
+
const source = steps[index];
|
|
311
|
+
const results = run(source);
|
|
312
|
+
const step = {
|
|
313
|
+
index,
|
|
314
|
+
tool: source.tool,
|
|
315
|
+
action: source.action,
|
|
316
|
+
success: results.every((result) => result.success),
|
|
317
|
+
rolledBack: false,
|
|
318
|
+
results
|
|
319
|
+
};
|
|
320
|
+
completed2.push(step);
|
|
321
|
+
if (!step.success) {
|
|
322
|
+
this.wasm.RollbackTransaction(transaction);
|
|
323
|
+
const rolledBack = completed2.map((value) => ({ ...value, rolledBack: true }));
|
|
324
|
+
const failed2 = rolledBack[rolledBack.length - 1];
|
|
325
|
+
return complete({
|
|
326
|
+
mode,
|
|
327
|
+
status: "failed",
|
|
328
|
+
success: false,
|
|
329
|
+
rolledBack: true,
|
|
330
|
+
steps: rolledBack,
|
|
331
|
+
failure: failureOf(failed2, true)
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
this.wasm.CommitTransaction(transaction);
|
|
336
|
+
return complete({ mode, status: "ok", success: true, rolledBack: false, steps: completed2 });
|
|
337
|
+
} catch (error) {
|
|
338
|
+
try {
|
|
339
|
+
this.wasm.RollbackTransaction(transaction);
|
|
340
|
+
} catch {
|
|
341
|
+
}
|
|
342
|
+
throw error;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
const completed = steps.map((source, index) => {
|
|
346
|
+
const preflight = preflightOne(source);
|
|
347
|
+
const results = preflight ? [{ success: false, error: preflight, created: [], removed: [], modified: [] }] : run(source);
|
|
348
|
+
return {
|
|
349
|
+
index,
|
|
350
|
+
tool: source.tool,
|
|
351
|
+
action: source.action,
|
|
352
|
+
success: results.every((result) => result.success),
|
|
353
|
+
rolledBack: false,
|
|
354
|
+
results
|
|
355
|
+
};
|
|
356
|
+
});
|
|
357
|
+
const failed = completed.find((step) => !step.success);
|
|
358
|
+
return complete({
|
|
359
|
+
mode,
|
|
360
|
+
status: failed ? completed.some((step) => step.success) ? "partial" : "failed" : "ok",
|
|
361
|
+
success: failed === void 0,
|
|
362
|
+
rolledBack: false,
|
|
363
|
+
steps: completed,
|
|
364
|
+
failure: failed ? failureOf(failed, false) : void 0
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Execute the same callback batch algorithm against a complete isolated package clone.
|
|
369
|
+
* Callbacks receive the shadow session explicitly; mutate that argument. The live session's
|
|
370
|
+
* package, caches, version, configuration, and undo/redo history are never execution targets.
|
|
371
|
+
*/
|
|
372
|
+
previewBatch(steps, mode = "atomic", options) {
|
|
373
|
+
if (mode !== "atomic" && mode !== "best_effort") {
|
|
374
|
+
throw new RangeError(`unknown mutation batch mode: ${String(mode)}`);
|
|
375
|
+
}
|
|
376
|
+
const htmlMode = options?.html ?? "none";
|
|
377
|
+
if (htmlMode !== "none" && htmlMode !== "scoped" && htmlMode !== "full") {
|
|
378
|
+
throw new RangeError(`unknown preview HTML mode: ${String(htmlMode)}`);
|
|
379
|
+
}
|
|
380
|
+
if (!this.wasm.OpenPreviewSession) {
|
|
381
|
+
throw new Error("This WASM bundle does not support isolated mutation previews.");
|
|
382
|
+
}
|
|
383
|
+
const shadow = new _DocxSession(this.wasm.OpenPreviewSession(this.handle), this.wasm);
|
|
384
|
+
try {
|
|
385
|
+
const result = shadow.executeBatch(
|
|
386
|
+
steps.map((step) => ({
|
|
387
|
+
tool: step.tool,
|
|
388
|
+
action: step.action,
|
|
389
|
+
mutation: () => step.mutation(shadow),
|
|
390
|
+
preflight: step.preflight ? () => step.preflight(shadow) : void 0
|
|
391
|
+
})),
|
|
392
|
+
mode
|
|
393
|
+
);
|
|
394
|
+
const warnings = [...result.warnings];
|
|
395
|
+
let html = null;
|
|
396
|
+
const unwrapRendered = (rendered) => {
|
|
397
|
+
if (rendered.trimStart().startsWith("{")) {
|
|
398
|
+
const envelope = JSON.parse(rendered);
|
|
399
|
+
if (envelope.error) {
|
|
400
|
+
warnings.push(`Preview HTML could not be generated: ${envelope.error}`);
|
|
401
|
+
return null;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
return rendered;
|
|
405
|
+
};
|
|
406
|
+
const legacyProfileWarning = "This WASM bundle predates the shared preview HTML profile; preview HTML omits comments, annotations and headers/footers and may differ from other surfaces.";
|
|
407
|
+
try {
|
|
408
|
+
if (htmlMode === "scoped") {
|
|
409
|
+
if (!options?.htmlAnchorId) {
|
|
410
|
+
warnings.push("Scoped HTML was requested without htmlAnchorId; no HTML was generated.");
|
|
411
|
+
} else if (this.wasm.RenderPreviewBlockHtml) {
|
|
412
|
+
html = unwrapRendered(
|
|
413
|
+
this.wasm.RenderPreviewBlockHtml(shadow.handle, options.htmlAnchorId)
|
|
414
|
+
);
|
|
415
|
+
} else {
|
|
416
|
+
warnings.push(legacyProfileWarning);
|
|
417
|
+
html = shadow.renderBlock(options.htmlAnchorId);
|
|
418
|
+
}
|
|
419
|
+
} else if (htmlMode === "full") {
|
|
420
|
+
if (this.wasm.RenderPreviewHtml) {
|
|
421
|
+
html = unwrapRendered(this.wasm.RenderPreviewHtml(shadow.handle));
|
|
422
|
+
} else {
|
|
423
|
+
warnings.push(legacyProfileWarning);
|
|
424
|
+
html = unwrapRendered(this.wasm.RenderHtmlForReview ? this.wasm.RenderHtmlForReview(shadow.handle, "docx-", false, false, 1, true) : this.wasm.RenderHtml(shadow.handle, "docx-", false, false, 1));
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
} catch (error) {
|
|
428
|
+
warnings.push(`Preview HTML could not be generated: ${error instanceof Error ? error.message : String(error)}`);
|
|
429
|
+
}
|
|
430
|
+
return { ...result, preview: true, warnings, html };
|
|
431
|
+
} finally {
|
|
432
|
+
shadow.close();
|
|
433
|
+
}
|
|
434
|
+
}
|
|
66
435
|
/**
|
|
67
436
|
* Project a slice of the document keyed off an anchor — useful for showing
|
|
68
437
|
* one section to an LLM at a time without paying the cost of projecting the
|
|
@@ -78,9 +447,9 @@ var DocxodusSession = (() => {
|
|
|
78
447
|
*
|
|
79
448
|
* @see docs/architecture/docx_mutation_api.md
|
|
80
449
|
*/
|
|
81
|
-
projectAnchor(anchorId, depth = 2 /* SubtreeAndFollowingSiblings
|
|
450
|
+
projectAnchor(anchorId, depth = 2 /* SubtreeAndFollowingSiblings */, citation) {
|
|
82
451
|
return JSON.parse(
|
|
83
|
-
this.wasm.ProjectAnchor(this.handle, anchorId, depth)
|
|
452
|
+
citation ? this.wasm.ProjectAnchorWithCitations(this.handle, anchorId, depth, JSON.stringify(citation)) : this.wasm.ProjectAnchor(this.handle, anchorId, depth)
|
|
84
453
|
);
|
|
85
454
|
}
|
|
86
455
|
/**
|
|
@@ -104,11 +473,21 @@ var DocxodusSession = (() => {
|
|
|
104
473
|
return html;
|
|
105
474
|
}
|
|
106
475
|
// ─── Tier A: text CRUD ───────────────────────────────────────────────
|
|
107
|
-
replaceText(anchorId, markdown) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
return
|
|
476
|
+
replaceText(anchorId, markdown, preconditions) {
|
|
477
|
+
const apply = () => JSON.parse(
|
|
478
|
+
this.wasm.ReplaceText(this.handle, anchorId, markdown)
|
|
479
|
+
);
|
|
480
|
+
return preconditions ? this.runWithPreconditions(
|
|
481
|
+
{ ...preconditions, anchorId: preconditions.anchorId ?? anchorId },
|
|
482
|
+
apply
|
|
483
|
+
) : apply();
|
|
484
|
+
}
|
|
485
|
+
deleteBlock(anchorId, preconditions) {
|
|
486
|
+
const apply = () => JSON.parse(this.wasm.DeleteBlock(this.handle, anchorId));
|
|
487
|
+
return preconditions ? this.runWithPreconditions(
|
|
488
|
+
{ ...preconditions, anchorId: preconditions.anchorId ?? anchorId },
|
|
489
|
+
apply
|
|
490
|
+
) : apply();
|
|
112
491
|
}
|
|
113
492
|
/** Reorder one top-level paragraph/heading/list/table block relative to another. */
|
|
114
493
|
moveBlock(sourceAnchorId, targetAnchorId, position) {
|
|
@@ -163,7 +542,7 @@ var DocxodusSession = (() => {
|
|
|
163
542
|
}
|
|
164
543
|
/**
|
|
165
544
|
* Insert a `rows`×`cols` table before/after the block. `options` controls borders, row-major
|
|
166
|
-
* cell markdown, and cell alignment. The returned `EditResult.created` lists
|
|
545
|
+
* cell markdown, and cell alignment. The returned `EditResult.created` lists canonical `tc`
|
|
167
546
|
* anchors (row-major), so each cell can then be addressed to fill/format.
|
|
168
547
|
*/
|
|
169
548
|
insertTable(anchorId, position, rows, cols, options) {
|
|
@@ -172,10 +551,26 @@ var DocxodusSession = (() => {
|
|
|
172
551
|
this.wasm.InsertTable(this.handle, anchorId, position, rows, cols, optionsJson)
|
|
173
552
|
);
|
|
174
553
|
}
|
|
554
|
+
/** Resolve a canonical `tbl` anchor to explicit table/row/column/cell identities. */
|
|
555
|
+
getTableMetadata(tableAnchorId) {
|
|
556
|
+
return JSON.parse(this.wasm.GetTableMetadata(this.handle, tableAnchorId));
|
|
557
|
+
}
|
|
558
|
+
/** Resolve a canonical `tc` anchor to its zero-based table-grid coordinate and spans. */
|
|
559
|
+
resolveTableCellAnchor(cellAnchorId) {
|
|
560
|
+
return JSON.parse(
|
|
561
|
+
this.wasm.ResolveTableCellAnchor(this.handle, cellAnchorId)
|
|
562
|
+
);
|
|
563
|
+
}
|
|
564
|
+
/** Resolve a zero-based table-grid coordinate to the physical `tc` covering it. */
|
|
565
|
+
resolveTableCellCoordinate(tableAnchorId, rowIndex, columnIndex) {
|
|
566
|
+
return JSON.parse(
|
|
567
|
+
this.wasm.ResolveTableCellCoordinate(this.handle, tableAnchorId, rowIndex, columnIndex)
|
|
568
|
+
);
|
|
569
|
+
}
|
|
175
570
|
/**
|
|
176
|
-
* Table row/column editing, addressed by
|
|
177
|
-
* {@link insertTable}'s `created`
|
|
178
|
-
* empty (`created` lists
|
|
571
|
+
* Table row/column editing, addressed by the canonical `tc` anchor returned from
|
|
572
|
+
* {@link insertTable}'s `created` or table metadata. Insert clones the reference row/column's
|
|
573
|
+
* widths and starts empty (`created` lists new `tc` anchors); delete of the last row/column removes
|
|
179
574
|
* the whole table. All four are grid-aware: inserting across a merge extends it, deleting
|
|
180
575
|
* through one narrows it, and deleting a vertical merge's lead row promotes the next row to
|
|
181
576
|
* carry it — the grid is never left ragged.
|
|
@@ -215,7 +610,7 @@ var DocxodusSession = (() => {
|
|
|
215
610
|
return JSON.parse(this.wasm.UnmergeCells(this.handle, cellAnchorId));
|
|
216
611
|
}
|
|
217
612
|
/**
|
|
218
|
-
* Table styling, addressed by a
|
|
613
|
+
* Table styling, addressed by a canonical `tc` anchor — the post-insert counterpart of
|
|
219
614
|
* {@link insertTable}'s options (issue #315 Stage A). `setColumnWidths` retunes `w:tblGrid` +
|
|
220
615
|
* every row's cell width (one positive twip value per column) and pins the table to fixed
|
|
221
616
|
* layout, exactly as inserting with explicit `columnWidths` would.
|
|
@@ -255,6 +650,19 @@ var DocxodusSession = (() => {
|
|
|
255
650
|
this.wasm.SetRepeatHeaderRow(this.handle, cellAnchorId, repeat)
|
|
256
651
|
);
|
|
257
652
|
}
|
|
653
|
+
/** Apply row layout options to the row containing the canonical cell anchor. */
|
|
654
|
+
setTableRowOptions(cellAnchorId, options) {
|
|
655
|
+
return JSON.parse(
|
|
656
|
+
this.wasm.SetTableRowOptions(
|
|
657
|
+
this.handle,
|
|
658
|
+
cellAnchorId,
|
|
659
|
+
options.repeatHeader ?? null,
|
|
660
|
+
options.allowBreakAcrossPages ?? null,
|
|
661
|
+
options.heightTwips ?? null,
|
|
662
|
+
options.heightRule ?? "atLeast"
|
|
663
|
+
)
|
|
664
|
+
);
|
|
665
|
+
}
|
|
258
666
|
// ─── Headers / footers / page numbers ────────────────────────────────
|
|
259
667
|
/**
|
|
260
668
|
* Set the running header story for the section that owns `anchorId` (any body block in that
|
|
@@ -305,6 +713,58 @@ var DocxodusSession = (() => {
|
|
|
305
713
|
this.wasm.SetPageNumbering(this.handle, anchorId, JSON.stringify(op))
|
|
306
714
|
);
|
|
307
715
|
}
|
|
716
|
+
/**
|
|
717
|
+
* Insert a **table of contents** before or after `anchorId` (issue #607). The field is written
|
|
718
|
+
* dirty and the document asks for a field update on open, so Word paginates and fills the table
|
|
719
|
+
* itself — nothing here ships a cached result that is stale the moment anything above it moves.
|
|
720
|
+
*
|
|
721
|
+
* The table is wrapped in the `w:sdt` content control Word puts around one, which is what gives
|
|
722
|
+
* it the *Update Table* control in Word's UI. Word's `TOCHeading` and `TOC1` styles are
|
|
723
|
+
* find-or-created; a document that already defines them keeps its own.
|
|
724
|
+
*
|
|
725
|
+
* Body anchors only, and refused under tracked-change recording: a generated table is regenerated
|
|
726
|
+
* wholesale on every field update, so there is no reversible way to redline it.
|
|
727
|
+
*/
|
|
728
|
+
insertTableOfContents(anchorId, pos = "before", options) {
|
|
729
|
+
return JSON.parse(
|
|
730
|
+
this.wasm.InsertTableOfContents(
|
|
731
|
+
this.handle,
|
|
732
|
+
anchorId,
|
|
733
|
+
pos,
|
|
734
|
+
options ? JSON.stringify(options) : ""
|
|
735
|
+
)
|
|
736
|
+
);
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* Insert a **table of figures** — the captions carrying `options.captionLabel` and their page
|
|
740
|
+
* numbers. Same field mechanics as {@link insertTableOfContents}; Word writes this one as a bare
|
|
741
|
+
* paragraph rather than inside a content control, so this does too.
|
|
742
|
+
*/
|
|
743
|
+
insertTableOfFigures(anchorId, pos = "before", options) {
|
|
744
|
+
return JSON.parse(
|
|
745
|
+
this.wasm.InsertTableOfFigures(
|
|
746
|
+
this.handle,
|
|
747
|
+
anchorId,
|
|
748
|
+
pos,
|
|
749
|
+
options ? JSON.stringify(options) : ""
|
|
750
|
+
)
|
|
751
|
+
);
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* Insert a **table of authorities** — the cases, statutes or other authorities marked in the
|
|
755
|
+
* document, grouped by `options.category`. The table lists entries the document has MARKED with
|
|
756
|
+
* `TA` fields; a document with no marked citations produces a table that is correct and empty.
|
|
757
|
+
*/
|
|
758
|
+
insertTableOfAuthorities(anchorId, pos = "before", options) {
|
|
759
|
+
return JSON.parse(
|
|
760
|
+
this.wasm.InsertTableOfAuthorities(
|
|
761
|
+
this.handle,
|
|
762
|
+
anchorId,
|
|
763
|
+
pos,
|
|
764
|
+
options ? JSON.stringify(options) : ""
|
|
765
|
+
)
|
|
766
|
+
);
|
|
767
|
+
}
|
|
308
768
|
/**
|
|
309
769
|
* Remove the section's page-numbering start/format: it reverts to continuing the previous
|
|
310
770
|
* section's numbering in Word's default `1, 2, 3`. Chapter-numbering attributes
|
|
@@ -349,6 +809,25 @@ var DocxodusSession = (() => {
|
|
|
349
809
|
this.wasm.InsertFootnote(this.handle, anchorId, characterOffset, markdown)
|
|
350
810
|
);
|
|
351
811
|
}
|
|
812
|
+
/**
|
|
813
|
+
* Insert a Word-faithful internal cross-reference — a `REF` field targeting an existing
|
|
814
|
+
* bookmark — at a character offset (issue #545). The field carries a cached result run
|
|
815
|
+
* (the bookmarked text, or the target's auto-number under `referenceNumber`), so
|
|
816
|
+
* renderers that do not recompute fields show a faithful snapshot and Word updates it
|
|
817
|
+
* like a hand-authored cross-reference. A missing or incoherent bookmark fails with
|
|
818
|
+
* `missing_bookmark_target`.
|
|
819
|
+
*/
|
|
820
|
+
insertCrossReference(anchorId, characterOffset, bookmarkName, options) {
|
|
821
|
+
return JSON.parse(
|
|
822
|
+
this.wasm.InsertCrossReference(
|
|
823
|
+
this.handle,
|
|
824
|
+
anchorId,
|
|
825
|
+
characterOffset,
|
|
826
|
+
bookmarkName,
|
|
827
|
+
options ? JSON.stringify(options) : ""
|
|
828
|
+
)
|
|
829
|
+
);
|
|
830
|
+
}
|
|
352
831
|
/** Create an endnote — see {@link insertFootnote}; writes the endnotes part and a
|
|
353
832
|
* `w:endnoteReference`, and the created definition anchor has kind `en`. */
|
|
354
833
|
insertEndnote(anchorId, characterOffset, markdown) {
|
|
@@ -440,6 +919,170 @@ var DocxodusSession = (() => {
|
|
|
440
919
|
listComments() {
|
|
441
920
|
return JSON.parse(this.wasm.ListComments(this.handle));
|
|
442
921
|
}
|
|
922
|
+
listHyperlinks(scopes = 63 /* All */) {
|
|
923
|
+
return JSON.parse(this.wasm.ListHyperlinks(this.handle, scopes));
|
|
924
|
+
}
|
|
925
|
+
addHyperlink(anchorId, span, kind, target) {
|
|
926
|
+
return JSON.parse(this.wasm.AddHyperlink(
|
|
927
|
+
this.handle,
|
|
928
|
+
anchorId,
|
|
929
|
+
span.start,
|
|
930
|
+
span.length,
|
|
931
|
+
kind,
|
|
932
|
+
target
|
|
933
|
+
));
|
|
934
|
+
}
|
|
935
|
+
updateHyperlink(hyperlinkId, kind, target) {
|
|
936
|
+
return JSON.parse(this.wasm.UpdateHyperlink(this.handle, hyperlinkId, kind, target));
|
|
937
|
+
}
|
|
938
|
+
removeHyperlink(hyperlinkId) {
|
|
939
|
+
return JSON.parse(this.wasm.RemoveHyperlink(this.handle, hyperlinkId));
|
|
940
|
+
}
|
|
941
|
+
/** Versioned operational facts for native image inspection/mutation in this runtime. */
|
|
942
|
+
getImageCapabilities() {
|
|
943
|
+
return JSON.parse(this.wasm.GetImageCapabilities());
|
|
944
|
+
}
|
|
945
|
+
listImages(scopes = 63 /* All */) {
|
|
946
|
+
return JSON.parse(this.wasm.ListImages(this.handle, scopes));
|
|
947
|
+
}
|
|
948
|
+
insertImage(anchorId, characterOffset, bytes, options = {}) {
|
|
949
|
+
return JSON.parse(this.wasm.InsertImage(
|
|
950
|
+
this.handle,
|
|
951
|
+
anchorId,
|
|
952
|
+
characterOffset,
|
|
953
|
+
imageBytesToBase64(bytes),
|
|
954
|
+
JSON.stringify(options)
|
|
955
|
+
));
|
|
956
|
+
}
|
|
957
|
+
replaceImage(imageId, bytes) {
|
|
958
|
+
return JSON.parse(this.wasm.ReplaceImage(
|
|
959
|
+
this.handle,
|
|
960
|
+
imageId,
|
|
961
|
+
imageBytesToBase64(bytes)
|
|
962
|
+
));
|
|
963
|
+
}
|
|
964
|
+
setImageDimensions(imageId, dimensions) {
|
|
965
|
+
return JSON.parse(this.wasm.SetImageDimensions(
|
|
966
|
+
this.handle,
|
|
967
|
+
imageId,
|
|
968
|
+
JSON.stringify(dimensions)
|
|
969
|
+
));
|
|
970
|
+
}
|
|
971
|
+
setImageMetadata(imageId, altText, title) {
|
|
972
|
+
return JSON.parse(this.wasm.SetImageMetadata(
|
|
973
|
+
this.handle,
|
|
974
|
+
imageId,
|
|
975
|
+
altText,
|
|
976
|
+
title
|
|
977
|
+
));
|
|
978
|
+
}
|
|
979
|
+
setImageFloatingLayout(imageId, layout) {
|
|
980
|
+
return JSON.parse(this.wasm.SetImageFloatingLayout(
|
|
981
|
+
this.handle,
|
|
982
|
+
imageId,
|
|
983
|
+
JSON.stringify(layout)
|
|
984
|
+
));
|
|
985
|
+
}
|
|
986
|
+
removeImage(imageId) {
|
|
987
|
+
return JSON.parse(this.wasm.RemoveImage(this.handle, imageId));
|
|
988
|
+
}
|
|
989
|
+
/** Native Word structured-document tags, in outer-before-inner story order. */
|
|
990
|
+
listContentControls(scopes = 63 /* All */) {
|
|
991
|
+
return JSON.parse(this.wasm.ListContentControls(this.handle, scopes));
|
|
992
|
+
}
|
|
993
|
+
fillContentControlText(anchorId, text, options = {}) {
|
|
994
|
+
return JSON.parse(this.wasm.FillContentControlText(
|
|
995
|
+
this.handle,
|
|
996
|
+
anchorId,
|
|
997
|
+
text,
|
|
998
|
+
JSON.stringify(options)
|
|
999
|
+
));
|
|
1000
|
+
}
|
|
1001
|
+
fillContentControlRichText(anchorId, markdown, options = {}) {
|
|
1002
|
+
return JSON.parse(this.wasm.FillContentControlRichText(
|
|
1003
|
+
this.handle,
|
|
1004
|
+
anchorId,
|
|
1005
|
+
markdown,
|
|
1006
|
+
JSON.stringify(options)
|
|
1007
|
+
));
|
|
1008
|
+
}
|
|
1009
|
+
setContentControlChecked(anchorId, isChecked, options = {}) {
|
|
1010
|
+
return JSON.parse(this.wasm.SetContentControlChecked(
|
|
1011
|
+
this.handle,
|
|
1012
|
+
anchorId,
|
|
1013
|
+
isChecked,
|
|
1014
|
+
JSON.stringify(options)
|
|
1015
|
+
));
|
|
1016
|
+
}
|
|
1017
|
+
setContentControlDate(anchorId, value, displayText, options = {}) {
|
|
1018
|
+
const timestamp = value instanceof Date ? value.toISOString() : value;
|
|
1019
|
+
return JSON.parse(this.wasm.SetContentControlDate(
|
|
1020
|
+
this.handle,
|
|
1021
|
+
anchorId,
|
|
1022
|
+
timestamp,
|
|
1023
|
+
displayText ?? null,
|
|
1024
|
+
JSON.stringify(options)
|
|
1025
|
+
));
|
|
1026
|
+
}
|
|
1027
|
+
selectContentControlItem(anchorId, value, options = {}) {
|
|
1028
|
+
return JSON.parse(this.wasm.SelectContentControlItem(
|
|
1029
|
+
this.handle,
|
|
1030
|
+
anchorId,
|
|
1031
|
+
value,
|
|
1032
|
+
JSON.stringify(options)
|
|
1033
|
+
));
|
|
1034
|
+
}
|
|
1035
|
+
fillContentControlPicture(anchorId, bytes, options = {}) {
|
|
1036
|
+
return JSON.parse(this.wasm.FillContentControlPicture(
|
|
1037
|
+
this.handle,
|
|
1038
|
+
anchorId,
|
|
1039
|
+
imageBytesToBase64(bytes),
|
|
1040
|
+
JSON.stringify(options)
|
|
1041
|
+
));
|
|
1042
|
+
}
|
|
1043
|
+
addRepeatingSectionItem(sectionAnchorId, afterItemAnchorId, options = {}) {
|
|
1044
|
+
return JSON.parse(this.wasm.AddRepeatingSectionItem(
|
|
1045
|
+
this.handle,
|
|
1046
|
+
sectionAnchorId,
|
|
1047
|
+
afterItemAnchorId ?? "",
|
|
1048
|
+
JSON.stringify(options)
|
|
1049
|
+
));
|
|
1050
|
+
}
|
|
1051
|
+
removeRepeatingSectionItem(itemAnchorId) {
|
|
1052
|
+
return JSON.parse(this.wasm.RemoveRepeatingSectionItem(
|
|
1053
|
+
this.handle,
|
|
1054
|
+
itemAnchorId
|
|
1055
|
+
));
|
|
1056
|
+
}
|
|
1057
|
+
listBookmarks(scopes = 63 /* All */) {
|
|
1058
|
+
return JSON.parse(this.wasm.ListBookmarks(this.handle, scopes));
|
|
1059
|
+
}
|
|
1060
|
+
addBookmark(name, range) {
|
|
1061
|
+
return JSON.parse(this.wasm.AddBookmark(
|
|
1062
|
+
this.handle,
|
|
1063
|
+
name,
|
|
1064
|
+
range.startAnchorId,
|
|
1065
|
+
range.startOffset,
|
|
1066
|
+
range.endAnchorId,
|
|
1067
|
+
range.endOffset
|
|
1068
|
+
));
|
|
1069
|
+
}
|
|
1070
|
+
renameBookmark(name, newName) {
|
|
1071
|
+
return JSON.parse(this.wasm.RenameBookmark(this.handle, name, newName));
|
|
1072
|
+
}
|
|
1073
|
+
moveBookmark(name, range) {
|
|
1074
|
+
return JSON.parse(this.wasm.MoveBookmark(
|
|
1075
|
+
this.handle,
|
|
1076
|
+
name,
|
|
1077
|
+
range.startAnchorId,
|
|
1078
|
+
range.startOffset,
|
|
1079
|
+
range.endAnchorId,
|
|
1080
|
+
range.endOffset
|
|
1081
|
+
));
|
|
1082
|
+
}
|
|
1083
|
+
removeBookmark(name) {
|
|
1084
|
+
return JSON.parse(this.wasm.RemoveBookmark(this.handle, name));
|
|
1085
|
+
}
|
|
443
1086
|
// ─── Tracked revisions (issue #318) ──────────────────────────────────
|
|
444
1087
|
/** Markup-native tracked-revision listing, in document order across body, headers,
|
|
445
1088
|
* footers, footnotes, and endnotes. Ids are stable while the underlying markup
|
|
@@ -460,6 +1103,22 @@ var DocxodusSession = (() => {
|
|
|
460
1103
|
rejectRevision(revisionId) {
|
|
461
1104
|
return JSON.parse(this.wasm.RejectRevision(this.handle, revisionId));
|
|
462
1105
|
}
|
|
1106
|
+
/**
|
|
1107
|
+
* Accept every live revision as one undoable session mutation.
|
|
1108
|
+
*
|
|
1109
|
+
* Fails closed: an unsupported, malformed, or ambiguous registry entry aborts the whole
|
|
1110
|
+
* operation (`revisionUnsupported`/`revisionMalformed`/`revisionAmbiguous`) and nothing is
|
|
1111
|
+
* mutated. There is no force mode — call {@link listRevisions} and read each entry's
|
|
1112
|
+
* `diagnostic` to see what blocks it.
|
|
1113
|
+
*/
|
|
1114
|
+
acceptAllRevisions() {
|
|
1115
|
+
return JSON.parse(this.wasm.AcceptAllRevisions(this.handle));
|
|
1116
|
+
}
|
|
1117
|
+
/** Reject every live revision as one undoable session mutation. Fails closed exactly like
|
|
1118
|
+
* {@link acceptAllRevisions}. */
|
|
1119
|
+
rejectAllRevisions() {
|
|
1120
|
+
return JSON.parse(this.wasm.RejectAllRevisions(this.handle));
|
|
1121
|
+
}
|
|
463
1122
|
// ─── Tier C: formatting ──────────────────────────────────────────────
|
|
464
1123
|
applyFormat(anchorId, span, op) {
|
|
465
1124
|
const spanJson = span ? JSON.stringify(span) : "";
|
|
@@ -565,6 +1224,10 @@ var DocxodusSession = (() => {
|
|
|
565
1224
|
* replaces it with `replace`, preserving the surrounding run formatting that
|
|
566
1225
|
* the match didn't touch. Returns one `EditResult` per attempted match.
|
|
567
1226
|
*
|
|
1227
|
+
* A `find` that matches nothing fails with a single `text_not_found` result
|
|
1228
|
+
* naming the anchor and the needle — never an empty array. Pass
|
|
1229
|
+
* `expectedMatchCount: 0` to assert absence as a successful no-op instead.
|
|
1230
|
+
*
|
|
568
1231
|
* Run-formatting contract: the replacement text inherits the formatting of
|
|
569
1232
|
* the FIRST run the match spanned. Middle/trailing runs keep their `w:rPr`
|
|
570
1233
|
* but lose the slice of text the match consumed.
|
|
@@ -741,10 +1404,16 @@ var DocxodusSession = (() => {
|
|
|
741
1404
|
*
|
|
742
1405
|
* @see docs/architecture/docx_mutation_api.md#findplaceholders
|
|
743
1406
|
*/
|
|
744
|
-
findPlaceholders(kinds = PlaceholderKinds.All, scope = 1, contextChars = 80, boundary = ContextBoundary.Char) {
|
|
745
|
-
|
|
746
|
-
this.
|
|
747
|
-
|
|
1407
|
+
findPlaceholders(kinds = PlaceholderKinds.All, scope = 1, contextChars = 80, boundary = ContextBoundary.Char, citation) {
|
|
1408
|
+
const json = citation ? this.wasm.FindPlaceholdersWithCitations(
|
|
1409
|
+
this.handle,
|
|
1410
|
+
kinds,
|
|
1411
|
+
scope,
|
|
1412
|
+
contextChars,
|
|
1413
|
+
boundary,
|
|
1414
|
+
JSON.stringify(citation)
|
|
1415
|
+
) : this.wasm.FindPlaceholders(this.handle, kinds, scope, contextChars, boundary);
|
|
1416
|
+
return JSON.parse(json);
|
|
748
1417
|
}
|
|
749
1418
|
/**
|
|
750
1419
|
* Returns a snapshot of edit-state introspection signals — placeholder counts,
|
|
@@ -767,6 +1436,23 @@ var DocxodusSession = (() => {
|
|
|
767
1436
|
}
|
|
768
1437
|
return raw;
|
|
769
1438
|
}
|
|
1439
|
+
/**
|
|
1440
|
+
* Return stable semantic changes from the package opened for this session to
|
|
1441
|
+
* its current state. Requires `captureInitialProjection` (enabled by default).
|
|
1442
|
+
*/
|
|
1443
|
+
getSemanticChanges() {
|
|
1444
|
+
return JSON.parse(this.wasm.GetSemanticChanges(this.handle));
|
|
1445
|
+
}
|
|
1446
|
+
/**
|
|
1447
|
+
* Run the default deliverable gate on this session's normal clean-save checkpoint.
|
|
1448
|
+
* With initial projection capture enabled (the default), exact opening bytes are the
|
|
1449
|
+
* baseline used for dispositions and semantic/package deltas.
|
|
1450
|
+
*/
|
|
1451
|
+
verifyDeliverable() {
|
|
1452
|
+
return JSON.parse(
|
|
1453
|
+
this.wasm.VerifyDeliverable(this.handle)
|
|
1454
|
+
);
|
|
1455
|
+
}
|
|
770
1456
|
// ─── Annotation-based anchor discovery (#132) ────────────────────────
|
|
771
1457
|
/**
|
|
772
1458
|
* Resolves an annotation's range to the block-level markdown anchors covering
|
|
@@ -782,8 +1468,9 @@ var DocxodusSession = (() => {
|
|
|
782
1468
|
*
|
|
783
1469
|
* @see docs/architecture/docx_mutation_api.md#findbyannotation
|
|
784
1470
|
*/
|
|
785
|
-
findByAnnotation(annotationId) {
|
|
786
|
-
|
|
1471
|
+
findByAnnotation(annotationId, citation) {
|
|
1472
|
+
const json = citation ? this.wasm.FindByAnnotationWithCitations(this.handle, annotationId, JSON.stringify(citation)) : this.wasm.FindByAnnotation(this.handle, annotationId);
|
|
1473
|
+
return JSON.parse(json);
|
|
787
1474
|
}
|
|
788
1475
|
/**
|
|
789
1476
|
* Finds every annotation whose `labelId` matches and resolves each of their
|
|
@@ -792,8 +1479,9 @@ var DocxodusSession = (() => {
|
|
|
792
1479
|
* annotations on different paragraphs become three entries). Annotations
|
|
793
1480
|
* whose bookmark resolves to no anchors are omitted from the result.
|
|
794
1481
|
*/
|
|
795
|
-
findByLabel(labelId) {
|
|
796
|
-
|
|
1482
|
+
findByLabel(labelId, citation) {
|
|
1483
|
+
const json = citation ? this.wasm.FindByLabelWithCitations(this.handle, labelId, JSON.stringify(citation)) : this.wasm.FindByLabel(this.handle, labelId);
|
|
1484
|
+
return JSON.parse(json);
|
|
797
1485
|
}
|
|
798
1486
|
/**
|
|
799
1487
|
* Resolves any bookmark in the main document part (Docxodus-managed or
|
|
@@ -801,8 +1489,9 @@ var DocxodusSession = (() => {
|
|
|
801
1489
|
* order. Empty when the bookmark name is unknown. Use this for raw bookmark
|
|
802
1490
|
* names that didn't come from the annotation system.
|
|
803
1491
|
*/
|
|
804
|
-
findByBookmark(bookmarkName) {
|
|
805
|
-
|
|
1492
|
+
findByBookmark(bookmarkName, citation) {
|
|
1493
|
+
const json = citation ? this.wasm.FindByBookmarkWithCitations(this.handle, bookmarkName, JSON.stringify(citation)) : this.wasm.FindByBookmark(this.handle, bookmarkName);
|
|
1494
|
+
return JSON.parse(json);
|
|
806
1495
|
}
|
|
807
1496
|
// ─── Text/kind-based anchor discovery (#171) ─────────────────────────
|
|
808
1497
|
/**
|
|
@@ -847,15 +1536,25 @@ var DocxodusSession = (() => {
|
|
|
847
1536
|
);
|
|
848
1537
|
}
|
|
849
1538
|
/**
|
|
850
|
-
* Return every anchor of the given `kind`
|
|
851
|
-
* `"
|
|
1539
|
+
* Return every anchor of the given `kind` — one of `"p"`, `"h"`, `"li"`,
|
|
1540
|
+
* `"tbl"`, `"tr"`, `"tc"`, `"col"`, `"sdt"`, `"sec"`, `"fn"`, `"en"`,
|
|
1541
|
+
* `"cmt"`, `"unk"` — in document order. Matching is an exact string comparison;
|
|
1542
|
+
* in particular the row and cell tokens are `"tr"` and `"tc"`, never
|
|
1543
|
+
* `"row"`/`"cell"`. Unknown strings are not parsed or rejected: they simply
|
|
1544
|
+
* return an empty array. `"img"` and `"drw"` likewise return empty because the
|
|
1545
|
+
* projection never assigns those reserved kinds; address images through the
|
|
1546
|
+
* image surface instead. Reads the projection's anchor
|
|
852
1547
|
* index directly — no text scan. Pass `scope` (e.g. `"body"`) to restrict to
|
|
853
1548
|
* a single part; omit it to span all scopes.
|
|
854
1549
|
*/
|
|
855
|
-
findByKind(kind, scope) {
|
|
856
|
-
|
|
857
|
-
this.
|
|
858
|
-
|
|
1550
|
+
findByKind(kind, scope, citation) {
|
|
1551
|
+
const json = citation ? this.wasm.FindByKindWithCitations(
|
|
1552
|
+
this.handle,
|
|
1553
|
+
kind,
|
|
1554
|
+
scope ?? "",
|
|
1555
|
+
JSON.stringify(citation)
|
|
1556
|
+
) : this.wasm.FindByKind(this.handle, kind, scope ?? "");
|
|
1557
|
+
return JSON.parse(json);
|
|
859
1558
|
}
|
|
860
1559
|
/**
|
|
861
1560
|
* Look up a single anchor's preview info — `{ id, kind, scope, textPreview }`.
|
|
@@ -909,6 +1608,18 @@ var DocxodusSession = (() => {
|
|
|
909
1608
|
const raw = this.wasm.GetSectionInfo(this.handle, anchorId);
|
|
910
1609
|
return JSON.parse(raw);
|
|
911
1610
|
}
|
|
1611
|
+
/** Enumerate the document's explicit style catalog with resolved high-signal properties. */
|
|
1612
|
+
listStyles() {
|
|
1613
|
+
return JSON.parse(this.wasm.ListStyles(this.handle));
|
|
1614
|
+
}
|
|
1615
|
+
/** Inspect direct and effective paragraph/run formatting for one paragraph anchor. */
|
|
1616
|
+
getFormatting(anchorId) {
|
|
1617
|
+
return JSON.parse(this.wasm.GetFormatting(this.handle, anchorId));
|
|
1618
|
+
}
|
|
1619
|
+
/** Enumerate text-bearing runs as mutation-compatible anchor/span pairs. */
|
|
1620
|
+
listInlineSpans(anchorId) {
|
|
1621
|
+
return JSON.parse(this.wasm.ListInlineSpans(this.handle, anchorId));
|
|
1622
|
+
}
|
|
912
1623
|
/**
|
|
913
1624
|
* Enumerates every annotation persisted in the document. Lets an agent prime
|
|
914
1625
|
* itself with "here are the labeled regions you can target" before committing
|
|
@@ -973,6 +1684,13 @@ var DocxodusSession = (() => {
|
|
|
973
1684
|
this.close();
|
|
974
1685
|
}
|
|
975
1686
|
};
|
|
1687
|
+
function imageBytesToBase64(bytes) {
|
|
1688
|
+
let binary = "";
|
|
1689
|
+
for (let offset = 0; offset < bytes.length; offset += 32768) {
|
|
1690
|
+
binary += String.fromCharCode(...bytes.subarray(offset, offset + 32768));
|
|
1691
|
+
}
|
|
1692
|
+
return globalThis.btoa(binary);
|
|
1693
|
+
}
|
|
976
1694
|
function openDocxSession(bytes, wasmExports, settings) {
|
|
977
1695
|
const bridge = wasmExports.DocxSessionBridge;
|
|
978
1696
|
const handle = bridge.OpenSession(bytes, settings ? JSON.stringify(settings) : "");
|