Skip to main content

lenso_contract_codegen/
browser.rs

1use std::{fmt::Write as _, path::Path};
2
3use super::{
4    CodegenError, contract_ir, load_descriptor, pascal_case, quote_string, snake_case,
5    typescript_property_name,
6};
7
8const BROWSER_RUNTIME_IMPORT: &str = r#"import {
9  validatePortableJson,
10  validateResult,
11  validateSchema,
12} from "@lenso/contract-runtime/browser";
13"#;
14
15/// Generates an executable browser request client from the same validated
16/// Descriptor IR used by the checked-in Rust and TypeScript bindings.
17pub fn generate_browser_request_client(path: &Path) -> Result<String, CodegenError> {
18    let descriptor = load_descriptor(path)?;
19    let contract = contract_ir(&descriptor);
20    let client_name = contract
21        .capability_id
22        .split('@')
23        .next()
24        .and_then(|id| id.rsplit('.').next())
25        .map_or_else(|| "Capability".to_owned(), pascal_case);
26    let mut methods = String::new();
27    for operation in contract
28        .operations
29        .iter()
30        .filter(|operation| operation.interaction == "request")
31    {
32        let descriptor_operation = descriptor
33            .operations
34            .iter()
35            .find(|candidate| candidate.name == operation.name)
36            .expect("Contract IR operations come from the Descriptor");
37        let method = typescript_property_name(&snake_case(&operation.name));
38        let route = format!(
39            "/api/capabilities/{}/{}",
40            contract.capability_id, operation.name
41        );
42        writeln!(
43            methods,
44            "    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    }},",
45            quote_string(&route),
46            request_schema = descriptor_operation.request_schema,
47            response_schema = descriptor_operation.response_schema,
48            error_schema = descriptor_operation.domain_error_schema,
49        )
50        .expect("writing to a String cannot fail");
51    }
52    let mut output = format!(
53        "// @generated by lenso-contract-codegen from {}; do not edit.\n{BROWSER_RUNTIME_IMPORT}\n",
54        contract.capability_id
55    );
56    write!(
57        output,
58        "export function create{client_name}Client(fetchTransport = fetch) {{\n  return {{\n{methods}  }};\n}}\n"
59    )
60    .expect("writing to a String cannot fail");
61    Ok(output)
62}