1 extern crate cfg_if;
2 extern crate js_sys;
3 extern crate jsonpath_lib as jsonpath;
4 extern crate serde_json;
5 extern crate wasm_bindgen;
6 
7 use cfg_if::cfg_if;
8 use jsonpath::Selector as _Selector;
9 use jsonpath::SelectorMut as _SelectorMut;
10 use jsonpath::{JsonPathError, Parser};
11 use serde_json::Value;
12 use wasm_bindgen::prelude::*;
13 
14 cfg_if! {
15     if #[cfg(feature = "wee_alloc")] {
16         extern crate wee_alloc;
17         #[global_allocator]
18         static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
19     }
20 }
21 
22 cfg_if! {
23     if #[cfg(feature = "console_error_panic_hook")] {
24         extern crate console_error_panic_hook;
25         pub use self::console_error_panic_hook::set_once as set_panic_hook;
26     } else {
27         #[inline]
28         pub fn set_panic_hook() {}
29     }
30 }
31 
32 #[wasm_bindgen]
33 extern "C" {
34     #[wasm_bindgen(js_namespace = console)]
error(s: &str)35     fn error(s: &str);
36 }
37 
38 macro_rules! console_error {
39     ($($t:tt)*) => (error(&format_args!($($t)*).to_string()))
40 }
41 
into_serde_json<D>(js_value: &JsValue) -> Result<D, String> where D: for<'a> serde::de::Deserialize<'a>,42 fn into_serde_json<D>(js_value: &JsValue) -> Result<D, String>
43 where
44     D: for<'a> serde::de::Deserialize<'a>,
45 {
46     if js_value.is_string() {
47         match serde_json::from_str(js_value.as_string().unwrap().as_str()) {
48             Ok(json) => Ok(json),
49             Err(e) => Err(e.to_string()),
50         }
51     } else {
52         match js_value.into_serde() {
53             Ok(json) => Ok(json),
54             Err(e) => Err(e.to_string()),
55         }
56     }
57 }
58 
59 #[allow(clippy::unnecessary_wraps)]
replace_fun(v: Value, fun: &js_sys::Function) -> Option<Value>60 fn replace_fun(v: Value, fun: &js_sys::Function) -> Option<Value> {
61     match JsValue::from_serde(&v) {
62         Ok(js_v) => match fun.call1(&JsValue::NULL, &js_v) {
63             Ok(result) => match into_serde_json(&result) {
64                 Ok(json) => Some(json),
65                 Err(e) => {
66                     console_error!("replace_with - closure returned a invalid JSON: {:?}", e);
67                     Some(Value::Null)
68                 }
69             },
70             Err(e) => {
71                 console_error!("replace_with - fail to call closure: {:?}", e);
72                 Some(Value::Null)
73             }
74         },
75         Err(e) => {
76             console_error!("replace_with - invalid JSON object: {:?}", e);
77             Some(Value::Null)
78         }
79     }
80 }
81 
82 #[wasm_bindgen]
compile(path: &str) -> JsValue83 pub fn compile(path: &str) -> JsValue {
84     let node = Parser::compile(path);
85 
86     if let Err(e) = &node {
87         return JsValue::from_str(&format!("{:?}", JsonPathError::Path(e.clone())));
88     };
89 
90     let cb = Closure::wrap(Box::new(move |js_value: JsValue| {
91         let json = match into_serde_json(&js_value) {
92             Ok(json) => json,
93             Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e))),
94         };
95 
96         let mut selector = _Selector::new();
97 
98         match &node {
99             Ok(node) => selector.compiled_path(node),
100             Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Path(e.clone()))),
101         };
102 
103         match selector.value(&json).select() {
104             Ok(ret) => match JsValue::from_serde(&ret) {
105                 Ok(ret) => ret,
106                 Err(e) => JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string()))),
107             },
108             Err(e) => JsValue::from_str(&format!("{:?}", e)),
109         }
110     }) as Box<dyn Fn(JsValue) -> JsValue>);
111 
112     let ret = cb.as_ref().clone();
113     cb.forget();
114     ret
115 }
116 
117 #[wasm_bindgen]
selector(js_value: JsValue) -> JsValue118 pub fn selector(js_value: JsValue) -> JsValue {
119     let json: Value = match JsValue::into_serde(&js_value) {
120         Ok(json) => json,
121         Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string()))),
122     };
123 
124     let cb = Closure::wrap(
125         Box::new(move |path: String| match Parser::compile(path.as_str()) {
126             Ok(node) => {
127                 let mut selector = _Selector::new();
128                 let _ = selector.compiled_path(&node);
129                 match selector.value(&json).select() {
130                     Ok(ret) => match JsValue::from_serde(&ret) {
131                         Ok(ret) => ret,
132                         Err(e) => {
133                             JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string())))
134                         }
135                     },
136                     Err(e) => JsValue::from_str(&format!("{:?}", e)),
137                 }
138             }
139             Err(e) => JsValue::from_str(&format!("{:?}", JsonPathError::Path(e))),
140         }) as Box<dyn Fn(String) -> JsValue>,
141     );
142 
143     let ret = cb.as_ref().clone();
144     cb.forget();
145     ret
146 }
147 
148 #[wasm_bindgen]
select(js_value: JsValue, path: &str) -> JsValue149 pub fn select(js_value: JsValue, path: &str) -> JsValue {
150     let json = match into_serde_json(&js_value) {
151         Ok(json) => json,
152         Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e))),
153     };
154 
155     match jsonpath::select(&json, path) {
156         Ok(ret) => match JsValue::from_serde(&ret) {
157             Ok(ret) => ret,
158             Err(e) => JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string()))),
159         },
160         Err(e) => JsValue::from_str(&format!("{:?}", e)),
161     }
162 }
163 
164 #[wasm_bindgen(catch, js_name = "deleteValue")]
delete(js_value: JsValue, path: &str) -> JsValue165 pub fn delete(js_value: JsValue, path: &str) -> JsValue {
166     let json = match into_serde_json(&js_value) {
167         Ok(json) => json,
168         Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e))),
169     };
170 
171     match jsonpath::delete(json, path) {
172         Ok(ret) => match JsValue::from_serde(&ret) {
173             Ok(ret) => ret,
174             Err(e) => JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string()))),
175         },
176         Err(e) => JsValue::from_str(&format!("{:?}", e)),
177     }
178 }
179 
180 #[wasm_bindgen(catch, js_name = "replaceWith")]
replace_with(js_value: JsValue, path: &str, fun: js_sys::Function) -> JsValue181 pub fn replace_with(js_value: JsValue, path: &str, fun: js_sys::Function) -> JsValue {
182     let json = match into_serde_json(&js_value) {
183         Ok(json) => json,
184         Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e))),
185     };
186 
187     match jsonpath::replace_with(json, path, &mut |v| replace_fun(v, &fun)) {
188         Ok(ret) => match JsValue::from_serde(&ret) {
189             Ok(ret) => ret,
190             Err(e) => JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string()))),
191         },
192         Err(e) => JsValue::from_str(&format!("{:?}", e)),
193     }
194 }
195 
196 ///
197 /// `wasm_bindgen` 제약으로 builder-pattern을 구사 할 수 없다.
198 /// lifetime 제약으로 Selector를 사용 할 수 없다.
199 ///
200 #[wasm_bindgen]
201 #[derive(Default)]
202 pub struct Selector {
203     path: Option<String>,
204     value: Option<Value>,
205 }
206 
207 #[wasm_bindgen]
208 impl Selector {
209     #[wasm_bindgen(constructor)]
new() -> Self210     pub fn new() -> Self {
211         Selector::default()
212     }
213 
214     #[wasm_bindgen(catch)]
path(&mut self, path: &str) -> Result<(), JsValue>215     pub fn path(&mut self, path: &str) -> Result<(), JsValue> {
216         self.path = Some(path.to_string());
217         Ok(())
218     }
219 
220     #[wasm_bindgen(catch)]
value(&mut self, value: JsValue) -> Result<(), JsValue>221     pub fn value(&mut self, value: JsValue) -> Result<(), JsValue> {
222         let json = into_serde_json(&value)
223             .map_err(|e| JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e))))?;
224         self.value = Some(json);
225         Ok(())
226     }
227 
228     #[wasm_bindgen(catch, js_name = select)]
select(&mut self) -> Result<JsValue, JsValue>229     pub fn select(&mut self) -> Result<JsValue, JsValue> {
230         let mut selector = _Selector::new();
231 
232         if let Some(path) = &self.path {
233             let _ = selector
234                 .str_path(&path)
235                 .map_err(|e| JsValue::from_str(&format!("{:?}", e)))?;
236         } else {
237             return Err(JsValue::from_str(&format!(
238                 "{:?}",
239                 JsonPathError::EmptyPath
240             )));
241         }
242 
243         if let Some(value) = &self.value {
244             let _ = selector.value(value);
245         } else {
246             return Err(JsValue::from_str(&format!(
247                 "{:?}",
248                 JsonPathError::EmptyValue
249             )));
250         }
251 
252         match selector.select() {
253             Ok(ret) => match JsValue::from_serde(&ret) {
254                 Ok(ret) => Ok(ret),
255                 Err(e) => Err(JsValue::from_str(&format!(
256                     "{:?}",
257                     JsonPathError::Serde(e.to_string())
258                 ))),
259             },
260             Err(e) => Err(JsValue::from_str(&format!("{:?}", e))),
261         }
262     }
263 }
264 
265 ///
266 /// `wasm_bindgen` 제약으로 builder-pattern을 구사 할 수 없다.
267 ///
268 #[wasm_bindgen]
269 #[derive(Default)]
270 pub struct SelectorMut {
271     path: Option<String>,
272     value: Option<Value>,
273 }
274 
275 #[wasm_bindgen]
276 impl SelectorMut {
277     #[wasm_bindgen(constructor)]
new() -> Self278     pub fn new() -> Self {
279         SelectorMut::default()
280     }
281 
282     #[wasm_bindgen(catch)]
path(&mut self, path: &str) -> Result<(), JsValue>283     pub fn path(&mut self, path: &str) -> Result<(), JsValue> {
284         self.path = Some(path.to_string());
285         Ok(())
286     }
287 
288     #[wasm_bindgen(catch)]
value(&mut self, value: JsValue) -> Result<(), JsValue>289     pub fn value(&mut self, value: JsValue) -> Result<(), JsValue> {
290         let json = into_serde_json(&value)
291             .map_err(|e| JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e))))?;
292         self.value = Some(json);
293         Ok(())
294     }
295 
296     #[wasm_bindgen(catch, js_name = "deleteValue")]
delete(&mut self) -> Result<(), JsValue>297     pub fn delete(&mut self) -> Result<(), JsValue> {
298         let mut selector = _SelectorMut::new();
299 
300         if let Some(path) = &self.path {
301             let _ = selector.str_path(path);
302         } else {
303             return Err(JsValue::from_str(&format!(
304                 "{:?}",
305                 JsonPathError::EmptyPath
306             )));
307         };
308 
309         if let Some(value) = self.value.take() {
310             selector.value(value);
311         } else {
312             return Err(JsValue::from_str(&format!(
313                 "{:?}",
314                 JsonPathError::EmptyValue
315             )));
316         };
317 
318         match selector.delete() {
319             Err(e) => Err(JsValue::from_str(&format!("{:?}", e))),
320             _ => {
321                 self.value = selector.take();
322                 Ok(())
323             }
324         }
325     }
326 
327     #[wasm_bindgen(catch, js_name = replaceWith)]
replace_with(&mut self, fun: js_sys::Function) -> Result<(), JsValue>328     pub fn replace_with(&mut self, fun: js_sys::Function) -> Result<(), JsValue> {
329         let mut selector = _SelectorMut::new();
330 
331         if let Some(path) = &self.path {
332             let _ = selector.str_path(path);
333         } else {
334             return Err(JsValue::from_str(&format!(
335                 "{:?}",
336                 JsonPathError::EmptyPath
337             )));
338         };
339 
340         if let Some(value) = self.value.take() {
341             selector.value(value);
342         } else {
343             return Err(JsValue::from_str(&format!(
344                 "{:?}",
345                 JsonPathError::EmptyValue
346             )));
347         };
348 
349         match selector.replace_with(&mut |v| replace_fun(v, &fun)) {
350             Err(e) => Err(JsValue::from_str(&format!("{:?}", e))),
351             _ => {
352                 self.value = selector.take();
353                 Ok(())
354             }
355         }
356     }
357 
358     #[wasm_bindgen(catch)]
take(&mut self) -> Result<JsValue, JsValue>359     pub fn take(&mut self) -> Result<JsValue, JsValue> {
360         match self.value.take() {
361             Some(ret) => match JsValue::from_serde(&ret) {
362                 Ok(ret) => Ok(ret),
363                 Err(e) => Err(JsValue::from_str(&format!("{:?}", e))),
364             },
365             None => Err(JsValue::from_str(&format!(
366                 "{:?}",
367                 JsonPathError::EmptyValue
368             ))),
369         }
370     }
371 }
372