mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-30 12:18:11 -07:00
clients: snapshot
This commit is contained in:
@@ -11,9 +11,8 @@ use serde::Serialize;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{
|
||||
ClientMetadata, GenericSyntax, IndexSetPattern, JavaScriptSyntax, PatternField,
|
||||
StructuralPattern, VERSION, generate_parameterized_field, generate_tree_path_field,
|
||||
to_camel_case,
|
||||
ClientMetadata, GenericSyntax, IndexSetPattern, JavaScriptSyntax, StructuralPattern, VERSION,
|
||||
generate_parameterized_field, generate_tree_path_field, to_camel_case,
|
||||
};
|
||||
|
||||
/// Generate the base BrkClient class with HTTP functionality.
|
||||
@@ -324,7 +323,8 @@ pub fn generate_structural_patterns(
|
||||
}
|
||||
writeln!(output, " * @typedef {{Object}} {}", pattern.name).unwrap();
|
||||
for field in &pattern.fields {
|
||||
let js_type = field_type_annotation(field, metadata, pattern.is_generic);
|
||||
let js_type =
|
||||
metadata.field_type_annotation(field, pattern.is_generic, None, GenericSyntax::JAVASCRIPT);
|
||||
writeln!(
|
||||
output,
|
||||
" * @property {{{}}} {}",
|
||||
@@ -371,17 +371,3 @@ pub fn generate_structural_patterns(
|
||||
writeln!(output, "}}\n").unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn field_type_annotation(field: &PatternField, metadata: &ClientMetadata, is_generic: bool) -> String {
|
||||
metadata.field_type_annotation(field, is_generic, None, GenericSyntax::JAVASCRIPT)
|
||||
}
|
||||
|
||||
/// Get field type with specific generic value type.
|
||||
pub fn field_type_with_generic(
|
||||
field: &PatternField,
|
||||
metadata: &ClientMetadata,
|
||||
is_generic: bool,
|
||||
generic_value_type: Option<&str>,
|
||||
) -> String {
|
||||
metadata.field_type_annotation(field, is_generic, generic_value_type, GenericSyntax::JAVASCRIPT)
|
||||
}
|
||||
|
||||
@@ -6,13 +6,13 @@ use std::fmt::Write;
|
||||
use brk_types::TreeNode;
|
||||
|
||||
use crate::{
|
||||
ClientMetadata, Endpoint, JavaScriptSyntax, PatternField, child_type_name, generate_leaf_field,
|
||||
get_first_leaf_name, get_node_fields, get_pattern_instance_base, infer_accumulated_name,
|
||||
prepare_tree_node, to_camel_case,
|
||||
ClientMetadata, Endpoint, GenericSyntax, JavaScriptSyntax, PatternField, child_type_name,
|
||||
generate_leaf_field, get_first_leaf_name, get_node_fields, get_pattern_instance_base,
|
||||
infer_accumulated_name, prepare_tree_node, to_camel_case,
|
||||
};
|
||||
|
||||
use super::api::generate_api_methods;
|
||||
use super::client::{field_type_with_generic, generate_static_constants};
|
||||
use super::client::generate_static_constants;
|
||||
|
||||
/// Generate JSDoc typedefs for the catalog tree.
|
||||
pub fn generate_tree_typedefs(output: &mut String, catalog: &TreeNode, metadata: &ClientMetadata) {
|
||||
@@ -49,10 +49,11 @@ fn generate_tree_typedef(
|
||||
ctx.fields_with_child_info.iter().zip(ctx.children.iter())
|
||||
{
|
||||
let js_type = metadata.resolve_tree_field_type(
|
||||
field,
|
||||
child_fields.as_deref(),
|
||||
name,
|
||||
child_name,
|
||||
|generic| field_type_with_generic(field, metadata, false, generic),
|
||||
GenericSyntax::JAVASCRIPT,
|
||||
);
|
||||
|
||||
writeln!(
|
||||
|
||||
@@ -10,9 +10,8 @@ use brk_types::{pools, Index};
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
ClientMetadata, GenericSyntax, IndexSetPattern, PatternField, PythonSyntax,
|
||||
StructuralPattern, VERSION, generate_parameterized_field, generate_tree_path_field,
|
||||
index_to_field_name,
|
||||
ClientMetadata, IndexSetPattern, PythonSyntax, StructuralPattern, VERSION,
|
||||
generate_parameterized_field, generate_tree_path_field, index_to_field_name,
|
||||
};
|
||||
|
||||
/// Generate class-level constants for the BrkClient class.
|
||||
@@ -341,13 +340,3 @@ pub fn generate_structural_patterns(
|
||||
writeln!(output).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
/// Get Python type annotation for a field with optional generic value type.
|
||||
pub fn field_type_with_generic(
|
||||
field: &PatternField,
|
||||
metadata: &ClientMetadata,
|
||||
is_generic: bool,
|
||||
generic_value_type: Option<&str>,
|
||||
) -> String {
|
||||
metadata.field_type_annotation(field, is_generic, generic_value_type, GenericSyntax::PYTHON)
|
||||
}
|
||||
|
||||
@@ -6,12 +6,10 @@ use std::fmt::Write;
|
||||
use brk_types::TreeNode;
|
||||
|
||||
use crate::{
|
||||
ClientMetadata, PatternField, PythonSyntax, child_type_name, generate_leaf_field,
|
||||
ClientMetadata, GenericSyntax, PatternField, PythonSyntax, child_type_name, generate_leaf_field,
|
||||
get_node_fields, get_pattern_instance_base, prepare_tree_node, to_snake_case,
|
||||
};
|
||||
|
||||
use super::client::field_type_with_generic;
|
||||
|
||||
/// Generate tree classes
|
||||
pub fn generate_tree_classes(output: &mut String, catalog: &TreeNode, metadata: &ClientMetadata) {
|
||||
writeln!(output, "# Catalog tree classes\n").unwrap();
|
||||
@@ -54,12 +52,13 @@ fn generate_tree_class(
|
||||
for ((field, child_fields_opt), (child_name, child_node)) in
|
||||
ctx.fields_with_child_info.iter().zip(ctx.children.iter())
|
||||
{
|
||||
// Look up type parameter for generic patterns
|
||||
let generic_value_type = child_fields_opt
|
||||
.as_ref()
|
||||
.and_then(|cf| metadata.get_type_param(cf))
|
||||
.map(String::as_str);
|
||||
let py_type = field_type_with_generic(field, metadata, false, generic_value_type);
|
||||
let py_type = metadata.resolve_tree_field_type(
|
||||
field,
|
||||
child_fields_opt.as_deref(),
|
||||
name,
|
||||
child_name,
|
||||
GenericSyntax::PYTHON,
|
||||
);
|
||||
let field_name_py = to_snake_case(&field.name);
|
||||
|
||||
if metadata.is_pattern_type(&field.rust_type) && metadata.is_parameterizable(&field.rust_type)
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
use std::fmt::Write;
|
||||
|
||||
use crate::{
|
||||
ClientMetadata, GenericSyntax, IndexSetPattern, PatternField, RustSyntax,
|
||||
StructuralPattern, generate_parameterized_field, generate_tree_path_field,
|
||||
index_to_field_name, to_snake_case,
|
||||
ClientMetadata, GenericSyntax, IndexSetPattern, RustSyntax, StructuralPattern,
|
||||
generate_parameterized_field, generate_tree_path_field, index_to_field_name, to_snake_case,
|
||||
};
|
||||
|
||||
/// Generate import statements.
|
||||
@@ -315,7 +314,7 @@ pub fn generate_pattern_structs(
|
||||
for field in &pattern.fields {
|
||||
let field_name = to_snake_case(&field.name);
|
||||
let type_annotation =
|
||||
field_type_with_generic(field, metadata, pattern.is_generic, None);
|
||||
metadata.field_type_annotation(field, pattern.is_generic, None, GenericSyntax::RUST);
|
||||
writeln!(output, " pub {}: {},", field_name, type_annotation).unwrap();
|
||||
}
|
||||
|
||||
@@ -368,13 +367,3 @@ pub fn generate_pattern_structs(
|
||||
writeln!(output, "}}\n").unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
/// Get Rust type annotation for a field with optional generic value type.
|
||||
pub fn field_type_with_generic(
|
||||
field: &PatternField,
|
||||
metadata: &ClientMetadata,
|
||||
is_generic: bool,
|
||||
generic_value_type: Option<&str>,
|
||||
) -> String {
|
||||
metadata.field_type_annotation(field, is_generic, generic_value_type, GenericSyntax::RUST)
|
||||
}
|
||||
|
||||
@@ -6,13 +6,11 @@ use std::fmt::Write;
|
||||
use brk_types::TreeNode;
|
||||
|
||||
use crate::{
|
||||
ClientMetadata, LanguageSyntax, PatternField, RustSyntax, child_type_name,
|
||||
ClientMetadata, GenericSyntax, LanguageSyntax, PatternField, RustSyntax, child_type_name,
|
||||
generate_leaf_field, generate_tree_node_field, get_node_fields, get_pattern_instance_base,
|
||||
prepare_tree_node, to_snake_case,
|
||||
};
|
||||
|
||||
use super::client::field_type_with_generic;
|
||||
|
||||
/// Generate tree structs.
|
||||
pub fn generate_tree(output: &mut String, catalog: &TreeNode, metadata: &ClientMetadata) {
|
||||
writeln!(output, "// Catalog tree\n").unwrap();
|
||||
@@ -49,10 +47,11 @@ fn generate_tree_node(
|
||||
{
|
||||
let field_name = to_snake_case(&field.name);
|
||||
let type_annotation = metadata.resolve_tree_field_type(
|
||||
field,
|
||||
child_fields.as_deref(),
|
||||
name,
|
||||
child_name,
|
||||
|generic| field_type_with_generic(field, metadata, false, generic),
|
||||
GenericSyntax::RUST,
|
||||
);
|
||||
writeln!(output, " pub {}: {},", field_name, type_annotation).unwrap();
|
||||
}
|
||||
|
||||
@@ -85,25 +85,23 @@ impl ClientMetadata {
|
||||
}
|
||||
|
||||
/// Resolve the type name for a tree field, considering parameterizability.
|
||||
/// If the field matches a parameterizable pattern, returns type annotation from callback.
|
||||
/// If the field matches a parameterizable pattern, returns type annotation.
|
||||
/// Otherwise returns the inline type name (parent_child format).
|
||||
pub fn resolve_tree_field_type<F>(
|
||||
pub fn resolve_tree_field_type(
|
||||
&self,
|
||||
field: &PatternField,
|
||||
child_fields: Option<&[PatternField]>,
|
||||
parent_name: &str,
|
||||
child_name: &str,
|
||||
type_annotation_fn: F,
|
||||
) -> String
|
||||
where
|
||||
F: FnOnce(Option<&str>) -> String,
|
||||
{
|
||||
syntax: GenericSyntax,
|
||||
) -> String {
|
||||
match child_fields {
|
||||
Some(cf) if self.is_parameterizable_fields(cf) => {
|
||||
let generic_value_type = self.get_type_param(cf).map(String::as_str);
|
||||
type_annotation_fn(generic_value_type)
|
||||
self.field_type_annotation(field, false, generic_value_type, syntax)
|
||||
}
|
||||
Some(_) => crate::child_type_name(parent_name, child_name),
|
||||
None => type_annotation_fn(None),
|
||||
None => self.field_type_annotation(field, false, None, syntax),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,31 @@ impl GenericSyntax {
|
||||
pub const RUST: Self = Self { open: '<', close: '>', default_type: "_" };
|
||||
|
||||
pub fn wrap(&self, name: &str, type_param: &str) -> String {
|
||||
format!("{}{}{}{}", name, self.open, type_param, self.close)
|
||||
// Convert the type_param from Rust syntax to target syntax
|
||||
let converted = self.convert(type_param);
|
||||
format!("{}{}{}{}", name, self.open, converted, self.close)
|
||||
}
|
||||
|
||||
/// Convert a type string from Rust generic syntax to target language syntax.
|
||||
///
|
||||
/// For Python, wrapper newtypes like `Close<Cents>` are flattened to just `Cents`
|
||||
/// because Python type aliases can't be parameterized. This matches JS behavior.
|
||||
pub fn convert(&self, type_str: &str) -> String {
|
||||
// Flatten nested generics to innermost type (e.g., Close<Cents> -> Cents)
|
||||
// This is needed because wrapper types like Close, Open, High, Low are
|
||||
// just type aliases in generated code, not actual generic classes.
|
||||
extract_inner_type_recursive(type_str)
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract the innermost type from nested generics.
|
||||
/// E.g., `Close<Cents>` -> `Cents`, `Foo<Bar<Baz>>` -> `Baz`
|
||||
fn extract_inner_type_recursive(type_str: &str) -> String {
|
||||
if let Some(start) = type_str.find('<') {
|
||||
if let Some(end) = type_str.rfind('>') {
|
||||
let inner = &type_str[start + 1..end];
|
||||
return extract_inner_type_recursive(inner);
|
||||
}
|
||||
}
|
||||
type_str.to_string()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user