diff --git a/reconcile-js/src/index.ts b/reconcile-js/src/index.ts index 18b6d57..4ac2bc6 100644 --- a/reconcile-js/src/index.ts +++ b/reconcile-js/src/index.ts @@ -13,7 +13,7 @@ import wasmBytes from 'reconcile-text/reconcile_text_bg.wasm'; /** * Represents a text document with associated cursor positions. - * + * * This interface is used both as input to reconcile functions (to specify where * cursors are positioned in the original documents) and as output (with cursors * automatically repositioned after merging). @@ -21,7 +21,7 @@ import wasmBytes from 'reconcile-text/reconcile_text_bg.wasm'; export interface TextWithCursors { /** The document's entire content as a string */ text: string; - /** + /** * Array of cursor positions within the text. Can be null, undefined, or empty * if there are no cursors to track. Each cursor has a unique ID and position. */ @@ -30,7 +30,7 @@ export interface TextWithCursors { /** * Represents a cursor position within a text document. - * + * * Cursors are automatically repositioned during text merging to maintain their * relative positions as text is inserted, deleted, or modified around them. */ @@ -43,7 +43,7 @@ export interface CursorPosition { /** * Represents a merged text document with cursor positions and detailed change history. - * + * * This is the return type of `reconcileWithHistory()` and provides complete information * about how the merge was performed, including which parts of the final text came from * which source documents. @@ -51,12 +51,12 @@ export interface CursorPosition { export interface TextWithCursorsAndHistory { /** The merged document's entire content */ text: string; - /** + /** * Array of cursor positions within the merged text. Can be null, undefined, or empty * if there are no cursors to track. All cursors are automatically repositioned. */ cursors: null | undefined | CursorPosition[]; - /** + /** * Detailed provenance information showing the origin of each text span in the result. * Each span indicates whether it was unchanged, added from left, added from right, etc. */ @@ -65,7 +65,7 @@ export interface TextWithCursorsAndHistory { /** * Represents a span of text in the merged result with its change history. - * + * * This shows exactly which source document contributed each piece of text to the * final merged result. Useful for understanding merge decisions and creating * visualisations of how documents were combined. @@ -73,8 +73,8 @@ export interface TextWithCursorsAndHistory { export interface SpanWithHistory { /** The text content of this span */ text: string; - /** - * The origin of this text span: "Unchanged" (from original), "AddedFromLeft", + /** + * The origin of this text span: "Unchanged" (from original), "AddedFromLeft", * "AddedFromRight", "RemovedFromLeft", or "RemovedFromRight" */ history: History; @@ -82,7 +82,7 @@ export interface SpanWithHistory { /** * Tokenisation strategies for text merging. - * + * * - "Word": Splits text on word boundaries (recommended for prose and most text) * - "Character": Splits text into individual characters (fine-grained control) * - "Line": Splits text into lines (similar to git merge or diff3) @@ -98,7 +98,7 @@ const UNSUPPORTED_TOKENIZER_ERROR = `Unsupported tokenizer. Only ${TOKENIZERS.jo /** * Merges three versions of text using intelligent conflict resolution. - * + * * This is the primary function for 3-way text merging. Unlike traditional merge tools * that produce conflict markers, this function automatically resolves conflicts by * applying both sets of changes where possible. @@ -106,16 +106,16 @@ const UNSUPPORTED_TOKENIZER_ERROR = `Unsupported tokenizer. Only ${TOKENIZERS.jo * @param original - The original/base version of the text that both sides diverged from * @param left - The left version of the text (either string or TextWithCursors with cursor positions) * @param right - The right version of the text (either string or TextWithCursors with cursor positions) - * @param tokenizer - The tokenisation strategy: "Word" (default, recommended for prose), + * @param tokenizer - The tokenisation strategy: "Word" (default, recommended for prose), * "Character" (fine-grained), or "Line" (similar to git merge) * @returns The reconciled text with automatically repositioned cursor positions - * + * * @example * ```typescript * const original = "Hello world"; * const left = "Hello beautiful world"; // Added "beautiful" * const right = "Hi world"; // Changed "Hello" to "Hi" - * + * * const result = reconcile(original, left, right); * console.log(result.text); // "Hi beautiful world" * ``` @@ -148,27 +148,27 @@ export function reconcile( /** * Merges three versions of text and returns detailed provenance information. - * + * * This function behaves identically to `reconcile()` but additionally provides * detailed historical information about the origin of each text span in the result. * This is valuable for understanding how the merge was performed and which changes * came from which source. - * + * * Note: Computing the history is computationally more expensive than the basic merge. * * @param original - The original/base version of the text that both sides diverged from * @param left - The left version of the text (either string or TextWithCursors with cursor positions) * @param right - The right version of the text (either string or TextWithCursors with cursor positions) - * @param tokenizer - The tokenisation strategy: "Word" (default, recommended for prose), + * @param tokenizer - The tokenisation strategy: "Word" (default, recommended for prose), * "Character" (fine-grained), or "Line" (similar to git merge) * @returns The reconciled text with cursor positions and detailed change history - * + * * @example * ```typescript * const original = "Hello world"; * const left = "Hello beautiful world"; * const right = "Hi world"; - * + * * const result = reconcileWithHistory(original, left, right); * console.log(result.text); // "Hi beautiful world" * console.log(result.history); // Array of SpanWithHistory objects showing change origins @@ -218,7 +218,7 @@ function init() { } function toWasmTextWithCursors(text: string | TextWithCursors): wasmTextWithCursors { - const isInputString = typeof text == 'string'; + const isInputString = typeof text === 'string'; const leftText = isInputString ? text : text.text; const leftCursors = isInputString ? [] : (text.cursors ?? []); diff --git a/src/lib.rs b/src/lib.rs index 07252b5..424615a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,14 @@ //! # Reconcile: 3-way text merging with automatic conflict resolution //! //! A library for merging conflicting text edits without manual intervention. -//! Unlike traditional 3-way merge tools that produce conflict markers, this library -//! automatically resolves conflicts by applying both sets of changes where possible. +//! Unlike traditional 3-way merge tools that produce conflict markers, this +//! library automatically resolves conflicts by applying both sets of changes +//! where possible. //! -//! Based on a combination of Myers' diff algorithm and Operational Transformation -//! principles, it's designed for scenarios where you have a common parent text -//! and two modified versions that need to be intelligently combined. +//! Based on a combination of Myers' diff algorithm and Operational +//! Transformation principles, it's designed for scenarios where you have a +//! common parent text and two modified versions that need to be intelligently +//! combined. //! //! **[Try the interactive demo](https://schmelczer.dev/reconcile)** to see it in action. //! @@ -17,7 +19,7 @@ //! //! // Start with original text //! let parent = "Merging text is hard!"; -//! // Two people edit simultaneously +//! // Two people edit simultaneously //! let left = "Merging text is easy!"; // Changed "hard" to "easy" //! let right = "With reconcile, merging documents is hard!"; // Added prefix and changed word //! @@ -33,9 +35,12 @@ //! //! ### Built-in tokenisers //! -//! - **`BuiltinTokenizer::Word`** (recommended): Splits on word boundaries, preserving word integrity -//! - **`BuiltinTokenizer::Character`**: Character-level merging for fine-grained control -//! - **`BuiltinTokenizer::Line`**: Line-based merging, similar to traditional diff tools +//! - **`BuiltinTokenizer::Word`** (recommended): Splits on word boundaries, +//! preserving word integrity +//! - **`BuiltinTokenizer::Character`**: Character-level merging for +//! fine-grained control +//! - **`BuiltinTokenizer::Line`**: Line-based merging, similar to traditional +//! diff tools //! //! ``` //! use reconcile_text::{reconcile, BuiltinTokenizer}; @@ -81,7 +86,8 @@ //! assert_eq!(result.apply().text(), "Hello beautiful world. This is a great test."); //! ``` //! -//! > **Note**: Setting token joinability to `false` causes insertions to interleave +//! > **Note**: Setting token joinability to `false` causes insertions to +//! > interleave //! > (LRLRLR) rather than group together (LLLRRR), which often produces more //! > natural-looking merged text. //! @@ -124,12 +130,16 @@ //! //! ## Algorithm overview //! -//! 1. **Diff computation**: Myers' algorithm calculates differences between parent↔left and parent↔right -//! 2. **Tokenisation**: Text is split into meaningful units (words, characters, etc.) -//! 3. **Diff optimisation**: Operations are reordered and consolidated for coherent changes +//! 1. **Diff computation**: Myers' algorithm calculates differences between +//! parent↔left and parent↔right +//! 2. **Tokenisation**: Text is split into meaningful units (words, characters, +//! etc.) +//! 3. **Diff optimisation**: Operations are reordered and consolidated for +//! coherent changes //! 4. **Operational Transformation**: Edits are combined using OT principles //! -//! For detailed algorithm explanation, see the [README](README.md#how-it-works). +//! For detailed algorithm explanation, see the +//! [README](README.md#how-it-works). mod operation_transformation; mod raw_operation; diff --git a/src/raw_operation.rs b/src/raw_operation.rs index fb55293..aa3ab8f 100644 --- a/src/raw_operation.rs +++ b/src/raw_operation.rs @@ -5,7 +5,7 @@ use crate::{tokenizer::token::Token, utils::myers_diff::myers_diff}; /// Text editing operation containing the to-be-changed `Tokens`-s. /// /// `RawOperations` can be joined together when the underlying tokens -/// allow for joining subseqeunt operations. +/// allow for joining subsequent operations. #[derive(Debug, Clone, PartialEq)] pub enum RawOperation where diff --git a/src/types/cursor_position.rs b/src/types/cursor_position.rs index bd20065..230794c 100644 --- a/src/types/cursor_position.rs +++ b/src/types/cursor_position.rs @@ -3,8 +3,8 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "wasm")] use wasm_bindgen::prelude::*; -// CursorPosition represents the position of an identifiable cursor in a text -// document based on its (UTF-8) character index. +/// `CursorPosition` represents the position of an identifiable cursor in a text +/// document based on its (UTF-8) character index. #[allow(clippy::unsafe_derive_deserialize)] #[cfg_attr(feature = "wasm", wasm_bindgen)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] diff --git a/src/utils/myers_diff.rs b/src/utils/myers_diff.rs index 705a7de..776e448 100644 --- a/src/utils/myers_diff.rs +++ b/src/utils/myers_diff.rs @@ -189,7 +189,7 @@ where // odd and when there is a reciprocal k line coming from the other // direction. if odd && (k - delta).abs() <= (d - 1) { - // TODO optimize this so we don't have to compare against n + // TODO optimise this so we don't have to compare against n if vf[k] + vb[-(k - delta)] >= n { // Return the snake return Some((x0 + old_range.start, y0 + new_range.start)); @@ -222,7 +222,7 @@ where vb[k] = x; if !odd && (k - delta).abs() <= d { - // TODO optimize this so we don't have to compare against n + // TODO optimise this so we don't have to compare against n if vb[k] + vf[-(k - delta)] >= n { // Return the snake return Some((n - x + old_range.start, m - y + new_range.start)); @@ -230,7 +230,7 @@ where } } - // TODO: Maybe there's an opportunity to optimize and bail early? + // TODO: Maybe there's an opportunity to optimise and bail early? } None