/** * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options */ /** * @module ai/aisdk/documentcompare * @publicApi */ import { Plugin, type PluginDependenciesOf } from "@ckeditor/ckeditor5-core"; import { type Operation, type ModelRange } from "@ckeditor/ckeditor5-engine"; import { DocumentChanges } from "./documentchanges.js"; import { DocumentCompareUtils } from "./documentcompareutils.js"; import { type DocumentCompareSnapshot } from "./documentsnapshot.js"; /** * `DocumentCompare` provides a set of tools that allows you to process editor document data by custom external logic, * evaluate the differences between original and processed data, and apply them as granular changes or tracked * suggestions. * * Contrary to `editor.setData()`, this does not replace the whole editor * data. Instead, atomic changes are evaluated and a small set of changes is applied to the document. This is especially * useful when the editor also uses Track Changes, Revision History, and Real-Time Collaboration features. * * Use {@link #process `process()`}, to run the whole pipeline in one call - it takes document snapshot, processes the data, * and applies granular changes: * * ```ts * await documentCompare.process( async snapshot => callMyService( snapshot.content ) ); * * // Or, to apply changes as suggestions: * await documentCompare.process( async snapshot => callMyService( snapshot.content ), { asSuggestions: true } ); * ``` * * Some integrations need to process the data in separate steps (e.g. backend processing, or when changes * are not applied immediately to the content). In this case, you can capture a snapshot first and apply the result later: * * ```ts * const snapshot = documentCompare.makeSnapshot(); * const processed = await callMyService( snapshot.content ); * * // ... * * const patch = documentCompare.diffSnapshot( snapshot, processed, { asSuggestions: true } ); * documentCompare.applyPatch( patch ); * ``` */ export declare class DocumentCompare extends Plugin { static get pluginName(): "DocumentCompare"; static get requires(): PluginDependenciesOf<[DocumentChanges, DocumentCompareUtils]>; static override get isOfficialPlugin(): true; static override get isPremiumPlugin(): true; init(): void; afterInit(): void; /** * Captures the current document state as a {@link module:ai/aisdk/documentsnapshot~DocumentCompareSnapshot}. * * The snapshot contains all data and metadata necessary to process the data and then be able to calculate differences between * the original data and the processed data. * * Importantly, `snapshot.content` holds data for each root (excluding `$graveyard`) serialized to HTML. The data is stamped with * `data-id` attributes, assigned to structural elements of the data. During processing, make sure that these `data-id`s are retained. * * See also {@link module:ai/aisdk/documentsnapshot~DocumentCompareSnapshot}. * * @param selection Ranges to capture with the snapshot as the user's selection. Must not intersect. By default no * selection is captured. * @returns The captured snapshot. */ makeSnapshot(selection?: Iterable): DocumentCompareSnapshot; /** * Diffs the snapshot against processed data, returning a document patch - a set of granular differences between the two states. * * Use `options` to set whether the patch should be calculated and applied as tracked changes or as direct changes to the document. * * You can apply the patch using {@link #applyPatch}. * * @param snapshot The captured before-state to diff against. * @param data The processed data. For multi-root editor, pass an object keyed by root name. * @param options How the comparison is computed. * @returns The patch bringing the document from the snapshot to the processed state. */ diffSnapshot(snapshot: DocumentCompareSnapshot, data: string | Record, options?: DocumentCompareDiffOptions): DocumentComparePatch; /** * Applies a patch to the current state of the document. * * As a result, all changes described by the patch are reflected in the document. Note, that this converges with all * changes that happened on the document after the snapshot was made, including both local and remote edits * (if real-time collaboration is enabled). * * Note, that the patch can be only applied to the same document as the snapshot, and only during the same editing session. * Otherwise, `documentcompare-apply-session-mismatch` error is thrown. * * The patch is first validated against a copy of the document before anything is committed. * In case if any errors or conflict resolution problems surface during this dry-run, `documentcompare-invalid-patch` * error is thrown, and the editor data is left intact. * * The changes can be applied directly to the content or as tracked suggestions (requires * {@link module:track-changes/trackchanges~TrackChanges Track changes plugin}). See also {@link #diffSnapshot}. * * @param patch The patch to apply, as produced by {@link #diffSnapshot}. */ applyPatch(patch: DocumentComparePatch): void; /** * Runs the whole processing pipeline in one call: snapshots the document, hands the snapshot to `callback` for * external processing (e.g. an AI service), then diffs returned data and applies granular changes to the document. * * If diffing or applying fails, the underlying error is rethrown and can be further handled, * unless `options.overwriteOnError` is set, in which case the current document is instead * fully replaced with the processed data, the same way as if `editor.setData()` was used. * In this case, changes that happened to the document after the snapshot was taken will be overwritten. * * @param callback Receives the captured snapshot and returns the processed data keyed by root name. * @param options Additional processing options. * @returns `true` when the process finished successfully and changes were applied granularly, * `false` when the full-replacement fallback was used. */ process(callback: (snapshot: DocumentCompareSnapshot) => Promise>, options?: DocumentCompareProcessOptions): Promise; } /** * Describes how a comparison is computed and, once recorded on a {@link ~DocumentComparePatch patch}, how it is applied. */ export interface DocumentCompareDiffOptions { /** * Whether the operations carry track-changes suggestion markers. */ asSuggestions?: boolean; } /** * Options for {@link module:ai/aisdk/documentcompare~DocumentCompare#process}. */ export interface DocumentCompareProcessOptions extends DocumentCompareDiffOptions { /** * What to do when the processing fails. * * By default, the underlying error is rethrown. * * When the options is set to `true`, the whole document is instead overwritten with the processed data * via `editor.setData()` and {@link module:ai/aisdk/documentcompare~DocumentCompare#process} returns `false`. * * Note, that the overwrite is also performed in real-time collaboration environment, and it may roll back some edits made by remote * users while `callback` was processing. Opt in only when overwriting the whole document is acceptable. */ overwriteOnError?: boolean; } /** * The result of comparing a snapshot against processed data: the operations to bring the document to the new state, * together with the snapshot metadata. * * Can be applied via {@link module:ai/aisdk/documentcompare~DocumentCompare#applyPatch}. */ export interface DocumentComparePatch { /** * The channel of the document the snapshot was captured from, validated on apply. */ channelId: string; /** * The editing session the snapshot was captured in, validated on apply. */ sessionId: string; /** * The snapshot version the operations are anchored to (used to reconcile them on apply). */ version: number; /** * The options the patch was computed with, reused when applying it. */ options: DocumentCompareDiffOptions; /** * The operations to apply, keyed by root name (a root with no changes maps to an empty array). */ operations: Record>; }