use std::collections::HashMap;
use wasm_bindgen::prelude::*;
use crate::index::wasm_index::InMemoryIndex;
use crate::SearchOptions;
#[derive(serde::Serialize)]
struct WasmMatch {
path: String,
line_number: u32,
line_content: String,
submatch_start: usize,
submatch_end: usize,
}
#[wasm_bindgen]
pub struct WasmIndex {
inner: InMemoryIndex,
}
#[wasm_bindgen]
impl WasmIndex {
#[wasm_bindgen(constructor)]
pub fn new(files: JsValue) -> Result<WasmIndex, JsValue> {
let entries = js_sys::Object::entries(files.unchecked_ref());
let mut map: HashMap<String, Vec<u8>> = HashMap::new();
for entry in entries.iter() {
let pair = js_sys::Array::from(&entry);
let key = pair
.get(0)
.as_string()
.ok_or_else(|| JsValue::from_str("file path must be a string"))?;
let val = pair.get(1);
let bytes = js_sys::Uint8Array::new(&val).to_vec();
map.insert(key, bytes);
}
let inner = InMemoryIndex::build(map)
.map_err(|e| JsValue::from_str(&e.to_string()))?;
Ok(WasmIndex { inner })
}
pub fn search(&self, pattern: &str) -> Result<JsValue, JsValue> {
let opts = SearchOptions::default();
let matches = self
.inner
.search(pattern, &opts)
.map_err(|e| JsValue::from_str(&e.to_string()))?;
let wasm_matches: Vec<WasmMatch> = matches
.iter()
.map(|m| WasmMatch {
path: m.path.to_string_lossy().into_owned(),
line_number: m.line_number,
line_content: String::from_utf8_lossy(&m.line_content).into_owned(),
submatch_start: m.submatch_start,
submatch_end: m.submatch_end,
})
.collect();
serde_wasm_bindgen::to_value(&wasm_matches)
.map_err(|e| JsValue::from_str(&e.to_string()))
}
}