mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-06-22 12:23:04 -07:00
229 lines
6.8 KiB
Rust
229 lines
6.8 KiB
Rust
//! JavaScript tree structure generation.
|
|
|
|
use std::collections::BTreeSet;
|
|
use std::fmt::Write;
|
|
|
|
use brk_types::TreeNode;
|
|
|
|
use crate::{
|
|
ClientMetadata, Endpoint, GenericSyntax, JavaScriptSyntax, PatternField, build_child_path,
|
|
generate_leaf_field, generate_tree_node_field, prepare_tree_node, to_camel_case,
|
|
};
|
|
|
|
use super::api::generate_api_methods;
|
|
use super::client::generate_static_constants;
|
|
|
|
/// Generate JSDoc typedefs for the series tree.
|
|
pub fn generate_tree_typedefs(output: &mut String, catalog: &TreeNode, metadata: &ClientMetadata) {
|
|
writeln!(output, "// Catalog tree typedefs\n").unwrap();
|
|
|
|
let pattern_lookup = metadata.pattern_lookup();
|
|
let mut generated = BTreeSet::new();
|
|
generate_tree_typedef(
|
|
output,
|
|
"SeriesTree",
|
|
"",
|
|
catalog,
|
|
pattern_lookup,
|
|
metadata,
|
|
&mut generated,
|
|
);
|
|
}
|
|
|
|
fn generate_tree_typedef(
|
|
output: &mut String,
|
|
name: &str,
|
|
path: &str,
|
|
node: &TreeNode,
|
|
pattern_lookup: &std::collections::BTreeMap<Vec<PatternField>, String>,
|
|
metadata: &ClientMetadata,
|
|
generated: &mut BTreeSet<String>,
|
|
) {
|
|
let Some(ctx) = prepare_tree_node(node, name, path, pattern_lookup, metadata, generated) else {
|
|
return;
|
|
};
|
|
|
|
writeln!(output, "/**").unwrap();
|
|
writeln!(output, " * @typedef {{Object}} {}", name).unwrap();
|
|
|
|
for child in &ctx.children {
|
|
let js_type = if child.should_inline {
|
|
child.inline_type_name.clone()
|
|
} else {
|
|
metadata.field_type_annotation(&child.field, false, None, GenericSyntax::JAVASCRIPT)
|
|
};
|
|
|
|
writeln!(
|
|
output,
|
|
" * @property {{{}}} {}",
|
|
js_type,
|
|
to_camel_case(&child.field.name)
|
|
)
|
|
.unwrap();
|
|
}
|
|
|
|
writeln!(output, " */\n").unwrap();
|
|
|
|
// Generate child typedefs
|
|
for child in &ctx.children {
|
|
if child.should_inline {
|
|
let child_path = build_child_path(path, child.name);
|
|
generate_tree_typedef(
|
|
output,
|
|
&child.inline_type_name,
|
|
&child_path,
|
|
child.node,
|
|
pattern_lookup,
|
|
metadata,
|
|
generated,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Generate the main BrkClient class.
|
|
pub fn generate_main_client(
|
|
output: &mut String,
|
|
catalog: &TreeNode,
|
|
metadata: &ClientMetadata,
|
|
endpoints: &[Endpoint],
|
|
) {
|
|
let pattern_lookup = metadata.pattern_lookup();
|
|
|
|
writeln!(output, "/**").unwrap();
|
|
writeln!(
|
|
output,
|
|
" * Main BRK client with series tree and API methods"
|
|
)
|
|
.unwrap();
|
|
writeln!(output, " * @extends BrkClientBase").unwrap();
|
|
writeln!(output, " */").unwrap();
|
|
writeln!(output, "class BrkClient extends BrkClientBase {{").unwrap();
|
|
|
|
generate_static_constants(output);
|
|
|
|
writeln!(output, " /**").unwrap();
|
|
writeln!(output, " * @param {{BrkClientOptions|string}} options").unwrap();
|
|
writeln!(output, " */").unwrap();
|
|
writeln!(output, " constructor(options) {{").unwrap();
|
|
writeln!(output, " super(options);").unwrap();
|
|
writeln!(output, " /** @type {{SeriesTree}} */").unwrap();
|
|
writeln!(output, " this.series = this._buildTree('');").unwrap();
|
|
writeln!(output, " }}\n").unwrap();
|
|
|
|
writeln!(output, " /**").unwrap();
|
|
writeln!(output, " * @private").unwrap();
|
|
writeln!(output, " * @param {{string}} basePath").unwrap();
|
|
writeln!(output, " * @returns {{SeriesTree}}").unwrap();
|
|
writeln!(output, " */").unwrap();
|
|
writeln!(output, " _buildTree(basePath) {{").unwrap();
|
|
writeln!(output, " return {{").unwrap();
|
|
let mut generated = BTreeSet::new();
|
|
generate_tree_initializer(
|
|
output,
|
|
catalog,
|
|
"SeriesTree",
|
|
"",
|
|
3,
|
|
pattern_lookup,
|
|
metadata,
|
|
&mut generated,
|
|
);
|
|
writeln!(output, " }};").unwrap();
|
|
writeln!(output, " }}\n").unwrap();
|
|
|
|
writeln!(output, " /**").unwrap();
|
|
writeln!(
|
|
output,
|
|
" * Create a dynamic series endpoint builder for any series/index combination."
|
|
)
|
|
.unwrap();
|
|
writeln!(output, " *").unwrap();
|
|
writeln!(
|
|
output,
|
|
" * Use this for programmatic access when the series name is determined at runtime."
|
|
)
|
|
.unwrap();
|
|
writeln!(
|
|
output,
|
|
" * For type-safe access, use the `series` tree instead."
|
|
)
|
|
.unwrap();
|
|
writeln!(output, " *").unwrap();
|
|
writeln!(output, " * @param {{string}} series - The series name").unwrap();
|
|
writeln!(output, " * @param {{Index}} index - The index name").unwrap();
|
|
writeln!(output, " * @returns {{SeriesEndpoint<unknown>}}").unwrap();
|
|
writeln!(output, " */").unwrap();
|
|
writeln!(output, " seriesEndpoint(series, index) {{").unwrap();
|
|
writeln!(output, " return _endpoint(this, series, index);").unwrap();
|
|
writeln!(output, " }}\n").unwrap();
|
|
|
|
generate_api_methods(output, endpoints);
|
|
|
|
writeln!(output, "}}\n").unwrap();
|
|
|
|
writeln!(output, "export {{ BrkClient, BrkError }};").unwrap();
|
|
}
|
|
|
|
#[allow(clippy::too_many_arguments)]
|
|
fn generate_tree_initializer(
|
|
output: &mut String,
|
|
node: &TreeNode,
|
|
name: &str,
|
|
path: &str,
|
|
indent: usize,
|
|
pattern_lookup: &std::collections::BTreeMap<Vec<PatternField>, String>,
|
|
metadata: &ClientMetadata,
|
|
generated: &mut BTreeSet<String>,
|
|
) {
|
|
let indent_str = " ".repeat(indent);
|
|
|
|
let Some(ctx) = prepare_tree_node(node, name, path, pattern_lookup, metadata, generated) else {
|
|
return;
|
|
};
|
|
|
|
let syntax = JavaScriptSyntax;
|
|
for child in &ctx.children {
|
|
let field_name = to_camel_case(child.name);
|
|
|
|
if child.is_leaf {
|
|
if let TreeNode::Leaf(leaf) = child.node {
|
|
generate_leaf_field(
|
|
output,
|
|
&syntax,
|
|
"this",
|
|
child.name,
|
|
leaf,
|
|
metadata,
|
|
&indent_str,
|
|
);
|
|
}
|
|
} else if child.should_inline {
|
|
// Inline object
|
|
let child_path = build_child_path(path, child.name);
|
|
writeln!(output, "{}{}: {{", indent_str, field_name).unwrap();
|
|
generate_tree_initializer(
|
|
output,
|
|
child.node,
|
|
&child.inline_type_name,
|
|
&child_path,
|
|
indent + 1,
|
|
pattern_lookup,
|
|
metadata,
|
|
generated,
|
|
);
|
|
writeln!(output, "{}}},", indent_str).unwrap();
|
|
} else {
|
|
generate_tree_node_field(
|
|
output,
|
|
&syntax,
|
|
&child.field,
|
|
metadata,
|
|
&indent_str,
|
|
"this",
|
|
&child.base_result,
|
|
);
|
|
}
|
|
}
|
|
}
|