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/index.js
CHANGED
|
@@ -20,8 +20,8 @@ export function openDocxSession(bytes, settings) {
|
|
|
20
20
|
export function createBlankDocx() {
|
|
21
21
|
return ensureInitialized().DocxSessionBridge.CreateBlankDocx();
|
|
22
22
|
}
|
|
23
|
-
import { CommentRenderMode, PaginationMode, AnnotationLabelMode, RevisionType,
|
|
24
|
-
export { PaginationEngine, paginateHtml } from "./pagination.js";
|
|
23
|
+
import { CommentRenderMode, PaginationMode, AnnotationLabelMode, RevisionType, DocxDiffRevisionGranularity, DocxDiffFormatComparison, ConflictResolution, ProjectionScopes, AnchorRenderMode, TableRenderMode, TrackedChangeMode, EmptyParagraphMode, AnchorIdRendering, ProjectionDepth, DocumentElementType, ComparisonLogLevel, ComparisonLogCodes, isInsertion, isDeletion, isMove, isFormatChange, findElementById, findElementsByType, getParagraphs, getTables, getTableColumns, targetElement, targetParagraph, targetParagraphRange, targetRun, targetTable, targetTableRow, targetTableCell, targetTableColumn, targetSearch, targetSearchInElement, } from "./types.js";
|
|
24
|
+
export { PaginationEngine, clearPageCitationHighlight, createUnavailablePageMap, navigateToPageCitation, paginateHtml, } from "./pagination.js";
|
|
25
25
|
// Page geometry is the document's own page setup (w:sectPr), read off the section wrappers
|
|
26
26
|
// the converter stamps in every render mode, plus the fit-to-width zoom a view applies to it.
|
|
27
27
|
export { DEFAULT_MARGIN, DEFAULT_PAGE_HEIGHT, DEFAULT_PAGE_WIDTH, fitScale, parseSectionDimensions, ptToPx, pxToPt, } from "./page-geometry.js";
|
|
@@ -31,7 +31,7 @@ export { DocxEditor } from "./editor.js";
|
|
|
31
31
|
// loading overlay wired onto DocxEditor's command surface. `createRibbonEditor`
|
|
32
32
|
// (docxodus/embed) is the one-call version that also boots WASM.
|
|
33
33
|
export { mountRibbon } from "./ribbon.js";
|
|
34
|
-
export { CommentRenderMode, PaginationMode, AnnotationLabelMode, RevisionType,
|
|
34
|
+
export { CommentRenderMode, PaginationMode, AnnotationLabelMode, RevisionType, DocxDiffRevisionGranularity, DocxDiffFormatComparison, ConflictResolution, ProjectionScopes, AnchorRenderMode, TableRenderMode, TrackedChangeMode, EmptyParagraphMode, AnchorIdRendering, ProjectionDepth, DocumentElementType, ComparisonLogLevel, ComparisonLogCodes, isInsertion, isDeletion, isMove, isFormatChange,
|
|
35
35
|
// Document structure helpers
|
|
36
36
|
findElementById, findElementsByType, getParagraphs, getTables, getTableColumns,
|
|
37
37
|
// Annotation target factory functions
|
|
@@ -71,7 +71,7 @@ async function yieldToMain() {
|
|
|
71
71
|
function getDefaultWasmBasePath() {
|
|
72
72
|
try {
|
|
73
73
|
// import.meta.url gives us the URL of this module
|
|
74
|
-
// e.g., "https://cdn.jsdelivr.net/npm/docxodus@
|
|
74
|
+
// e.g., "https://cdn.jsdelivr.net/npm/docxodus@10.0.0/dist/index.js"
|
|
75
75
|
// or "file:///path/to/node_modules/docxodus/dist/index.js"
|
|
76
76
|
const moduleUrl = import.meta.url;
|
|
77
77
|
// Remove the filename to get the directory
|
|
@@ -206,6 +206,71 @@ async function toBytes(input) {
|
|
|
206
206
|
const buffer = await input.arrayBuffer();
|
|
207
207
|
return new Uint8Array(buffer);
|
|
208
208
|
}
|
|
209
|
+
/**
|
|
210
|
+
* Generate a deterministic, non-mutating verification manifest from DOCX bytes.
|
|
211
|
+
* Invalid, malformed, and encrypted packages are represented by structured findings.
|
|
212
|
+
*/
|
|
213
|
+
export async function generatePackageManifest(document) {
|
|
214
|
+
const exports = ensureInitialized();
|
|
215
|
+
const bytes = await toBytes(document);
|
|
216
|
+
await yieldToMain();
|
|
217
|
+
return JSON.parse(exports.DocumentConverter.GeneratePackageManifest(bytes));
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Run the default bounded deliverable-verification policy on exact DOCX bytes.
|
|
221
|
+
* Invalid, malformed, encrypted, and safety-limited packages are returned as
|
|
222
|
+
* structured report findings rather than editable-session errors. When supplied,
|
|
223
|
+
* the exact baseline bytes are used to classify pre-existing, new, and resolved findings.
|
|
224
|
+
*/
|
|
225
|
+
export async function verifyDeliverable(document, baseline) {
|
|
226
|
+
const exports = ensureInitialized();
|
|
227
|
+
const bytes = await toBytes(document);
|
|
228
|
+
const baselineBytes = baseline === undefined ? undefined : await toBytes(baseline);
|
|
229
|
+
await yieldToMain();
|
|
230
|
+
return JSON.parse(baselineBytes === undefined
|
|
231
|
+
? exports.DocumentConverter.VerifyDeliverable(bytes)
|
|
232
|
+
: exports.DocumentConverter.VerifyDeliverableWithBaseline(baselineBytes, bytes));
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Verify a portable JSON delivery change receipt against supplied artifact bytes.
|
|
236
|
+
*
|
|
237
|
+
* The receipt travels as its JSON envelope string; `artifacts` maps each artifact id
|
|
238
|
+
* the receipt records to the exact bytes to independently re-hash against it. Omitted
|
|
239
|
+
* artifacts report `"missing"`. Malformed input yields a structured invalid verdict
|
|
240
|
+
* whose findings carry the reason — never a thrown error.
|
|
241
|
+
*/
|
|
242
|
+
export async function verifyDeliveryReceipt(receiptJson, artifacts) {
|
|
243
|
+
const exports = ensureInitialized();
|
|
244
|
+
const artifactsJson = artifacts === undefined
|
|
245
|
+
? ""
|
|
246
|
+
: JSON.stringify(Object.fromEntries(Object.entries(artifacts).map(([artifactId, bytes]) => [
|
|
247
|
+
artifactId,
|
|
248
|
+
bytesToBase64(bytes),
|
|
249
|
+
])));
|
|
250
|
+
await yieldToMain();
|
|
251
|
+
return JSON.parse(exports.DocumentConverter.VerifyDeliveryReceipt(receiptJson, artifactsJson));
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Prove that a redline's generated revisions accept to the intended final and reject to the
|
|
255
|
+
* selected baseline without consuming pre-existing review state.
|
|
256
|
+
*
|
|
257
|
+
* Three packages are inspected and two rebuilt, so on a UI thread prefer the worker proxy's
|
|
258
|
+
* `proveRedlineReversibility`. Malformed, encrypted, and safety-limited packages are reported as
|
|
259
|
+
* structured proof findings rather than thrown errors. The rebuilt packages are not returned:
|
|
260
|
+
* the proof carries their digests and the divergences between them and each expected document.
|
|
261
|
+
*
|
|
262
|
+
* @param baseline - The document the redline was generated against
|
|
263
|
+
* @param intendedFinal - The document accepting the generated revisions must reproduce
|
|
264
|
+
* @param redline - The generated redline under proof
|
|
265
|
+
*/
|
|
266
|
+
export async function proveRedlineReversibility(baseline, intendedFinal, redline) {
|
|
267
|
+
const exports = ensureInitialized();
|
|
268
|
+
const baselineBytes = await toBytes(baseline);
|
|
269
|
+
const intendedFinalBytes = await toBytes(intendedFinal);
|
|
270
|
+
const redlineBytes = await toBytes(redline);
|
|
271
|
+
await yieldToMain();
|
|
272
|
+
return JSON.parse(exports.DocumentConverter.ProveRedlineReversibility(baselineBytes, intendedFinalBytes, redlineBytes));
|
|
273
|
+
}
|
|
209
274
|
/**
|
|
210
275
|
* Convert a DOCX document to HTML.
|
|
211
276
|
*
|
|
@@ -319,12 +384,11 @@ export async function compareDocuments(original, modified, options) {
|
|
|
319
384
|
// Yield to browser before heavy WASM work - allows loading states to render
|
|
320
385
|
await yieldToMain();
|
|
321
386
|
let result;
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
result = exports.DocumentComparer.CompareDocumentsWithOptions(originalBytes, modifiedBytes, options?.authorName ?? "Docxodus", options?.detailThreshold ?? 0.15, options?.caseInsensitive ?? false, engine);
|
|
387
|
+
if (options?.caseInsensitive) {
|
|
388
|
+
result = exports.DocumentComparer.CompareDocumentsWithOptions(originalBytes, modifiedBytes, options?.authorName ?? "Docxodus", options.caseInsensitive);
|
|
325
389
|
}
|
|
326
390
|
else {
|
|
327
|
-
result = exports.DocumentComparer.CompareDocuments(originalBytes, modifiedBytes, options?.authorName ?? "Docxodus"
|
|
391
|
+
result = exports.DocumentComparer.CompareDocuments(originalBytes, modifiedBytes, options?.authorName ?? "Docxodus");
|
|
328
392
|
}
|
|
329
393
|
if (result.length === 0) {
|
|
330
394
|
throw new Error("Comparison failed - empty result");
|
|
@@ -347,14 +411,12 @@ export async function compareDocumentsToHtml(original, modified, options) {
|
|
|
347
411
|
// Yield to browser before heavy WASM work - allows loading states to render
|
|
348
412
|
await yieldToMain();
|
|
349
413
|
const renderTrackedChanges = options?.renderTrackedChanges ?? true;
|
|
350
|
-
const engine = options?.engine ?? ComparisonEngine.DocxDiff;
|
|
351
414
|
let result;
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
result = exports.DocumentComparer.CompareDocumentsToHtmlFull(originalBytes, modifiedBytes, options?.authorName ?? "Docxodus", options?.detailThreshold ?? 0.15, options?.caseInsensitive ?? false, renderTrackedChanges, engine);
|
|
415
|
+
if (options?.caseInsensitive !== undefined) {
|
|
416
|
+
result = exports.DocumentComparer.CompareDocumentsToHtmlFull(originalBytes, modifiedBytes, options?.authorName ?? "Docxodus", options.caseInsensitive, renderTrackedChanges);
|
|
355
417
|
}
|
|
356
418
|
else {
|
|
357
|
-
result = exports.DocumentComparer.CompareDocumentsToHtmlWithOptions(originalBytes, modifiedBytes, options?.authorName ?? "Docxodus", renderTrackedChanges
|
|
419
|
+
result = exports.DocumentComparer.CompareDocumentsToHtmlWithOptions(originalBytes, modifiedBytes, options?.authorName ?? "Docxodus", renderTrackedChanges);
|
|
358
420
|
}
|
|
359
421
|
if (isErrorResponse(result)) {
|
|
360
422
|
const error = parseError(result);
|
|
@@ -362,107 +424,6 @@ export async function compareDocumentsToHtml(original, modified, options) {
|
|
|
362
424
|
}
|
|
363
425
|
return result;
|
|
364
426
|
}
|
|
365
|
-
/**
|
|
366
|
-
* Compare two DOCX documents with logging enabled.
|
|
367
|
-
* Returns both the redlined document and a log of any warnings/errors encountered.
|
|
368
|
-
* This allows the comparison to continue past recoverable issues (like orphaned footnotes)
|
|
369
|
-
* while providing visibility into what was fixed or skipped.
|
|
370
|
-
*
|
|
371
|
-
* @param original - Original DOCX document
|
|
372
|
-
* @param modified - Modified DOCX document
|
|
373
|
-
* @param options - Comparison options
|
|
374
|
-
* @returns Result with document bytes and log entries
|
|
375
|
-
*
|
|
376
|
-
* @example
|
|
377
|
-
* ```typescript
|
|
378
|
-
* const result = await compareDocumentsWithLog(original, modified, {
|
|
379
|
-
* authorName: "Reviewer",
|
|
380
|
-
* detailThreshold: 0.15
|
|
381
|
-
* });
|
|
382
|
-
*
|
|
383
|
-
* if (result.success) {
|
|
384
|
-
* // Use result.document (Uint8Array)
|
|
385
|
-
* if (result.hasWarnings) {
|
|
386
|
-
* console.log("Warnings during comparison:");
|
|
387
|
-
* for (const entry of result.log) {
|
|
388
|
-
* console.log(` [${entry.level}] ${entry.code}: ${entry.message}`);
|
|
389
|
-
* }
|
|
390
|
-
* }
|
|
391
|
-
* } else {
|
|
392
|
-
* console.error(`Comparison failed: ${result.error}`);
|
|
393
|
-
* }
|
|
394
|
-
* ```
|
|
395
|
-
*/
|
|
396
|
-
export async function compareDocumentsWithLog(original, modified, options) {
|
|
397
|
-
const exports = ensureInitialized();
|
|
398
|
-
const originalBytes = await toBytes(original);
|
|
399
|
-
const modifiedBytes = await toBytes(modified);
|
|
400
|
-
await yieldToMain();
|
|
401
|
-
const result = exports.DocumentComparer.CompareDocumentsWithLog(originalBytes, modifiedBytes, options?.authorName ?? "Docxodus", options?.detailThreshold ?? 0.15, options?.caseInsensitive ?? false);
|
|
402
|
-
const parsed = JSON.parse(result);
|
|
403
|
-
return {
|
|
404
|
-
success: parsed.Success ?? parsed.success ?? false,
|
|
405
|
-
document: parsed.DocumentBase64 || parsed.documentBase64
|
|
406
|
-
? Uint8Array.from(atob(parsed.DocumentBase64 || parsed.documentBase64), c => c.charCodeAt(0))
|
|
407
|
-
: undefined,
|
|
408
|
-
error: parsed.Error ?? parsed.error,
|
|
409
|
-
log: convertLogEntries(parsed.Log || parsed.log || []),
|
|
410
|
-
hasWarnings: parsed.HasWarnings ?? parsed.hasWarnings ?? false,
|
|
411
|
-
hasErrors: parsed.HasErrors ?? parsed.hasErrors ?? false,
|
|
412
|
-
};
|
|
413
|
-
}
|
|
414
|
-
/**
|
|
415
|
-
* Compare two DOCX documents to HTML with logging enabled.
|
|
416
|
-
* Returns both the HTML output and a log of any warnings/errors encountered.
|
|
417
|
-
*
|
|
418
|
-
* @param original - Original DOCX document
|
|
419
|
-
* @param modified - Modified DOCX document
|
|
420
|
-
* @param options - Comparison options
|
|
421
|
-
* @returns Result with HTML and log entries
|
|
422
|
-
*
|
|
423
|
-
* @example
|
|
424
|
-
* ```typescript
|
|
425
|
-
* const result = await compareDocumentsToHtmlWithLog(original, modified, {
|
|
426
|
-
* authorName: "Reviewer",
|
|
427
|
-
* renderTrackedChanges: true
|
|
428
|
-
* });
|
|
429
|
-
*
|
|
430
|
-
* if (result.success) {
|
|
431
|
-
* document.getElementById("viewer").innerHTML = result.html;
|
|
432
|
-
* if (result.hasWarnings) {
|
|
433
|
-
* console.log(`${result.log.length} warnings during comparison`);
|
|
434
|
-
* }
|
|
435
|
-
* }
|
|
436
|
-
* ```
|
|
437
|
-
*/
|
|
438
|
-
export async function compareDocumentsToHtmlWithLog(original, modified, options) {
|
|
439
|
-
const exports = ensureInitialized();
|
|
440
|
-
const originalBytes = await toBytes(original);
|
|
441
|
-
const modifiedBytes = await toBytes(modified);
|
|
442
|
-
await yieldToMain();
|
|
443
|
-
const result = exports.DocumentComparer.CompareDocumentsToHtmlWithLog(originalBytes, modifiedBytes, options?.authorName ?? "Docxodus", options?.detailThreshold ?? 0.15, options?.caseInsensitive ?? false, options?.renderTrackedChanges ?? true);
|
|
444
|
-
const parsed = JSON.parse(result);
|
|
445
|
-
return {
|
|
446
|
-
success: parsed.Success ?? parsed.success ?? false,
|
|
447
|
-
html: parsed.Html ?? parsed.html,
|
|
448
|
-
error: parsed.Error ?? parsed.error,
|
|
449
|
-
log: convertLogEntries(parsed.Log || parsed.log || []),
|
|
450
|
-
hasWarnings: parsed.HasWarnings ?? parsed.hasWarnings ?? false,
|
|
451
|
-
hasErrors: parsed.HasErrors ?? parsed.hasErrors ?? false,
|
|
452
|
-
};
|
|
453
|
-
}
|
|
454
|
-
/**
|
|
455
|
-
* Convert log entries from PascalCase to camelCase.
|
|
456
|
-
*/
|
|
457
|
-
function convertLogEntries(entries) {
|
|
458
|
-
return entries.map((e) => ({
|
|
459
|
-
level: e.Level ?? e.level ?? "Info",
|
|
460
|
-
code: e.Code ?? e.code ?? "",
|
|
461
|
-
message: e.Message ?? e.message ?? "",
|
|
462
|
-
details: e.Details ?? e.details,
|
|
463
|
-
location: e.Location ?? e.location,
|
|
464
|
-
}));
|
|
465
|
-
}
|
|
466
427
|
/**
|
|
467
428
|
* Get revisions from a compared document.
|
|
468
429
|
*
|
|
@@ -488,35 +449,18 @@ function convertLogEntries(entries) {
|
|
|
488
449
|
* const revisions = await getRevisions(comparedDoc, { detectMoves: false });
|
|
489
450
|
* ```
|
|
490
451
|
*/
|
|
491
|
-
export async function getRevisions(document
|
|
452
|
+
export async function getRevisions(document) {
|
|
492
453
|
const exports = ensureInitialized();
|
|
493
454
|
const bytes = await toBytes(document);
|
|
494
455
|
// Yield to browser before WASM work - allows loading states to render
|
|
495
456
|
await yieldToMain();
|
|
496
|
-
|
|
497
|
-
const detectMoves = options?.detectMoves ?? true;
|
|
498
|
-
const moveSimilarityThreshold = options?.moveSimilarityThreshold ?? 0.8;
|
|
499
|
-
const moveMinimumWordCount = options?.moveMinimumWordCount ?? 3;
|
|
500
|
-
const caseInsensitive = options?.caseInsensitive ?? false;
|
|
501
|
-
const result = exports.DocumentComparer.GetRevisionsJsonWithOptions(bytes, detectMoves, moveSimilarityThreshold, moveMinimumWordCount, caseInsensitive);
|
|
457
|
+
const result = exports.DocumentComparer.GetRevisionsJson(bytes);
|
|
502
458
|
if (isErrorResponse(result)) {
|
|
503
459
|
const error = parseError(result);
|
|
504
460
|
throw new Error(`Failed to get revisions: ${error.error}`);
|
|
505
461
|
}
|
|
506
|
-
|
|
507
|
-
return
|
|
508
|
-
author: r.Author || r.author,
|
|
509
|
-
date: r.Date || r.date,
|
|
510
|
-
revisionType: r.RevisionType || r.revisionType,
|
|
511
|
-
text: r.Text || r.text,
|
|
512
|
-
moveGroupId: r.MoveGroupId ?? r.moveGroupId,
|
|
513
|
-
isMoveSource: r.IsMoveSource ?? r.isMoveSource,
|
|
514
|
-
formatChange: (r.FormatChange || r.formatChange) ? {
|
|
515
|
-
oldProperties: r.FormatChange?.OldProperties || r.formatChange?.oldProperties,
|
|
516
|
-
newProperties: r.FormatChange?.NewProperties || r.formatChange?.newProperties,
|
|
517
|
-
changedPropertyNames: r.FormatChange?.ChangedPropertyNames || r.formatChange?.changedPropertyNames,
|
|
518
|
-
} : undefined,
|
|
519
|
-
}));
|
|
462
|
+
// The payload is the session's own revision wire shape, so it needs no remapping.
|
|
463
|
+
return JSON.parse(result);
|
|
520
464
|
}
|
|
521
465
|
// ─── DocxDiff (IR diff engine) ──────────────────────────────────────────────
|
|
522
466
|
//
|
|
@@ -569,20 +513,98 @@ export async function docxDiffGetRevisions(left, right, settings) {
|
|
|
569
513
|
throw new Error(`Failed to get DocxDiff revisions: ${error.error}`);
|
|
570
514
|
}
|
|
571
515
|
const parsed = JSON.parse(result);
|
|
572
|
-
return (parsed.revisions || parsed.Revisions || []).map(
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
516
|
+
return (parsed.revisions || parsed.Revisions || []).map(mapDocxDiffRevision);
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Compare two DOCX documents ONCE and return every requested data product from
|
|
520
|
+
* that single memoized pass (issue #594). Where a review pipeline calling
|
|
521
|
+
* {@link docxDiffCompare}, {@link docxDiffGetRevisions}, and
|
|
522
|
+
* {@link docxDiffGetEditScript} separately pays for the alignment per call, this
|
|
523
|
+
* runs it once — each product identical to its standalone counterpart (the edit
|
|
524
|
+
* script is handed over parsed rather than as the serialized string).
|
|
525
|
+
*
|
|
526
|
+
* @param left - The earlier/original document.
|
|
527
|
+
* @param right - The later/revised document.
|
|
528
|
+
* @param settings - Optional {@link DocxDiffSettings}; omit for engine defaults.
|
|
529
|
+
* @param products - Products to compute; omit for all four.
|
|
530
|
+
* @throws Error if the operation fails.
|
|
531
|
+
*/
|
|
532
|
+
export async function docxDiffCompareProducts(left, right, settings, products) {
|
|
533
|
+
const exports = ensureInitialized();
|
|
534
|
+
const leftBytes = await toBytes(left);
|
|
535
|
+
const rightBytes = await toBytes(right);
|
|
536
|
+
await yieldToMain();
|
|
537
|
+
const result = exports.DocxDiffBridge.CompareProductsJson(leftBytes, rightBytes, docxDiffSettingsJson(settings), products ? JSON.stringify(products) : "");
|
|
538
|
+
if (isErrorResponse(result)) {
|
|
539
|
+
const error = parseError(result);
|
|
540
|
+
throw new Error(`Failed to compare products: ${error.error}`);
|
|
541
|
+
}
|
|
542
|
+
const parsed = JSON.parse(result);
|
|
543
|
+
return {
|
|
544
|
+
redline: typeof parsed.redlineB64 === "string"
|
|
545
|
+
? Uint8Array.from(atob(parsed.redlineB64), c => c.charCodeAt(0))
|
|
546
|
+
: undefined,
|
|
547
|
+
revisions: Array.isArray(parsed.revisions)
|
|
548
|
+
? parsed.revisions.map(mapDocxDiffRevision)
|
|
549
|
+
: undefined,
|
|
550
|
+
editScript: parsed.editScript !== undefined
|
|
551
|
+
? parsed.editScript
|
|
552
|
+
: undefined,
|
|
553
|
+
semanticChanges: parsed.semanticChanges !== undefined
|
|
554
|
+
? parsed.semanticChanges
|
|
555
|
+
: undefined,
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* Compare ONE baseline against MANY candidates, reading the baseline once (issue #617).
|
|
560
|
+
*
|
|
561
|
+
* The read is the single largest stage of a comparison, and a fan-out — one negotiated
|
|
562
|
+
* draft against every counterparty's markup — otherwise re-reads the baseline for each
|
|
563
|
+
* one. This reads it once and compares every candidate against that snapshot; each
|
|
564
|
+
* result is identical to what {@link docxDiffCompareProducts} returns for the same pair.
|
|
565
|
+
*
|
|
566
|
+
* A candidate that fails carries an `error` instead of products; the rest of the batch
|
|
567
|
+
* still comes back, because one malformed markup should not cost the other ninety-nine.
|
|
568
|
+
*
|
|
569
|
+
* @param baseline - The shared left-hand document.
|
|
570
|
+
* @param candidates - The documents to compare against it, in order.
|
|
571
|
+
* @param settings - Optional {@link DocxDiffSettings}; omit for engine defaults.
|
|
572
|
+
* @param products - Products to compute; omit for all four.
|
|
573
|
+
* @throws Error if the batch itself fails (a bad baseline, malformed settings).
|
|
574
|
+
*/
|
|
575
|
+
export async function docxDiffCompareBatch(baseline, candidates, settings, products) {
|
|
576
|
+
const exports = ensureInitialized();
|
|
577
|
+
const baselineBytes = await toBytes(baseline);
|
|
578
|
+
const payload = [];
|
|
579
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
580
|
+
const bytes = await toBytes(candidates[i].document);
|
|
581
|
+
payload.push({
|
|
582
|
+
name: candidates[i].name ?? String(i),
|
|
583
|
+
docB64: bytesToBase64(bytes),
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
await yieldToMain();
|
|
587
|
+
const result = exports.DocxDiffBridge.CompareBatchJson(baselineBytes, JSON.stringify(payload), docxDiffSettingsJson(settings), products ? JSON.stringify(products) : "");
|
|
588
|
+
if (isErrorResponse(result)) {
|
|
589
|
+
const error = parseError(result);
|
|
590
|
+
throw new Error(`Failed to compare batch: ${error.error}`);
|
|
591
|
+
}
|
|
592
|
+
const parsed = JSON.parse(result);
|
|
593
|
+
return (parsed.results ?? []).map((entry) => ({
|
|
594
|
+
name: String(entry.name ?? ""),
|
|
595
|
+
error: typeof entry.error === "string" ? entry.error : undefined,
|
|
596
|
+
redline: typeof entry.redlineB64 === "string"
|
|
597
|
+
? Uint8Array.from(atob(entry.redlineB64), c => c.charCodeAt(0))
|
|
598
|
+
: undefined,
|
|
599
|
+
revisions: Array.isArray(entry.revisions)
|
|
600
|
+
? entry.revisions.map(mapDocxDiffRevision)
|
|
601
|
+
: undefined,
|
|
602
|
+
editScript: entry.editScript !== undefined
|
|
603
|
+
? entry.editScript
|
|
604
|
+
: undefined,
|
|
605
|
+
semanticChanges: entry.semanticChanges !== undefined
|
|
606
|
+
? entry.semanticChanges
|
|
607
|
+
: undefined,
|
|
586
608
|
}));
|
|
587
609
|
}
|
|
588
610
|
/**
|
|
@@ -609,6 +631,23 @@ export async function docxDiffGetEditScript(left, right, settings) {
|
|
|
609
631
|
}
|
|
610
632
|
return result;
|
|
611
633
|
}
|
|
634
|
+
/**
|
|
635
|
+
* Compare two DOCX documents and return the stable, versioned semantic-change
|
|
636
|
+
* schema. This is the audit/verification surface; it classifies document meaning
|
|
637
|
+
* beyond the renderer's internal edit script and preserves unknown package changes.
|
|
638
|
+
*/
|
|
639
|
+
export async function docxDiffGetSemanticChanges(left, right, settings) {
|
|
640
|
+
const exports = ensureInitialized();
|
|
641
|
+
const leftBytes = await toBytes(left);
|
|
642
|
+
const rightBytes = await toBytes(right);
|
|
643
|
+
await yieldToMain();
|
|
644
|
+
const result = exports.DocxDiffBridge.GetSemanticChangesJson(leftBytes, rightBytes, docxDiffSettingsJson(settings));
|
|
645
|
+
if (isErrorResponse(result)) {
|
|
646
|
+
const error = parseError(result);
|
|
647
|
+
throw new Error(`Failed to get semantic changes: ${error.error}`);
|
|
648
|
+
}
|
|
649
|
+
return JSON.parse(result);
|
|
650
|
+
}
|
|
612
651
|
/**
|
|
613
652
|
* Accept every tracked revision in a redlined DOCX and return the resulting bytes
|
|
614
653
|
* (materializes the "right"/revised side). The byte-in, byte-out counterpart of
|
|
@@ -1055,6 +1094,7 @@ export async function getDocumentStructure(document) {
|
|
|
1055
1094
|
// Convert from PascalCase to camelCase
|
|
1056
1095
|
const convertElement = (el) => ({
|
|
1057
1096
|
id: el.Id || el.id,
|
|
1097
|
+
anchorId: el.AnchorId || el.anchorId,
|
|
1058
1098
|
type: el.Type || el.type,
|
|
1059
1099
|
textPreview: el.TextPreview || el.textPreview,
|
|
1060
1100
|
index: el.Index ?? el.index,
|
|
@@ -1066,8 +1106,12 @@ export async function getDocumentStructure(document) {
|
|
|
1066
1106
|
});
|
|
1067
1107
|
const convertTableColumn = (col) => ({
|
|
1068
1108
|
tableId: col.TableId || col.tableId,
|
|
1109
|
+
anchorId: col.AnchorId || col.anchorId,
|
|
1110
|
+
tableAnchorId: col.TableAnchorId || col.tableAnchorId,
|
|
1111
|
+
isVirtual: col.IsVirtual ?? col.isVirtual ?? false,
|
|
1069
1112
|
columnIndex: col.ColumnIndex ?? col.columnIndex,
|
|
1070
1113
|
cellIds: col.CellIds || col.cellIds || [],
|
|
1114
|
+
cellAnchorIds: col.CellAnchorIds || col.cellAnchorIds || [],
|
|
1071
1115
|
rowCount: col.RowCount ?? col.rowCount,
|
|
1072
1116
|
});
|
|
1073
1117
|
const root = convertElement(parsed.Root || parsed.root);
|
|
@@ -1168,6 +1212,7 @@ export async function getDocumentMetadata(document) {
|
|
|
1168
1212
|
hasTrackedChanges: parsed.HasTrackedChanges ?? parsed.hasTrackedChanges,
|
|
1169
1213
|
hasComments: parsed.HasComments ?? parsed.hasComments,
|
|
1170
1214
|
estimatedPageCount: parsed.EstimatedPageCount ?? parsed.estimatedPageCount,
|
|
1215
|
+
estimatedPageCountSource: parsed.EstimatedPageCountSource ?? parsed.estimatedPageCountSource ?? "heuristic",
|
|
1171
1216
|
};
|
|
1172
1217
|
}
|
|
1173
1218
|
/**
|