codemirror 0.2.0

A wasm-bingen wrapper for CodeMirror
Documentation
use js_sys::{Array, Object, Reflect};
use wasm_bindgen::prelude::*;

use crate::Position;

#[derive(Debug, Clone, PartialEq)]
pub struct ChangeObject {
    pub from: Position,
    pub to: Position,
    pub text: Vec<String>,
    pub removed: Vec<String>,
    pub origin: Option<String>,
}

impl TryFrom<JsValue> for ChangeObject {
    type Error = &'static str;

    fn try_from(value: JsValue) -> Result<Self, Self::Error> {
        let change_obj: Object = value.into();

        let from =
            Reflect::get(&change_obj, &JsValue::from("from")).map_err(|_| "Missing 'from'")?;
        let from_line = Reflect::get(&from, &JsValue::from("line"))
            .map_err(|_| "Missing 'line' in from")?
            .as_f64()
            .ok_or("Invalid number for line")? as u32;
        let from_column = Reflect::get(&from, &JsValue::from("ch"))
            .map_err(|_| "Missing 'ch' in from")?
            .as_f64()
            .ok_or("Invalid number for character")? as u32;

        let to = Reflect::get(&change_obj, &JsValue::from("to")).map_err(|_| "Missing 'to'")?;
        let to_line = Reflect::get(&to, &JsValue::from("line"))
            .map_err(|_| "Missing 'line' in to")?
            .as_f64()
            .ok_or("Invalid number for line")? as u32;
        let to_column = Reflect::get(&to, &JsValue::from("ch"))
            .map_err(|_| "Missing 'ch' in to")?
            .as_f64()
            .ok_or("Invalid number for character")? as u32;

        let text_array =
            Reflect::get(&change_obj, &JsValue::from("text")).map_err(|_| "Missing 'text'")?;
        let text: Vec<String> = Array::from(&text_array)
            .iter()
            .map(|v| v.as_string().ok_or("Invalid string in text"))
            .collect::<Result<_, _>>()?;

        let removed_array = Reflect::get(&change_obj, &JsValue::from("removed"))
            .map_err(|_| "Missing 'removed'")?;
        let removed: Vec<String> = Array::from(&removed_array)
            .iter()
            .map(|v| v.as_string().ok_or("Invalid string in removed"))
            .collect::<Result<_, _>>()?;

        let origin = Reflect::get(&change_obj, &JsValue::from("origin"))
            .ok()
            .and_then(|val| val.as_string());

        let from = Position::new(from_line.into(), from_column.into());
        let to = Position::new(to_line.into(), to_column.into());

        Ok(ChangeObject {
            from,
            to,
            text,
            removed,
            origin,
        })
    }
}