lenso-contract-codegen 0.6.5

Code generator for portable Lenso Capability contracts.
Documentation
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)
}