extern crate cfg_if; extern crate js_sys; extern crate jsonpath_lib as jsonpath; extern crate serde; extern crate serde_json; extern crate wasm_bindgen; extern crate web_sys; use std::ops::Deref; use std::result; use std::result::Result; use cfg_if::cfg_if; use jsonpath::filter::value_filter::JsonValueFilter; use jsonpath::parser::parser::{Node, NodeVisitor, Parser}; use jsonpath::ref_value::model::{RefValue, RefValueWrapper}; use jsonpath::Selector as _Selector; use serde_json::Value; use wasm_bindgen::*; use wasm_bindgen::prelude::*; use web_sys::console; cfg_if! { if #[cfg(feature = "wee_alloc")] { extern crate wee_alloc; #[global_allocator] static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; } } cfg_if! { if #[cfg(feature = "console_error_panic_hook")] { extern crate console_error_panic_hook; pub use self::console_error_panic_hook::set_once as set_panic_hook; } else { #[inline] pub fn set_panic_hook() {} } } fn filter_ref_value(json: RefValueWrapper, node: Node) -> JsValue { let mut jf = JsonValueFilter::new(json); jf.visit(node); let taken = &jf.clone_value(); match JsValue::from_serde(taken.deref()) { Ok(js_value) => js_value, Err(e) => JsValue::from_str(&format!("Json deserialize error: {:?}", e)) } } fn into_serde_json(js_value: &JsValue) -> Result where D: for<'a> serde::de::Deserialize<'a> { if js_value.is_string() { match serde_json::from_str(js_value.as_string().unwrap().as_str()) { Ok(json) => Ok(json), Err(e) => Err(e.to_string()) } } else { match js_value.into_serde() { Ok(json) => Ok(json), Err(e) => Err(e.to_string()) } } } fn into_ref_value(js_value: &JsValue, node: Node) -> JsValue { let result: result::Result = into_serde_json::(js_value); match result { Ok(json) => filter_ref_value(json.into(), node), Err(e) => JsValue::from_str(&format!("Json serialize error: {}", e)) } } fn get_ref_value(js_value: JsValue, node: Node) -> JsValue { into_ref_value(&js_value, node) } #[wasm_bindgen] pub fn compile(path: &str) -> JsValue { let mut parser = Parser::new(path); let node = parser.compile(); let cb = Closure::wrap(Box::new(move |js_value: JsValue| { match &node { Ok(node) => get_ref_value(js_value, node.clone()), Err(e) => JsValue::from_str(&format!("Json path error: {:?}", e)) } }) as Box JsValue>); let ret = cb.as_ref().clone(); cb.forget(); ret } #[wasm_bindgen] pub fn selector(js_value: JsValue) -> JsValue { let json: RefValueWrapper = match into_serde_json::(&js_value) { Ok(json) => json.into(), Err(e) => return JsValue::from_str(e.as_str()) }; let cb = Closure::wrap(Box::new(move |path: String| { let mut parser = Parser::new(path.as_str()); match parser.compile() { Ok(node) => filter_ref_value(json.clone(), node), Err(e) => return JsValue::from_str(e.as_str()) } }) as Box JsValue>); let ret = cb.as_ref().clone(); cb.forget(); ret } #[wasm_bindgen] pub fn select(js_value: JsValue, path: &str) -> JsValue { let mut parser = Parser::new(path); match parser.compile() { Ok(node) => get_ref_value(js_value, node), Err(e) => return JsValue::from_str(e.as_str()) } } /// /// `wasm_bindgen` 제약으로 builder-pattern을 구사 할 수 없다. /// #[wasm_bindgen] pub struct Selector { selector: _Selector } #[wasm_bindgen] impl Selector { #[wasm_bindgen(constructor)] pub fn new() -> Self { Selector { selector: _Selector::new() } } #[wasm_bindgen(catch)] pub fn path(&mut self, path: &str) -> result::Result<(), JsValue> { let _ = self.selector.path(path)?; Ok(()) } #[wasm_bindgen(catch)] pub fn value(&mut self, value: JsValue) -> result::Result<(), JsValue> { let ref ref_value = into_serde_json(&value)?; let _ = self.selector.value(ref_value)?; Ok(()) } #[wasm_bindgen(catch, js_name = selectToStr)] pub fn select_to_str(&mut self) -> result::Result { self.select_as_str() } #[wasm_bindgen(catch, js_name = selectAsStr)] pub fn select_as_str(&mut self) -> result::Result { let json_str = self.selector.select_as_str()?; Ok(JsValue::from_str(&json_str)) } #[wasm_bindgen(catch, js_name = selectTo)] pub fn select_to(&mut self) -> result::Result { self.select_as() } #[wasm_bindgen(catch, js_name = selectAs)] pub fn select_as(&mut self) -> result::Result { let ref_value = self.selector.select_as::() .map_err(|e| JsValue::from_str(&e))?; Ok(JsValue::from_serde(&ref_value) .map_err(|e| JsValue::from_str(&e.to_string()))?) } #[wasm_bindgen(catch)] pub fn map(&mut self, func: JsValue) -> result::Result<(), JsValue> { if !func.is_function() { return Err(JsValue::from_str("Not a function argument")); } let cb: &js_sys::Function = JsCast::unchecked_ref(func.as_ref()); self.selector.map(|v| { let str_value = match JsValue::from_serde(&v) { Ok(str_value) => str_value, Err(e) => return { console::error_1(&JsValue::from_str(&e.to_string())); None } }; match cb.call1(&func, &str_value) { Ok(ret) => { match into_serde_json::(&ret) { Ok(value) => Some(value), Err(e) => { console::error_1(&JsValue::from_str(&e.to_string())); None } } } Err(e) => { console::error_1(&e); None } } }).map_err(|e| JsValue::from_str(&e))?; Ok(()) } #[wasm_bindgen(catch)] pub fn get(&mut self) -> result::Result { let v = self.selector.get().map_err(|e| JsValue::from_str(&e.to_string()))?; JsValue::from_serde(&v).map_err(|e| JsValue::from_str(&e.to_string())) } }