brk_bindgen 0.2.3

A trait-based generator of client bindings for multiple languages
Documentation
//! JavaScript language syntax implementation.

use crate::{GenericSyntax, LanguageSyntax, to_camel_case};

/// JavaScript-specific code generation syntax.
pub struct JavaScriptSyntax;

impl LanguageSyntax for JavaScriptSyntax {
    fn field_name(&self, name: &str) -> String {
        to_camel_case(name)
    }

    fn path_expr(&self, base_var: &str, suffix: &str) -> String {
        // Convert base_var to camelCase for JavaScript
        let var_name = to_camel_case(base_var);
        format!("`${{{}}}{}`", var_name, suffix)
    }

    fn suffix_expr(&self, acc_var: &str, relative: &str) -> String {
        let var_name = to_camel_case(acc_var);
        if relative.is_empty() {
            // Identity: just return acc
            var_name
        } else {
            // _m(acc, relative) -> acc ? `${acc}_relative` : 'relative'
            format!("_m({}, '{}')", var_name, relative)
        }
    }

    fn prefix_expr(&self, prefix: &str, acc_var: &str) -> String {
        let var_name = to_camel_case(acc_var);
        if prefix.is_empty() {
            // Identity: just return acc
            var_name
        } else {
            // _p(prefix, acc) -> acc ? `${prefix}${acc}` : 'prefix_without_underscore'
            let prefix_base = prefix.trim_end_matches('_');
            format!("_p('{}', {})", prefix_base, var_name)
        }
    }

    fn constructor(&self, type_name: &str, path_expr: &str) -> String {
        format!("create{}(client, {})", type_name, path_expr)
    }

    fn field_init(&self, indent: &str, name: &str, _type_ann: &str, value: &str) -> String {
        // JavaScript uses object literal syntax; type is in JSDoc, not in assignment
        format!("{}{}: {},", indent, name, value)
    }

    fn generic_syntax(&self) -> GenericSyntax {
        GenericSyntax::JAVASCRIPT
    }

    fn string_literal(&self, value: &str) -> String {
        format!("'{}'", value)
    }

    fn constructor_name(&self, type_name: &str) -> String {
        format!("create{}", type_name)
    }

    fn disc_arg_expr(&self, template: &str) -> String {
        if template == "{disc}" {
            "disc".to_string()
        } else if template.is_empty() {
            "''".to_string()
        } else if !template.contains("{disc}") {
            format!("'{}'", template)
        } else if template.ends_with("{disc}") {
            let static_part = template.trim_end_matches("{disc}").trim_end_matches('_');
            format!("_m('{}', disc)", static_part)
        } else {
            let js_template = template.replace("{disc}", "${disc}");
            format!("`{}`", js_template)
        }
    }

    fn template_expr(&self, acc_var: &str, template: &str) -> String {
        let var_name = to_camel_case(acc_var);
        if template.is_empty() {
            // Identity — just pass disc
            format!("_m({}, disc)", var_name)
        } else if template == "{disc}" {
            // Template IS the discriminator
            format!("_m({}, disc)", var_name)
        } else if !template.contains("{disc}") {
            // Static suffix — no disc involved
            format!("_m({}, '{}')", var_name, template)
        } else {
            // Template with {disc}: use nested _m for proper separator handling
            // "ratio_{disc}_bps" → split on {disc} → _m(_m(acc, 'ratio'), disc) then _bps
            // But this is complex. For embedded disc, use string interpolation.
            // For suffix disc (ends with {disc}), use _m composition.
            if let Some(static_part) = template.strip_suffix("{disc}") {
                if static_part.is_empty() {
                    format!("_m({}, disc)", var_name)
                } else {
                    let static_part = static_part.trim_end_matches('_');
                    format!("_m(_m({}, '{}'), disc)", var_name, static_part)
                }
            } else {
                // Embedded disc — use template literal
                let js_template = template.replace("{disc}", "${disc}");
                format!("_m({}, `{}`)", var_name, js_template)
            }
        }
    }
}