Remove merge from sync-lib

This commit is contained in:
Andras Schmelczer 2025-07-12 11:10:26 +01:00
parent d9d14e03e9
commit 4543180f7b
No known key found for this signature in database
GPG key ID: FC8F2C3D3D1A718C
8 changed files with 32 additions and 302 deletions

View file

@ -11,7 +11,6 @@ crate-type = ["cdylib", "rlib"]
[dependencies]
base64 = "0.22.1"
reconcile = { path = "../reconcile" }
wasm-bindgen = "0.2.99"
thiserror = { workspace = true }

View file

@ -1,88 +0,0 @@
use wasm_bindgen::prelude::*;
/// Wrapper type to expose `TextWithCursors` to JS.
#[wasm_bindgen]
#[derive(Debug, Clone, PartialEq)]
pub struct TextWithCursors {
text: String,
cursors: Vec<CursorPosition>,
}
#[wasm_bindgen]
impl TextWithCursors {
#[wasm_bindgen(constructor)]
#[must_use]
pub fn new(text: String, cursors: Vec<CursorPosition>) -> Self { Self { text, cursors } }
#[must_use]
pub fn text(&self) -> String { self.text.clone() }
#[must_use]
pub fn cursors(&self) -> Vec<CursorPosition> { self.cursors.clone() }
}
impl From<TextWithCursors> for reconcile::TextWithCursors<'_> {
fn from(owned: TextWithCursors) -> Self {
reconcile::TextWithCursors::new_owned(
owned.text.to_string(),
owned
.cursors
.into_iter()
.map(std::convert::Into::into)
.collect(),
)
}
}
impl From<reconcile::TextWithCursors<'_>> for TextWithCursors {
fn from(text_with_cursors: reconcile::TextWithCursors<'_>) -> Self {
TextWithCursors {
text: text_with_cursors.text.into_owned(),
cursors: text_with_cursors
.cursors
.into_iter()
.map(std::convert::Into::into)
.collect(),
}
}
}
/// Wrapper type to expose `CursorPosition` to JS.
#[wasm_bindgen]
#[derive(Debug, Clone, PartialEq)]
pub struct CursorPosition {
id: usize,
char_index: usize,
}
#[wasm_bindgen]
impl CursorPosition {
#[wasm_bindgen(constructor)]
#[must_use]
pub fn new(id: usize, char_index: usize) -> Self { Self { id, char_index } }
#[must_use]
pub fn id(&self) -> usize { self.id }
#[wasm_bindgen(js_name = characterPosition)]
#[must_use]
pub fn char_index(&self) -> usize { self.char_index }
}
impl From<CursorPosition> for reconcile::CursorPosition {
fn from(owned: CursorPosition) -> Self {
reconcile::CursorPosition {
id: owned.id,
char_index: owned.char_index,
}
}
}
impl From<reconcile::CursorPosition> for CursorPosition {
fn from(cursor: reconcile::CursorPosition) -> Self {
CursorPosition {
id: cursor.id,
char_index: cursor.char_index,
}
}
}

View file

@ -1,6 +1,6 @@
//! This crate provides utilities for easily communicating between backend &
//! frontend and ensuring the same logic for encoding and decoding binary data,
//! and 3-way-merging documents in Rust and JavaScript.
//! and filtering files.
//!
//! The crate is designed to be used as a Rust library and as a
//! TypeScript/JavaScript package through WebAssembly (WASM).
@ -12,11 +12,9 @@
use core::str;
use base64::{Engine as _, engine::general_purpose::STANDARD};
use cursor::TextWithCursors;
use errors::SyncLibError;
use wasm_bindgen::prelude::*;
pub mod cursor;
pub mod errors;
/// Encode binary data for easy transport over HTTP. Inverse of
@ -62,78 +60,6 @@ pub fn base64_to_bytes(input: &str) -> Result<Vec<u8>, SyncLibError> {
STANDARD.decode(input).map_err(SyncLibError::from)
}
/// Merge two documents with a common parent. Relies on `reconcile::reconcile`
/// for texts and returns the right document as-is if either of the updated
/// documents is binary.
///
/// # Arguments
///
/// - `parent`: The common parent document.
/// - `left`: The left document updated by one user.
/// - `right`: The right document updated by another user.
///
/// # Returns
///
/// The merged document.
///
/// # Panics
///
/// If any of the input documents are not valid UTF-8 strings.
#[wasm_bindgen]
#[must_use]
pub fn merge(parent: &[u8], left: &[u8], right: &[u8]) -> Vec<u8> {
set_panic_hook();
if is_binary(parent) || is_binary(left) || is_binary(right) {
right.to_vec()
} else {
reconcile::reconcile(
str::from_utf8(parent).expect("parent must be valid UTF-8 because it's not binary"),
str::from_utf8(left).expect("left must be valid UTF-8 because it's not binary"),
str::from_utf8(right).expect("right must be valid UTF-8 because it's not binary"),
)
.into_bytes()
}
}
/// WASM wrapper around `reconcile::reconcile` for merging text.
#[wasm_bindgen(js_name = mergeText)]
#[must_use]
pub fn merge_text(parent: &str, left: &str, right: &str) -> String {
set_panic_hook();
reconcile::reconcile(parent, left, right)
}
/// WASM wrapper around `reconcile::reconcile_with_cursors` for merging text.
#[wasm_bindgen(js_name = mergeTextWithCursors)]
#[must_use]
pub fn merge_text_with_cursors(
parent: &str,
left: TextWithCursors,
right: TextWithCursors,
) -> TextWithCursors {
set_panic_hook();
reconcile::reconcile_with_cursors(parent, left.into(), right.into()).into()
}
/// Heuristically determine if the given data is a binary or a text file's
/// content.
#[wasm_bindgen(js_name = isBinary)]
#[must_use]
pub fn is_binary(data: &[u8]) -> bool {
set_panic_hook();
if data.contains(&0) {
// Even though the NUL character is valid in UTF-8, it's highly suspicious in
// human-readable text.
return true;
}
std::str::from_utf8(data).is_err()
}
/// We don't want to support merging structured data like JSON, YAML, etc.
#[wasm_bindgen(js_name = isFileTypeMergable)]
#[must_use]

View file

@ -1,8 +1,5 @@
use insta::assert_debug_snapshot;
use sync_lib::{
cursor::{CursorPosition, TextWithCursors},
*,
};
use sync_lib::*;
use wasm_bindgen_test::*;
#[wasm_bindgen_test(unsupported = test)]
@ -25,66 +22,6 @@ fn test_base64_to_bytes_error() {
assert_debug_snapshot!(base64_to_bytes(input));
}
#[wasm_bindgen_test(unsupported = test)]
fn test_merge() {
let left = b"hello ";
let right = b"world";
let result = merge(b"", left, right);
assert_eq!(result, b"hello world");
let left = b"\0binary";
let right = b"other";
let result = merge(b"", left, right);
assert_eq!(result, right);
}
#[wasm_bindgen_test(unsupported = test)]
fn test_merge_text() {
let left = "hello ";
let right = "world";
let result = merge_text("", left, right);
assert_eq!(result, "hello world");
}
#[wasm_bindgen_test(unsupported = test)]
fn test_merge_text_with_cursors() {
let result = merge_text_with_cursors(
"hi",
TextWithCursors::new("hi world".to_owned(), vec![]),
TextWithCursors::new(
"hi".to_owned(),
vec![CursorPosition::new(0, 1), CursorPosition::new(1, 2)],
),
);
assert_eq!(
result,
TextWithCursors::new(
"hi world".to_owned(),
vec![CursorPosition::new(0, 1), CursorPosition::new(1, 2)]
),
);
}
#[wasm_bindgen_test(unsupported = test)]
fn merge_binary() {
let left = [0, 1, 2];
let right = [3, 4, 5];
assert_eq!(merge(b"", &left, &right), right);
}
#[wasm_bindgen_test(unsupported = test)]
fn test_is_binary() {
assert!(is_binary(&[0, 159, 146, 150]));
assert!(is_binary(&[0, 12]));
assert!(!is_binary(b"hello"));
}
#[wasm_bindgen_test(unsupported = test)]
fn test_is_binary_empty() {
assert!(!is_binary(b""));
}
#[wasm_bindgen_test(unsupported = test)]
fn test_is_file_type_mergable() {
assert!(is_file_type_mergable(".md"));