docxodus 9.9.0 → 10.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 +178 -0
- 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 +244 -3
- package/dist/docxodus.worker.js.map +1 -1
- package/dist/editor.bundle.js +1914 -419
- 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 +2803 -469
- package/dist/embed.iife.js +2801 -467
- package/dist/export-assets.json +283 -0
- package/dist/export-browser.bundle.js +7990 -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 +62 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +130 -16
- 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 +11 -4
- 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 +1 -1
- package/dist/ribbon-chrome.d.ts.map +1 -1
- package/dist/ribbon-chrome.js +45 -0
- package/dist/ribbon-chrome.js.map +1 -1
- package/dist/ribbon.js +70 -0
- package/dist/ribbon.js.map +1 -1
- package/dist/session.bundle.js +695 -29
- package/dist/session.d.ts +134 -19
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +562 -25
- package/dist/session.js.map +1 -1
- package/dist/types.d.ts +1207 -16
- package/dist/types.d.ts.map +1 -1
- 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.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.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.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 +21 -21
- package/dist/wasm/_framework/dotnet.boot.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 +196 -29
- package/dist/worker-proxy.d.ts +36 -3
- package/dist/worker-proxy.d.ts.map +1 -1
- package/dist/worker-proxy.js +186 -33
- package/dist/worker-proxy.js.map +1 -1
- package/package.json +22 -6
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
|
|
@@ -349,6 +757,25 @@ var DocxodusSession = (() => {
|
|
|
349
757
|
this.wasm.InsertFootnote(this.handle, anchorId, characterOffset, markdown)
|
|
350
758
|
);
|
|
351
759
|
}
|
|
760
|
+
/**
|
|
761
|
+
* Insert a Word-faithful internal cross-reference — a `REF` field targeting an existing
|
|
762
|
+
* bookmark — at a character offset (issue #545). The field carries a cached result run
|
|
763
|
+
* (the bookmarked text, or the target's auto-number under `referenceNumber`), so
|
|
764
|
+
* renderers that do not recompute fields show a faithful snapshot and Word updates it
|
|
765
|
+
* like a hand-authored cross-reference. A missing or incoherent bookmark fails with
|
|
766
|
+
* `missing_bookmark_target`.
|
|
767
|
+
*/
|
|
768
|
+
insertCrossReference(anchorId, characterOffset, bookmarkName, options) {
|
|
769
|
+
return JSON.parse(
|
|
770
|
+
this.wasm.InsertCrossReference(
|
|
771
|
+
this.handle,
|
|
772
|
+
anchorId,
|
|
773
|
+
characterOffset,
|
|
774
|
+
bookmarkName,
|
|
775
|
+
options ? JSON.stringify(options) : ""
|
|
776
|
+
)
|
|
777
|
+
);
|
|
778
|
+
}
|
|
352
779
|
/** Create an endnote — see {@link insertFootnote}; writes the endnotes part and a
|
|
353
780
|
* `w:endnoteReference`, and the created definition anchor has kind `en`. */
|
|
354
781
|
insertEndnote(anchorId, characterOffset, markdown) {
|
|
@@ -440,6 +867,170 @@ var DocxodusSession = (() => {
|
|
|
440
867
|
listComments() {
|
|
441
868
|
return JSON.parse(this.wasm.ListComments(this.handle));
|
|
442
869
|
}
|
|
870
|
+
listHyperlinks(scopes = 63 /* All */) {
|
|
871
|
+
return JSON.parse(this.wasm.ListHyperlinks(this.handle, scopes));
|
|
872
|
+
}
|
|
873
|
+
addHyperlink(anchorId, span, kind, target) {
|
|
874
|
+
return JSON.parse(this.wasm.AddHyperlink(
|
|
875
|
+
this.handle,
|
|
876
|
+
anchorId,
|
|
877
|
+
span.start,
|
|
878
|
+
span.length,
|
|
879
|
+
kind,
|
|
880
|
+
target
|
|
881
|
+
));
|
|
882
|
+
}
|
|
883
|
+
updateHyperlink(hyperlinkId, kind, target) {
|
|
884
|
+
return JSON.parse(this.wasm.UpdateHyperlink(this.handle, hyperlinkId, kind, target));
|
|
885
|
+
}
|
|
886
|
+
removeHyperlink(hyperlinkId) {
|
|
887
|
+
return JSON.parse(this.wasm.RemoveHyperlink(this.handle, hyperlinkId));
|
|
888
|
+
}
|
|
889
|
+
/** Versioned operational facts for native image inspection/mutation in this runtime. */
|
|
890
|
+
getImageCapabilities() {
|
|
891
|
+
return JSON.parse(this.wasm.GetImageCapabilities());
|
|
892
|
+
}
|
|
893
|
+
listImages(scopes = 63 /* All */) {
|
|
894
|
+
return JSON.parse(this.wasm.ListImages(this.handle, scopes));
|
|
895
|
+
}
|
|
896
|
+
insertImage(anchorId, characterOffset, bytes, options = {}) {
|
|
897
|
+
return JSON.parse(this.wasm.InsertImage(
|
|
898
|
+
this.handle,
|
|
899
|
+
anchorId,
|
|
900
|
+
characterOffset,
|
|
901
|
+
imageBytesToBase64(bytes),
|
|
902
|
+
JSON.stringify(options)
|
|
903
|
+
));
|
|
904
|
+
}
|
|
905
|
+
replaceImage(imageId, bytes) {
|
|
906
|
+
return JSON.parse(this.wasm.ReplaceImage(
|
|
907
|
+
this.handle,
|
|
908
|
+
imageId,
|
|
909
|
+
imageBytesToBase64(bytes)
|
|
910
|
+
));
|
|
911
|
+
}
|
|
912
|
+
setImageDimensions(imageId, dimensions) {
|
|
913
|
+
return JSON.parse(this.wasm.SetImageDimensions(
|
|
914
|
+
this.handle,
|
|
915
|
+
imageId,
|
|
916
|
+
JSON.stringify(dimensions)
|
|
917
|
+
));
|
|
918
|
+
}
|
|
919
|
+
setImageMetadata(imageId, altText, title) {
|
|
920
|
+
return JSON.parse(this.wasm.SetImageMetadata(
|
|
921
|
+
this.handle,
|
|
922
|
+
imageId,
|
|
923
|
+
altText,
|
|
924
|
+
title
|
|
925
|
+
));
|
|
926
|
+
}
|
|
927
|
+
setImageFloatingLayout(imageId, layout) {
|
|
928
|
+
return JSON.parse(this.wasm.SetImageFloatingLayout(
|
|
929
|
+
this.handle,
|
|
930
|
+
imageId,
|
|
931
|
+
JSON.stringify(layout)
|
|
932
|
+
));
|
|
933
|
+
}
|
|
934
|
+
removeImage(imageId) {
|
|
935
|
+
return JSON.parse(this.wasm.RemoveImage(this.handle, imageId));
|
|
936
|
+
}
|
|
937
|
+
/** Native Word structured-document tags, in outer-before-inner story order. */
|
|
938
|
+
listContentControls(scopes = 63 /* All */) {
|
|
939
|
+
return JSON.parse(this.wasm.ListContentControls(this.handle, scopes));
|
|
940
|
+
}
|
|
941
|
+
fillContentControlText(anchorId, text, options = {}) {
|
|
942
|
+
return JSON.parse(this.wasm.FillContentControlText(
|
|
943
|
+
this.handle,
|
|
944
|
+
anchorId,
|
|
945
|
+
text,
|
|
946
|
+
JSON.stringify(options)
|
|
947
|
+
));
|
|
948
|
+
}
|
|
949
|
+
fillContentControlRichText(anchorId, markdown, options = {}) {
|
|
950
|
+
return JSON.parse(this.wasm.FillContentControlRichText(
|
|
951
|
+
this.handle,
|
|
952
|
+
anchorId,
|
|
953
|
+
markdown,
|
|
954
|
+
JSON.stringify(options)
|
|
955
|
+
));
|
|
956
|
+
}
|
|
957
|
+
setContentControlChecked(anchorId, isChecked, options = {}) {
|
|
958
|
+
return JSON.parse(this.wasm.SetContentControlChecked(
|
|
959
|
+
this.handle,
|
|
960
|
+
anchorId,
|
|
961
|
+
isChecked,
|
|
962
|
+
JSON.stringify(options)
|
|
963
|
+
));
|
|
964
|
+
}
|
|
965
|
+
setContentControlDate(anchorId, value, displayText, options = {}) {
|
|
966
|
+
const timestamp = value instanceof Date ? value.toISOString() : value;
|
|
967
|
+
return JSON.parse(this.wasm.SetContentControlDate(
|
|
968
|
+
this.handle,
|
|
969
|
+
anchorId,
|
|
970
|
+
timestamp,
|
|
971
|
+
displayText ?? null,
|
|
972
|
+
JSON.stringify(options)
|
|
973
|
+
));
|
|
974
|
+
}
|
|
975
|
+
selectContentControlItem(anchorId, value, options = {}) {
|
|
976
|
+
return JSON.parse(this.wasm.SelectContentControlItem(
|
|
977
|
+
this.handle,
|
|
978
|
+
anchorId,
|
|
979
|
+
value,
|
|
980
|
+
JSON.stringify(options)
|
|
981
|
+
));
|
|
982
|
+
}
|
|
983
|
+
fillContentControlPicture(anchorId, bytes, options = {}) {
|
|
984
|
+
return JSON.parse(this.wasm.FillContentControlPicture(
|
|
985
|
+
this.handle,
|
|
986
|
+
anchorId,
|
|
987
|
+
imageBytesToBase64(bytes),
|
|
988
|
+
JSON.stringify(options)
|
|
989
|
+
));
|
|
990
|
+
}
|
|
991
|
+
addRepeatingSectionItem(sectionAnchorId, afterItemAnchorId, options = {}) {
|
|
992
|
+
return JSON.parse(this.wasm.AddRepeatingSectionItem(
|
|
993
|
+
this.handle,
|
|
994
|
+
sectionAnchorId,
|
|
995
|
+
afterItemAnchorId ?? "",
|
|
996
|
+
JSON.stringify(options)
|
|
997
|
+
));
|
|
998
|
+
}
|
|
999
|
+
removeRepeatingSectionItem(itemAnchorId) {
|
|
1000
|
+
return JSON.parse(this.wasm.RemoveRepeatingSectionItem(
|
|
1001
|
+
this.handle,
|
|
1002
|
+
itemAnchorId
|
|
1003
|
+
));
|
|
1004
|
+
}
|
|
1005
|
+
listBookmarks(scopes = 63 /* All */) {
|
|
1006
|
+
return JSON.parse(this.wasm.ListBookmarks(this.handle, scopes));
|
|
1007
|
+
}
|
|
1008
|
+
addBookmark(name, range) {
|
|
1009
|
+
return JSON.parse(this.wasm.AddBookmark(
|
|
1010
|
+
this.handle,
|
|
1011
|
+
name,
|
|
1012
|
+
range.startAnchorId,
|
|
1013
|
+
range.startOffset,
|
|
1014
|
+
range.endAnchorId,
|
|
1015
|
+
range.endOffset
|
|
1016
|
+
));
|
|
1017
|
+
}
|
|
1018
|
+
renameBookmark(name, newName) {
|
|
1019
|
+
return JSON.parse(this.wasm.RenameBookmark(this.handle, name, newName));
|
|
1020
|
+
}
|
|
1021
|
+
moveBookmark(name, range) {
|
|
1022
|
+
return JSON.parse(this.wasm.MoveBookmark(
|
|
1023
|
+
this.handle,
|
|
1024
|
+
name,
|
|
1025
|
+
range.startAnchorId,
|
|
1026
|
+
range.startOffset,
|
|
1027
|
+
range.endAnchorId,
|
|
1028
|
+
range.endOffset
|
|
1029
|
+
));
|
|
1030
|
+
}
|
|
1031
|
+
removeBookmark(name) {
|
|
1032
|
+
return JSON.parse(this.wasm.RemoveBookmark(this.handle, name));
|
|
1033
|
+
}
|
|
443
1034
|
// ─── Tracked revisions (issue #318) ──────────────────────────────────
|
|
444
1035
|
/** Markup-native tracked-revision listing, in document order across body, headers,
|
|
445
1036
|
* footers, footnotes, and endnotes. Ids are stable while the underlying markup
|
|
@@ -460,6 +1051,22 @@ var DocxodusSession = (() => {
|
|
|
460
1051
|
rejectRevision(revisionId) {
|
|
461
1052
|
return JSON.parse(this.wasm.RejectRevision(this.handle, revisionId));
|
|
462
1053
|
}
|
|
1054
|
+
/**
|
|
1055
|
+
* Accept every live revision as one undoable session mutation.
|
|
1056
|
+
*
|
|
1057
|
+
* Fails closed: an unsupported, malformed, or ambiguous registry entry aborts the whole
|
|
1058
|
+
* operation (`revisionUnsupported`/`revisionMalformed`/`revisionAmbiguous`) and nothing is
|
|
1059
|
+
* mutated. There is no force mode — call {@link listRevisions} and read each entry's
|
|
1060
|
+
* `diagnostic` to see what blocks it.
|
|
1061
|
+
*/
|
|
1062
|
+
acceptAllRevisions() {
|
|
1063
|
+
return JSON.parse(this.wasm.AcceptAllRevisions(this.handle));
|
|
1064
|
+
}
|
|
1065
|
+
/** Reject every live revision as one undoable session mutation. Fails closed exactly like
|
|
1066
|
+
* {@link acceptAllRevisions}. */
|
|
1067
|
+
rejectAllRevisions() {
|
|
1068
|
+
return JSON.parse(this.wasm.RejectAllRevisions(this.handle));
|
|
1069
|
+
}
|
|
463
1070
|
// ─── Tier C: formatting ──────────────────────────────────────────────
|
|
464
1071
|
applyFormat(anchorId, span, op) {
|
|
465
1072
|
const spanJson = span ? JSON.stringify(span) : "";
|
|
@@ -565,6 +1172,10 @@ var DocxodusSession = (() => {
|
|
|
565
1172
|
* replaces it with `replace`, preserving the surrounding run formatting that
|
|
566
1173
|
* the match didn't touch. Returns one `EditResult` per attempted match.
|
|
567
1174
|
*
|
|
1175
|
+
* A `find` that matches nothing fails with a single `text_not_found` result
|
|
1176
|
+
* naming the anchor and the needle — never an empty array. Pass
|
|
1177
|
+
* `expectedMatchCount: 0` to assert absence as a successful no-op instead.
|
|
1178
|
+
*
|
|
568
1179
|
* Run-formatting contract: the replacement text inherits the formatting of
|
|
569
1180
|
* the FIRST run the match spanned. Middle/trailing runs keep their `w:rPr`
|
|
570
1181
|
* but lose the slice of text the match consumed.
|
|
@@ -741,10 +1352,16 @@ var DocxodusSession = (() => {
|
|
|
741
1352
|
*
|
|
742
1353
|
* @see docs/architecture/docx_mutation_api.md#findplaceholders
|
|
743
1354
|
*/
|
|
744
|
-
findPlaceholders(kinds = PlaceholderKinds.All, scope = 1, contextChars = 80, boundary = ContextBoundary.Char) {
|
|
745
|
-
|
|
746
|
-
this.
|
|
747
|
-
|
|
1355
|
+
findPlaceholders(kinds = PlaceholderKinds.All, scope = 1, contextChars = 80, boundary = ContextBoundary.Char, citation) {
|
|
1356
|
+
const json = citation ? this.wasm.FindPlaceholdersWithCitations(
|
|
1357
|
+
this.handle,
|
|
1358
|
+
kinds,
|
|
1359
|
+
scope,
|
|
1360
|
+
contextChars,
|
|
1361
|
+
boundary,
|
|
1362
|
+
JSON.stringify(citation)
|
|
1363
|
+
) : this.wasm.FindPlaceholders(this.handle, kinds, scope, contextChars, boundary);
|
|
1364
|
+
return JSON.parse(json);
|
|
748
1365
|
}
|
|
749
1366
|
/**
|
|
750
1367
|
* Returns a snapshot of edit-state introspection signals — placeholder counts,
|
|
@@ -767,6 +1384,23 @@ var DocxodusSession = (() => {
|
|
|
767
1384
|
}
|
|
768
1385
|
return raw;
|
|
769
1386
|
}
|
|
1387
|
+
/**
|
|
1388
|
+
* Return stable semantic changes from the package opened for this session to
|
|
1389
|
+
* its current state. Requires `captureInitialProjection` (enabled by default).
|
|
1390
|
+
*/
|
|
1391
|
+
getSemanticChanges() {
|
|
1392
|
+
return JSON.parse(this.wasm.GetSemanticChanges(this.handle));
|
|
1393
|
+
}
|
|
1394
|
+
/**
|
|
1395
|
+
* Run the default deliverable gate on this session's normal clean-save checkpoint.
|
|
1396
|
+
* With initial projection capture enabled (the default), exact opening bytes are the
|
|
1397
|
+
* baseline used for dispositions and semantic/package deltas.
|
|
1398
|
+
*/
|
|
1399
|
+
verifyDeliverable() {
|
|
1400
|
+
return JSON.parse(
|
|
1401
|
+
this.wasm.VerifyDeliverable(this.handle)
|
|
1402
|
+
);
|
|
1403
|
+
}
|
|
770
1404
|
// ─── Annotation-based anchor discovery (#132) ────────────────────────
|
|
771
1405
|
/**
|
|
772
1406
|
* Resolves an annotation's range to the block-level markdown anchors covering
|
|
@@ -782,8 +1416,9 @@ var DocxodusSession = (() => {
|
|
|
782
1416
|
*
|
|
783
1417
|
* @see docs/architecture/docx_mutation_api.md#findbyannotation
|
|
784
1418
|
*/
|
|
785
|
-
findByAnnotation(annotationId) {
|
|
786
|
-
|
|
1419
|
+
findByAnnotation(annotationId, citation) {
|
|
1420
|
+
const json = citation ? this.wasm.FindByAnnotationWithCitations(this.handle, annotationId, JSON.stringify(citation)) : this.wasm.FindByAnnotation(this.handle, annotationId);
|
|
1421
|
+
return JSON.parse(json);
|
|
787
1422
|
}
|
|
788
1423
|
/**
|
|
789
1424
|
* Finds every annotation whose `labelId` matches and resolves each of their
|
|
@@ -792,8 +1427,9 @@ var DocxodusSession = (() => {
|
|
|
792
1427
|
* annotations on different paragraphs become three entries). Annotations
|
|
793
1428
|
* whose bookmark resolves to no anchors are omitted from the result.
|
|
794
1429
|
*/
|
|
795
|
-
findByLabel(labelId) {
|
|
796
|
-
|
|
1430
|
+
findByLabel(labelId, citation) {
|
|
1431
|
+
const json = citation ? this.wasm.FindByLabelWithCitations(this.handle, labelId, JSON.stringify(citation)) : this.wasm.FindByLabel(this.handle, labelId);
|
|
1432
|
+
return JSON.parse(json);
|
|
797
1433
|
}
|
|
798
1434
|
/**
|
|
799
1435
|
* Resolves any bookmark in the main document part (Docxodus-managed or
|
|
@@ -801,8 +1437,9 @@ var DocxodusSession = (() => {
|
|
|
801
1437
|
* order. Empty when the bookmark name is unknown. Use this for raw bookmark
|
|
802
1438
|
* names that didn't come from the annotation system.
|
|
803
1439
|
*/
|
|
804
|
-
findByBookmark(bookmarkName) {
|
|
805
|
-
|
|
1440
|
+
findByBookmark(bookmarkName, citation) {
|
|
1441
|
+
const json = citation ? this.wasm.FindByBookmarkWithCitations(this.handle, bookmarkName, JSON.stringify(citation)) : this.wasm.FindByBookmark(this.handle, bookmarkName);
|
|
1442
|
+
return JSON.parse(json);
|
|
806
1443
|
}
|
|
807
1444
|
// ─── Text/kind-based anchor discovery (#171) ─────────────────────────
|
|
808
1445
|
/**
|
|
@@ -847,15 +1484,25 @@ var DocxodusSession = (() => {
|
|
|
847
1484
|
);
|
|
848
1485
|
}
|
|
849
1486
|
/**
|
|
850
|
-
* Return every anchor of the given `kind`
|
|
851
|
-
* `"
|
|
1487
|
+
* Return every anchor of the given `kind` — one of `"p"`, `"h"`, `"li"`,
|
|
1488
|
+
* `"tbl"`, `"tr"`, `"tc"`, `"col"`, `"sdt"`, `"sec"`, `"fn"`, `"en"`,
|
|
1489
|
+
* `"cmt"`, `"unk"` — in document order. Matching is an exact string comparison;
|
|
1490
|
+
* in particular the row and cell tokens are `"tr"` and `"tc"`, never
|
|
1491
|
+
* `"row"`/`"cell"`. Unknown strings are not parsed or rejected: they simply
|
|
1492
|
+
* return an empty array. `"img"` and `"drw"` likewise return empty because the
|
|
1493
|
+
* projection never assigns those reserved kinds; address images through the
|
|
1494
|
+
* image surface instead. Reads the projection's anchor
|
|
852
1495
|
* index directly — no text scan. Pass `scope` (e.g. `"body"`) to restrict to
|
|
853
1496
|
* a single part; omit it to span all scopes.
|
|
854
1497
|
*/
|
|
855
|
-
findByKind(kind, scope) {
|
|
856
|
-
|
|
857
|
-
this.
|
|
858
|
-
|
|
1498
|
+
findByKind(kind, scope, citation) {
|
|
1499
|
+
const json = citation ? this.wasm.FindByKindWithCitations(
|
|
1500
|
+
this.handle,
|
|
1501
|
+
kind,
|
|
1502
|
+
scope ?? "",
|
|
1503
|
+
JSON.stringify(citation)
|
|
1504
|
+
) : this.wasm.FindByKind(this.handle, kind, scope ?? "");
|
|
1505
|
+
return JSON.parse(json);
|
|
859
1506
|
}
|
|
860
1507
|
/**
|
|
861
1508
|
* Look up a single anchor's preview info — `{ id, kind, scope, textPreview }`.
|
|
@@ -909,6 +1556,18 @@ var DocxodusSession = (() => {
|
|
|
909
1556
|
const raw = this.wasm.GetSectionInfo(this.handle, anchorId);
|
|
910
1557
|
return JSON.parse(raw);
|
|
911
1558
|
}
|
|
1559
|
+
/** Enumerate the document's explicit style catalog with resolved high-signal properties. */
|
|
1560
|
+
listStyles() {
|
|
1561
|
+
return JSON.parse(this.wasm.ListStyles(this.handle));
|
|
1562
|
+
}
|
|
1563
|
+
/** Inspect direct and effective paragraph/run formatting for one paragraph anchor. */
|
|
1564
|
+
getFormatting(anchorId) {
|
|
1565
|
+
return JSON.parse(this.wasm.GetFormatting(this.handle, anchorId));
|
|
1566
|
+
}
|
|
1567
|
+
/** Enumerate text-bearing runs as mutation-compatible anchor/span pairs. */
|
|
1568
|
+
listInlineSpans(anchorId) {
|
|
1569
|
+
return JSON.parse(this.wasm.ListInlineSpans(this.handle, anchorId));
|
|
1570
|
+
}
|
|
912
1571
|
/**
|
|
913
1572
|
* Enumerates every annotation persisted in the document. Lets an agent prime
|
|
914
1573
|
* itself with "here are the labeled regions you can target" before committing
|
|
@@ -973,6 +1632,13 @@ var DocxodusSession = (() => {
|
|
|
973
1632
|
this.close();
|
|
974
1633
|
}
|
|
975
1634
|
};
|
|
1635
|
+
function imageBytesToBase64(bytes) {
|
|
1636
|
+
let binary = "";
|
|
1637
|
+
for (let offset = 0; offset < bytes.length; offset += 32768) {
|
|
1638
|
+
binary += String.fromCharCode(...bytes.subarray(offset, offset + 32768));
|
|
1639
|
+
}
|
|
1640
|
+
return globalThis.btoa(binary);
|
|
1641
|
+
}
|
|
976
1642
|
function openDocxSession(bytes, wasmExports, settings) {
|
|
977
1643
|
const bridge = wasmExports.DocxSessionBridge;
|
|
978
1644
|
const handle = bridge.OpenSession(bytes, settings ? JSON.stringify(settings) : "");
|