mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-30 09:30:00 -07:00
global: MASSIVE snapshot
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
use std::fmt::Write;
|
||||
|
||||
use crate::{Endpoint, Parameter, to_camel_case};
|
||||
use crate::{Endpoint, Parameter, generators::MANUAL_GENERIC_TYPES, to_camel_case};
|
||||
|
||||
/// Generate API methods for the BrkClient class.
|
||||
pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) {
|
||||
@@ -12,7 +12,7 @@ pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) {
|
||||
}
|
||||
|
||||
let method_name = endpoint_to_method_name(endpoint);
|
||||
let return_type = endpoint.response_type.as_deref().unwrap_or("*");
|
||||
let return_type = normalize_return_type(endpoint.response_type.as_deref().unwrap_or("*"));
|
||||
|
||||
writeln!(output, " /**").unwrap();
|
||||
if let Some(summary) = &endpoint.summary {
|
||||
@@ -110,3 +110,12 @@ fn build_path_template(path: &str, path_params: &[Parameter]) -> String {
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
/// Replace generic types with their Any variants in return types.
|
||||
fn normalize_return_type(return_type: &str) -> String {
|
||||
let mut result = return_type.to_string();
|
||||
for type_name in MANUAL_GENERIC_TYPES {
|
||||
result = result.replace(type_name, &format!("Any{}", type_name));
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
@@ -49,6 +49,16 @@ class BrkError extends Error {{
|
||||
}}
|
||||
}}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {{Object}} MetricData
|
||||
* @property {{number}} total - Total number of data points
|
||||
* @property {{number}} from - Start index (inclusive)
|
||||
* @property {{number}} to - End index (exclusive)
|
||||
* @property {{T[]}} data - The metric data
|
||||
*/
|
||||
/** @typedef {{MetricData<unknown>}} AnyMetricData */
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {{Object}} MetricEndpoint
|
||||
|
||||
@@ -136,9 +136,56 @@ pub fn generate_main_client(
|
||||
|
||||
generate_api_methods(output, endpoints);
|
||||
|
||||
// Instance method: mergeMetricPatterns
|
||||
writeln!(output, r#"
|
||||
/**
|
||||
* Merge multiple MetricPatterns into a single pattern.
|
||||
* Throws if any two patterns have overlapping indexes.
|
||||
* @template T
|
||||
* @param {{...MetricPattern<T>}} patterns - The patterns to merge
|
||||
* @returns {{MetricPattern<T>}} A new merged pattern
|
||||
*/
|
||||
mergeMetricPatterns(...patterns) {{
|
||||
if (patterns.length === 0) {{
|
||||
throw new BrkError('mergeMetricPatterns requires at least one pattern');
|
||||
}}
|
||||
if (patterns.length === 1) {{
|
||||
return patterns[0];
|
||||
}}
|
||||
|
||||
const seenIndexes = /** @type {{Map<Index, string>}} */ (new Map());
|
||||
const mergedBy = /** @type {{Partial<Record<Index, MetricEndpoint<T>>>}} */ ({{}});
|
||||
|
||||
for (const pattern of patterns) {{
|
||||
for (const index of pattern.indexes()) {{
|
||||
const existing = seenIndexes.get(index);
|
||||
if (existing !== undefined) {{
|
||||
throw new BrkError(`Index '${{index}}' exists in both '${{existing}}' and '${{pattern.name}}'`);
|
||||
}}
|
||||
seenIndexes.set(index, pattern.name);
|
||||
Object.defineProperty(mergedBy, index, {{
|
||||
get() {{ return pattern.get(index); }},
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
}});
|
||||
}}
|
||||
}}
|
||||
|
||||
const allIndexes = /** @type {{Index[]}} */ ([...seenIndexes.keys()]);
|
||||
const firstName = patterns[0].name;
|
||||
|
||||
return {{
|
||||
name: firstName,
|
||||
by: mergedBy,
|
||||
indexes() {{ return allIndexes; }},
|
||||
get(index) {{ return mergedBy[index]; }},
|
||||
}};
|
||||
}}
|
||||
"#).unwrap();
|
||||
|
||||
writeln!(output, "}}\n").unwrap();
|
||||
|
||||
writeln!(output, "export {{ BrkClient, BrkClientBase, BrkError }};").unwrap();
|
||||
writeln!(output, "export {{ BrkClient, BrkError }};").unwrap();
|
||||
}
|
||||
|
||||
fn generate_tree_initializer(
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::fmt::Write;
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{TypeSchemas, ref_to_type_name, to_camel_case};
|
||||
use crate::{TypeSchemas, generators::MANUAL_GENERIC_TYPES, ref_to_type_name, to_camel_case};
|
||||
|
||||
/// Generate JSDoc type definitions from OpenAPI schemas.
|
||||
pub fn generate_type_definitions(output: &mut String, schemas: &TypeSchemas) {
|
||||
@@ -15,6 +15,10 @@ pub fn generate_type_definitions(output: &mut String, schemas: &TypeSchemas) {
|
||||
writeln!(output, "// Type definitions\n").unwrap();
|
||||
|
||||
for (name, schema) in schemas {
|
||||
if MANUAL_GENERIC_TYPES.contains(&name.as_str()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let js_type = schema_to_js_type(schema, Some(name));
|
||||
|
||||
if is_primitive_alias(schema) {
|
||||
|
||||
@@ -14,3 +14,6 @@ pub mod rust;
|
||||
pub use javascript::generate_javascript_client;
|
||||
pub use python::generate_python_client;
|
||||
pub use rust::generate_rust_client;
|
||||
|
||||
/// Types that are manually defined as generics in client code, not from schema.
|
||||
pub const MANUAL_GENERIC_TYPES: &[&str] = &["MetricData", "MetricEndpoint"];
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
use std::fmt::Write;
|
||||
|
||||
use crate::{Endpoint, Parameter, escape_python_keyword, to_snake_case};
|
||||
use crate::{Endpoint, Parameter, escape_python_keyword, generators::MANUAL_GENERIC_TYPES, to_snake_case};
|
||||
|
||||
use super::client::generate_class_constants;
|
||||
use super::types::js_type_to_python;
|
||||
@@ -41,11 +41,13 @@ pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) {
|
||||
}
|
||||
|
||||
let method_name = endpoint_to_method_name(endpoint);
|
||||
let return_type = endpoint
|
||||
.response_type
|
||||
.as_deref()
|
||||
.map(js_type_to_python)
|
||||
.unwrap_or_else(|| "Any".to_string());
|
||||
let return_type = normalize_return_type(
|
||||
&endpoint
|
||||
.response_type
|
||||
.as_deref()
|
||||
.map(js_type_to_python)
|
||||
.unwrap_or_else(|| "Any".to_string()),
|
||||
);
|
||||
|
||||
// Build method signature
|
||||
let params = build_method_params(endpoint);
|
||||
@@ -149,3 +151,12 @@ fn build_path_template(path: &str, path_params: &[Parameter]) -> String {
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
/// Replace generic types with their Any variants in return types.
|
||||
fn normalize_return_type(return_type: &str) -> String {
|
||||
let mut result = return_type.to_string();
|
||||
for type_name in MANUAL_GENERIC_TYPES {
|
||||
result = result.replace(type_name, &format!("Any{}", type_name));
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
@@ -118,11 +118,23 @@ def _m(acc: str, s: str) -> str:
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
/// Generate the Endpoint class
|
||||
/// Generate the MetricData and MetricEndpoint classes
|
||||
pub fn generate_endpoint_class(output: &mut String) {
|
||||
writeln!(
|
||||
output,
|
||||
r#"class Endpoint(Generic[T]):
|
||||
r#"class MetricData(TypedDict, Generic[T]):
|
||||
"""Metric data with range information."""
|
||||
total: int
|
||||
from_: int # 'from' is reserved in Python
|
||||
to: int
|
||||
data: List[T]
|
||||
|
||||
|
||||
# Type alias for non-generic usage
|
||||
AnyMetricData = MetricData[Any]
|
||||
|
||||
|
||||
class MetricEndpoint(Generic[T]):
|
||||
"""An endpoint for a specific metric + index combination."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, name: str, index: str):
|
||||
@@ -130,11 +142,11 @@ pub fn generate_endpoint_class(output: &mut String) {
|
||||
self._name = name
|
||||
self._index = index
|
||||
|
||||
def get(self) -> List[T]:
|
||||
def get(self) -> MetricData[T]:
|
||||
"""Fetch all data points for this metric/index."""
|
||||
return self._client.get(self.path())
|
||||
|
||||
def range(self, from_val: Optional[int] = None, to_val: Optional[int] = None) -> List[T]:
|
||||
def range(self, from_val: Optional[int] = None, to_val: Optional[int] = None) -> MetricData[T]:
|
||||
"""Fetch data points within a range."""
|
||||
params = []
|
||||
if from_val is not None:
|
||||
@@ -150,6 +162,10 @@ pub fn generate_endpoint_class(output: &mut String) {
|
||||
return f"/api/metric/{{self._name}}/{{self._index}}"
|
||||
|
||||
|
||||
# Type alias for non-generic usage
|
||||
AnyMetricEndpoint = MetricEndpoint[Any]
|
||||
|
||||
|
||||
class MetricPattern(Protocol[T]):
|
||||
"""Protocol for metric patterns with different index sets."""
|
||||
|
||||
@@ -162,7 +178,7 @@ class MetricPattern(Protocol[T]):
|
||||
"""Get the list of available indexes for this metric."""
|
||||
...
|
||||
|
||||
def get(self, index: str) -> Optional[Endpoint[T]]:
|
||||
def get(self, index: str) -> Optional[MetricEndpoint[T]]:
|
||||
"""Get an endpoint for a specific index, if supported."""
|
||||
...
|
||||
|
||||
@@ -199,10 +215,10 @@ pub fn generate_index_accessors(output: &mut String, patterns: &[IndexSetPattern
|
||||
for index in &pattern.indexes {
|
||||
let method_name = index_to_field_name(index);
|
||||
let index_name = index.serialize_long();
|
||||
writeln!(output, " def {}(self) -> Endpoint[T]:", method_name).unwrap();
|
||||
writeln!(output, " def {}(self) -> MetricEndpoint[T]:", method_name).unwrap();
|
||||
writeln!(
|
||||
output,
|
||||
" return Endpoint(self._client, self._name, '{}')",
|
||||
" return MetricEndpoint(self._client, self._name, '{}')",
|
||||
index_name
|
||||
)
|
||||
.unwrap();
|
||||
@@ -250,7 +266,7 @@ pub fn generate_index_accessors(output: &mut String, patterns: &[IndexSetPattern
|
||||
writeln!(output).unwrap();
|
||||
|
||||
// Generate get(index) method
|
||||
writeln!(output, " def get(self, index: str) -> Optional[Endpoint[T]]:").unwrap();
|
||||
writeln!(output, " def get(self, index: str) -> Optional[MetricEndpoint[T]]:").unwrap();
|
||||
writeln!(output, " \"\"\"Get an endpoint for a specific index, if supported.\"\"\"").unwrap();
|
||||
for (i, index) in pattern.indexes.iter().enumerate() {
|
||||
let method_name = index_to_field_name(index);
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::fmt::Write;
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{TypeSchemas, escape_python_keyword, ref_to_type_name};
|
||||
use crate::{TypeSchemas, escape_python_keyword, generators::MANUAL_GENERIC_TYPES, ref_to_type_name};
|
||||
|
||||
/// Generate type definitions from schemas.
|
||||
pub fn generate_type_definitions(output: &mut String, schemas: &TypeSchemas) {
|
||||
@@ -18,6 +18,10 @@ pub fn generate_type_definitions(output: &mut String, schemas: &TypeSchemas) {
|
||||
let sorted_names = topological_sort_schemas(schemas);
|
||||
|
||||
for name in sorted_names {
|
||||
if MANUAL_GENERIC_TYPES.contains(&name.as_str()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let Some(schema) = schemas.get(&name) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user