use forge_core::util::to_camel_case;
use crate::Error;
use crate::binding::BindingSet;
use crate::emit::{self, Position};
use super::api::ts_args_type;
pub fn generate(bindings: &BindingSet) -> Result<String, Error> {
if bindings.queries.is_empty() {
return Ok(String::new());
}
let mut output = String::from("// Auto-generated by FORGE - DO NOT EDIT\n\n");
let store_imports: Vec<String> = bindings
.queries
.iter()
.map(|b| format!("{}Store$", to_camel_case(&b.name)))
.collect();
output.push_str(&format!(
"import {{ {} }} from \"./api\";\n",
store_imports.join(", ")
));
output.push_str("import { toReactive, type ReactiveQuery } from \"./runes.svelte\";\n");
let mut type_imports = Vec::new();
for b in &bindings.queries {
emit::collect_type_imports(&b.return_type, &mut type_imports);
for arg in &b.args {
emit::collect_type_imports(&arg.rust_type, &mut type_imports);
}
}
type_imports.sort();
type_imports.dedup();
if !type_imports.is_empty() {
output.push_str(&format!(
"import type {{ {} }} from \"./types\";\n",
type_imports.join(", ")
));
}
for b in &bindings.queries {
let ts_name = to_camel_case(&b.name);
let result_type = emit::ts_type(&b.return_type, Position::Return);
if b.has_args() {
let args_type = ts_args_type(b);
output.push_str(&format!(
"export const {}$ = (args: {}): ReactiveQuery<{}> =>\n toReactive({}Store$(args));\n",
ts_name, args_type, result_type, ts_name
));
} else {
output.push_str(&format!(
"export const {}$ = (): ReactiveQuery<{}> =>\n toReactive({}Store$());\n",
ts_name, result_type, ts_name
));
}
}
Ok(output)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::binding::BindingSet;
use forge_core::schema::{FunctionDef, RustType, SchemaRegistry};
#[test]
fn test_generate_reactive_empty() {
let registry = SchemaRegistry::new();
let bindings = BindingSet::from_registry(®istry);
let content = generate(&bindings).expect("empty reactive bindings should generate");
assert!(content.is_empty());
}
#[test]
fn test_generate_reactive_with_query() {
let registry = SchemaRegistry::new();
let func = FunctionDef::query(
"list_users",
RustType::Vec(Box::new(RustType::Custom("User".into()))),
);
registry.register_function(func);
let bindings = BindingSet::from_registry(®istry);
let content = generate(&bindings).expect("reactive query bindings should generate");
assert!(content.contains("listUsers$"));
assert!(content.contains("ReactiveQuery<User[]>"));
assert!(content.contains("toReactive(listUsersStore$())"));
}
}