Skip to main content

repoask_wasm/
lib.rs

1//! repoask WASM bindings for browser usage.
2//!
3//! Provides the same search functionality as the CLI, but operates on
4//! in-memory file contents instead of filesystem paths.
5
6use wasm_bindgen::prelude::*;
7
8use repoask_core::index::InvertedIndex;
9use repoask_core::types::IndexDocument;
10
11/// A search index that can be built from file contents and queried.
12///
13/// Usage from JavaScript:
14/// ```js
15/// const index = new RepoIndex();
16/// index.addFile("src/auth.ts", sourceCode);
17/// index.addFile("README.md", readmeContent);
18/// index.build();
19/// const results = index.search("authentication", 10);
20/// ```
21#[wasm_bindgen]
22pub struct RepoIndex {
23    documents: Vec<IndexDocument>,
24    index: Option<InvertedIndex>,
25}
26
27#[wasm_bindgen]
28impl RepoIndex {
29    /// Create a new empty index.
30    #[wasm_bindgen(constructor)]
31    pub fn new() -> Self {
32        Self {
33            documents: Vec::new(),
34            index: None,
35        }
36    }
37
38    /// Add a file to be indexed.
39    ///
40    /// Call this for each file before calling `build()`.
41    /// The filepath determines the parser used (e.g. `.ts` → oxc, `.md` → markdown).
42    #[wasm_bindgen(js_name = "addFile")]
43    pub fn add_file(&mut self, filepath: &str, content: &str) {
44        let docs = repoask_parser::parse_file_lenient(filepath, content);
45        self.documents.extend(docs);
46    }
47
48    /// Build the search index from all added files.
49    ///
50    /// Must be called after all `addFile()` calls and before `search()`.
51    pub fn build(&mut self) {
52        let docs = std::mem::take(&mut self.documents);
53        self.index = Some(InvertedIndex::build(docs));
54    }
55
56    /// Search the index and return results as a JSON string.
57    ///
58    /// Returns a JSON array of search results.
59    /// Each result is `{"Code": {...}}`, `{"Doc": {...}}`, or `{"Example": {...}}`.
60    pub fn search(&self, query: &str, limit: usize) -> Result<String, JsError> {
61        let index = self
62            .index
63            .as_ref()
64            .ok_or_else(|| JsError::new("index not built: call build() first"))?;
65
66        let results = index.search(query, limit);
67        serde_json::to_string(&results).map_err(|e| JsError::new(&e.to_string()))
68    }
69
70    /// Return the number of documents in the index.
71    #[wasm_bindgen(js_name = "docCount")]
72    pub fn doc_count(&self) -> usize {
73        match &self.index {
74            Some(idx) => idx.doc_count(),
75            None => self.documents.len(),
76        }
77    }
78}
79
80impl Default for RepoIndex {
81    fn default() -> Self {
82        Self::new()
83    }
84}