mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-06-22 12:23:04 -07:00
110 lines
4.0 KiB
Rust
110 lines
4.0 KiB
Rust
//! 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)
|
|
}
|
|
}
|
|
}
|
|
}
|