use core::str;
use wasm_bindgen::prelude::*;
use crate::{BuiltinTokenizer, CursorPosition, EditedText, SpanWithHistory, TextWithCursors};
#[wasm_bindgen(js_name = reconcile)]
#[must_use]
pub fn reconcile(
parent: &str,
left: &TextWithCursors,
right: &TextWithCursors,
tokenizer: BuiltinTokenizer,
) -> TextWithCursors {
set_panic_hook();
crate::reconcile(parent, left, right, &*tokenizer).apply()
}
#[wasm_bindgen(js_name = reconcileWithHistory)]
#[must_use]
pub fn reconcile_with_history(
parent: &str,
left: &TextWithCursors,
right: &TextWithCursors,
tokenizer: BuiltinTokenizer,
) -> TextWithCursorsAndHistory {
set_panic_hook();
let reconciled = crate::reconcile(parent, left, right, &*tokenizer);
let (text_with_cursors, history) = reconciled.apply_with_all();
TextWithCursorsAndHistory {
text_with_cursors,
history,
}
}
#[wasm_bindgen(js_name = genericReconcile)]
#[must_use]
pub fn generic_reconcile(
parent: &[u8],
left: &[u8],
right: &[u8],
tokenizer: BuiltinTokenizer,
) -> Vec<u8> {
set_panic_hook();
if let (Some(parent), Some(left), Some(right)) = (
string_or_nothing(parent),
string_or_nothing(left),
string_or_nothing(right),
) {
crate::reconcile(&parent, &left.into(), &right.into(), &*tokenizer)
.apply()
.text()
.into_bytes()
} else {
right.to_vec()
}
}
#[wasm_bindgen(js_name = diff)]
pub fn diff(
parent: &str,
changed: &TextWithCursors,
tokenizer: BuiltinTokenizer,
) -> Result<Vec<JsValue>, JsValue> {
set_panic_hook();
let edited_text = EditedText::from_strings_with_tokenizer(parent, changed, &*tokenizer);
edited_text
.to_diff()
.map(|diff| diff.into_iter().map(std::convert::Into::into).collect())
.map_err(|e| JsValue::from_str(&e.to_string()))
}
#[wasm_bindgen(js_name = undiff)]
pub fn undiff(
parent: &str,
diff: Vec<JsValue>,
tokenizer: BuiltinTokenizer,
) -> Result<String, JsValue> {
set_panic_hook();
let parsed_diff: Vec<_> = diff
.into_iter()
.map(std::convert::TryInto::try_into)
.collect::<Result<_, _>>()
.map_err(|e: crate::types::number_or_text::DeserialisationError| -> JsValue { e.into() })?;
EditedText::from_diff(parent, parsed_diff, &*tokenizer)
.map(|edited_text| edited_text.apply().text())
.map_err(|e| JsValue::from_str(&e.to_string()))
}
fn set_panic_hook() {
#[cfg(feature = "console_error_panic_hook")]
console_error_panic_hook::set_once();
}
#[wasm_bindgen]
#[derive(Debug, Clone, PartialEq, Default)]
pub struct TextWithCursorsAndHistory {
text_with_cursors: TextWithCursors,
history: Vec<SpanWithHistory>,
}
#[wasm_bindgen]
impl TextWithCursorsAndHistory {
#[must_use]
pub fn text(&self) -> String {
self.text_with_cursors.text()
}
#[must_use]
pub fn cursors(&self) -> Vec<CursorPosition> {
self.text_with_cursors.cursors()
}
#[must_use]
pub fn history(&self) -> Vec<SpanWithHistory> {
self.history.clone()
}
}
#[must_use]
fn string_or_nothing(data: &[u8]) -> Option<String> {
if data.contains(&0) {
return None;
}
std::str::from_utf8(data)
.map(std::borrow::ToOwned::to_owned)
.ok()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_string_or_nothing() {
assert_eq!(string_or_nothing(&[0, 159, 146, 150]), None);
assert_eq!(string_or_nothing(&[0, 12]), None);
assert_eq!(string_or_nothing(b"hello"), Some("hello".into()));
}
}