use std::{fmt::Write as _, path::Path};
use super::{
CodegenError, contract_ir, load_descriptor, pascal_case, quote_string, snake_case,
typescript_property_name,
};
const BROWSER_RUNTIME_IMPORT: &str = r#"import {
validatePortableJson,
validateResult,
validateSchema,
} from "@lenso/contract-runtime/browser";
"#;
/// Generates an executable browser request client from the same validated
/// Descriptor IR used by the checked-in Rust and TypeScript bindings.
pub fn generate_browser_request_client(path: &Path) -> Result<String, CodegenError> {
let descriptor = load_descriptor(path)?;
let contract = contract_ir(&descriptor);
let client_name = contract
.capability_id
.split('@')
.next()
.and_then(|id| id.rsplit('.').next())
.map_or_else(|| "Capability".to_owned(), pascal_case);
let mut methods = String::new();
for operation in contract
.operations
.iter()
.filter(|operation| operation.interaction == "request")
{
let descriptor_operation = descriptor
.operations
.iter()
.find(|candidate| candidate.name == operation.name)
.expect("Contract IR operations come from the Descriptor");
let method = typescript_property_name(&snake_case(&operation.name));
let route = format!(
"/api/capabilities/{}/{}",
contract.capability_id, operation.name
);
writeln!(
methods,
" async {method}(request, token) {{\n validateSchema(request, {request_schema}, \"request\");\n const response = await fetchTransport({}, {{\n method: \"POST\",\n headers: {{ \"authorization\": `Bearer ${{token}}`, \"content-type\": \"application/json\" }},\n body: JSON.stringify(request),\n }});\n const result = await response.json();\n validatePortableJson(result);\n validateResult(result, {response_schema}, {error_schema});\n return result;\n }},",
quote_string(&route),
request_schema = descriptor_operation.request_schema,
response_schema = descriptor_operation.response_schema,
error_schema = descriptor_operation.domain_error_schema,
)
.expect("writing to a String cannot fail");
}
let mut output = format!(
"// @generated by lenso-contract-codegen from {}; do not edit.\n{BROWSER_RUNTIME_IMPORT}\n",
contract.capability_id
);
write!(
output,
"export function create{client_name}Client(fetchTransport = fetch) {{\n return {{\n{methods} }};\n}}\n"
)
.expect("writing to a String cannot fail");
Ok(output)
}