From c2bb290618fe780285a60fad98e4ce5e6ad90fa9 Mon Sep 17 00:00:00 2001 From: Aiden McClelland Date: Wed, 12 Nov 2025 10:57:37 -0700 Subject: [PATCH] wip: replace ts lib --- Cargo.lock | 65 +++++++++++++--------------------- Cargo.toml | 19 +++++----- src/cli.rs | 2 +- src/handler/adapters.rs | 18 +++++----- src/handler/from_fn.rs | 15 ++++---- src/handler/mod.rs | 6 ++-- src/handler/parent.rs | 12 +++---- src/lib.rs | 7 ++-- src/ts.rs | 77 +++++++++++++++++++++++++++++++++++++++++ tests/test.rs | 4 +-- 10 files changed, 143 insertions(+), 82 deletions(-) create mode 100644 src/ts.rs diff --git a/Cargo.lock b/Cargo.lock index 152767c..8814f1e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1198,8 +1198,8 @@ dependencies = [ "thiserror 2.0.17", "tokio", "tokio-stream", - "ts-rs", "url", + "visit-rs", "yajrc", ] @@ -1495,15 +1495,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - [[package]] name = "thiserror" version = "1.0.69" @@ -1704,28 +1695,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "ts-rs" -version = "9.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b44017f9f875786e543595076374b9ef7d13465a518dd93d6ccdbf5b432dde8c" -dependencies = [ - "thiserror 1.0.69", - "ts-rs-macros", -] - -[[package]] -name = "ts-rs-macros" -version = "9.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c88cc88fd23b5a04528f3a8436024f20010a16ec18eb23c164b1242f65860130" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "termcolor", -] - [[package]] name = "unicode-ident" version = "1.0.22" @@ -1774,6 +1743,29 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "visit-rs" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ea0fdb05dd98029f7e226ccd11bd7184ad68566365547930bdde9ae79b5ce3d" +dependencies = [ + "async-stream", + "futures", + "serde", + "visit-rs-derive", +] + +[[package]] +name = "visit-rs-derive" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dde3216fefaf10421d9509f88bc5a480b5fb3fe48779ca4f148e75896d3f5ad" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "want" version = "0.3.1" @@ -1866,15 +1858,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "winapi-util" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" -dependencies = [ - "windows-sys 0.61.2", -] - [[package]] name = "windows-link" version = "0.1.3" diff --git a/Cargo.toml b/Cargo.toml index 9025785..94c5f29 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,31 +1,32 @@ [package] authors = ["Aiden McClelland "] -edition = "2018" -name = "rpc-toolkit" -version = "0.3.2" description = "A toolkit for creating JSON-RPC 2.0 servers with automatic cli bindings" -license = "MIT" documentation = "https://docs.rs/rpc-toolkit" -keywords = ["json", "rpc", "cli"] +edition = "2018" +keywords = ["cli", "json", "rpc"] +license = "MIT" +name = "rpc-toolkit" repository = "https://github.com/Start9Labs/rpc-toolkit" +version = "0.3.2" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] cbor = ["serde_cbor"] -default = ["cbor", "ts-rs"] +default = ["cbor", "ts"] +ts = ["visit-rs"] [dependencies] -axum = "0.8" async-stream = "0.3" async-trait = "0.1" +axum = "0.8" clap = { version = "4", features = ["derive"] } futures = "0.3" http = "1" http-body-util = "0.1" # hyper = { version = "1", features = ["server", "http1", "http2", "client"] } -itertools = "0.14" imbl-value = "0.4.3" +itertools = "0.14" lazy_format = "2" lazy_static = "1.4" openssl = { version = "0.10", features = ["vendored"] } @@ -37,6 +38,6 @@ serde_json = "1.0" thiserror = "2.0" tokio = { version = "1", features = ["full"] } tokio-stream = { version = "0.1", features = ["io-util", "net"] } -ts-rs = { version = "9.0.1", optional = true } url = "2" +visit-rs = { version = "0.1.5", optional = true } yajrc = "0.1" diff --git a/src/cli.rs b/src/cli.rs index 2b2a6e7..05f28f2 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -209,7 +209,7 @@ where type Err = RemoteHandler::Err; } -#[cfg(feature = "ts-rs")] +#[cfg(feature = "ts")] impl crate::handler::HandlerTS for CallRemoteHandler where diff --git a/src/handler/adapters.rs b/src/handler/adapters.rs index 844d813..16f2ca8 100644 --- a/src/handler/adapters.rs +++ b/src/handler/adapters.rs @@ -139,7 +139,7 @@ impl HandlerTypes for NoCli { type Ok = H::Ok; type Err = H::Err; } -#[cfg(feature = "ts-rs")] +#[cfg(feature = "ts")] impl crate::handler::HandlerTS for NoCli where H: crate::handler::HandlerTS, @@ -233,7 +233,7 @@ impl HandlerTypes for NoDisplay { type Ok = H::Ok; type Err = H::Err; } -#[cfg(feature = "ts-rs")] +#[cfg(feature = "ts")] impl crate::handler::HandlerTS for NoDisplay where H: crate::handler::HandlerTS, @@ -355,7 +355,7 @@ where type Ok = H::Ok; type Err = H::Err; } -#[cfg(feature = "ts-rs")] +#[cfg(feature = "ts")] impl crate::handler::HandlerTS for CustomDisplay where H: crate::handler::HandlerTS, @@ -526,7 +526,7 @@ where type Ok = H::Ok; type Err = H::Err; } -#[cfg(feature = "ts-rs")] +#[cfg(feature = "ts")] impl crate::handler::HandlerTS for CustomDisplayFn where H: crate::handler::HandlerTS, @@ -751,7 +751,7 @@ where type Err = H::Err; } -#[cfg(feature = "ts-rs")] +#[cfg(feature = "ts")] impl crate::handler::HandlerTS for InheritanceHandler where @@ -884,7 +884,7 @@ where type Ok = H::Ok; type Err = H::Err; } -#[cfg(feature = "ts-rs")] +#[cfg(feature = "ts")] impl crate::handler::HandlerTS for WithAbout where H: crate::handler::HandlerTS, @@ -988,7 +988,7 @@ where type Err = H::Err; } -#[cfg(feature = "ts-rs")] +#[cfg(feature = "ts")] impl crate::handler::HandlerTS for NoTS { fn type_info(&self) -> Option { None @@ -1088,7 +1088,7 @@ where type Err = H::Err; } -#[cfg(feature = "ts-rs")] +#[cfg(feature = "ts")] impl crate::handler::HandlerTS for UnknownTS { fn type_info(&self) -> Option { Some("{_PARAMS:unknown,_RETURN:unknown}".to_string()) @@ -1192,7 +1192,7 @@ where type Err = H::Err; } -#[cfg(feature = "ts-rs")] +#[cfg(feature = "ts")] impl crate::handler::HandlerTS for CustomTS { fn type_info(&self) -> Option { Some(format!( diff --git a/src/handler/from_fn.rs b/src/handler/from_fn.rs index 0f672c4..af711cf 100644 --- a/src/handler/from_fn.rs +++ b/src/handler/from_fn.rs @@ -7,9 +7,9 @@ use imbl_value::imbl::OrdMap; use imbl_value::Value; use serde::de::DeserializeOwned; use serde::Serialize; -#[cfg(feature = "ts-rs")] -use ts_rs::TS; +#[cfg(feature = "ts")] +use crate::ts::TSVisitor; use crate::util::PhantomData; use crate::{ CliBindings, Empty, HandlerArgs, HandlerArgsFor, HandlerFor, HandlerTypes, LeafHandler, @@ -48,14 +48,15 @@ impl std::fmt::Debug for FromFn { } } -#[cfg(feature = "ts-rs")] +#[cfg(feature = "ts")] impl crate::handler::HandlerTS for FromFn where Self: HandlerTypes, - ::Params: ts_rs::TS, - ::Ok: ts_rs::TS, + visit_rs::Static<::Params>: visit_rs::Visit, + visit_rs::Static<::Ok>: visit_rs::Visit, { fn type_info(&self) -> Option { + let mut visitor = TSVisitor::default(); Some(format!( "{{_PARAMS:{},_RETURN:{}}}", ::Params::inline_flattened(), @@ -173,7 +174,7 @@ impl std::fmt::Debug for FromFnAsync { } } -#[cfg(feature = "ts-rs")] +#[cfg(feature = "ts")] impl crate::handler::HandlerTS for FromFnAsync where Self: HandlerTypes, @@ -285,7 +286,7 @@ impl std::fmt::Debug for FromFnAsyncLocal crate::handler::HandlerTS for FromFnAsyncLocal where Self: HandlerTypes, diff --git a/src/handler/mod.rs b/src/handler/mod.rs index 9236ee9..f904c77 100644 --- a/src/handler/mod.rs +++ b/src/handler/mod.rs @@ -233,7 +233,7 @@ pub trait HandlerTS { fn type_info(&self) -> Option; } -#[cfg(not(feature = "ts-rs"))] +#[cfg(not(feature = "ts"))] impl HandlerTS for T { fn type_info(&self) -> Option { None @@ -450,8 +450,8 @@ where } #[derive(Debug, Clone, Copy, Deserialize, Serialize, Parser)] -#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))] -#[cfg_attr(feature = "ts-rs", ts(type = "{}"))] +#[cfg_attr(feature = "ts", derive(ts_rs::TS))] +#[cfg_attr(feature = "ts", ts(type = "{}"))] pub struct Empty {} pub trait OrEmpty { diff --git a/src/handler/parent.rs b/src/handler/parent.rs index c2406ae..3fd260a 100644 --- a/src/handler/parent.rs +++ b/src/handler/parent.rs @@ -7,14 +7,14 @@ use imbl_value::Value; use serde::Serialize; use yajrc::RpcError; -#[cfg(feature = "ts-rs")] +#[cfg(feature = "ts")] use crate::handler::HandleAnyTS; use crate::util::{combine, Flat, PhantomData}; use crate::{ CliBindings, DynHandler, Empty, HandleAny, HandleAnyArgs, Handler, HandlerArgs, HandlerArgsFor, HandlerFor, HandlerRequires, HandlerTypes, WithContext, }; -#[cfg(feature = "ts-rs")] +#[cfg(feature = "ts")] use crate::{CustomTS, UnknownTS}; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] @@ -88,7 +88,7 @@ impl ParentHandler Option { use std::fmt::Write; let mut res = "{".to_owned(); @@ -169,7 +169,7 @@ where type Err = RpcError; } -#[cfg(feature = "ts-rs")] +#[cfg(feature = "ts")] impl crate::handler::HandlerTS for ParentHandler where @@ -180,7 +180,7 @@ where self.type_info_impl(&Params::inline_flattened()) } } -#[cfg(feature = "ts-rs")] +#[cfg(feature = "ts")] impl crate::handler::HandlerTS for CustomTS> where @@ -191,7 +191,7 @@ where self.handler.type_info_impl(&self.params_ty) } } -#[cfg(feature = "ts-rs")] +#[cfg(feature = "ts")] impl crate::handler::HandlerTS for UnknownTS> where diff --git a/src/lib.rs b/src/lib.rs index 112db5f..eb3b3d4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,9 +10,8 @@ pub mod command_helpers; mod context; mod handler; mod server; +#[cfg(feature = "ts")] +pub mod ts; pub mod util; -#[cfg(feature = "ts-rs")] -pub fn type_helpers() -> &'static str { - include_str!("./type-helpers.ts") -} +#[cfg(feature = "ts")] \ No newline at end of file diff --git a/src/ts.rs b/src/ts.rs new file mode 100644 index 0000000..94a8359 --- /dev/null +++ b/src/ts.rs @@ -0,0 +1,77 @@ +use visit_rs::{NamedStatic, Static, Visit, VisitFieldsStaticNamed, Visitor}; + +pub fn type_helpers() -> &'static str { + include_str!("./type-helpers.ts") +} + +#[derive(Default)] +pub struct TSVisitor { + pub ts: String, +} +impl Visitor for TSVisitor { + type Result = (); +} + +impl Visit for Static +where + T: VisitFieldsStaticNamed, +{ + fn visit(&self, visitor: &mut TSVisitor) -> ::Result { + if Self::IS_NAMED { + visitor.ts.push_str("{"); + } else { + visitor.ts.push_str("["); + } + self.visit_fields_static_named(visitor).collect::<()>(); + if Self::IS_NAMED { + visitor.ts.push_str("}"); + } else { + visitor.ts.push_str("]"); + } + } +} + +impl Visit for NamedStatic +where + Static: Visit, +{ + fn visit(&self, visitor: &mut TSVisitor) -> ::Result { + if let Some(name) = self.name { + if name.chars().all(|c| c.is_alphanumeric() || c == '_') + && name.chars().next().map_or(false, |c| c.is_alphabetic()) + { + visitor.ts.push_str(name); + } else { + write!( + &mut visitor.ts, + "[{}]", + serde_json::to_string(&name).unwrap() + ) + .unwrap(); + } + visitor.ts.push_str(":"); + } + Static::::new().visit(visitor); + if self.name.is_some() { + visitor.ts.push(";"); + } else { + visitor.ts.push(","); + } + } +} + +macro_rules! impl_ts { + ($($ty:ty),+ => $ts:expr) => { + $( + impl Visit for Static<$ty> { + fn visit(&self, visitor: &mut TSVisitor) -> ::Result { + visitor.ts.push_str($ts); + } + } + )+ + }; +} + +impl_ts!(String => "string"); +impl_ts!(usize,u8,u16,u32,isize,i8,i16,i32,f32,f64 => "number"); +impl_ts!(u64,u128,i64,i128 => "bigint"); diff --git a/tests/test.rs b/tests/test.rs index 44b9bb4..3c8e8bd 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -11,7 +11,7 @@ struct TestContext; impl Context for TestContext {} #[derive(Debug, Deserialize, Serialize, Parser)] -#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))] +#[cfg_attr(feature = "ts", derive(ts_rs::TS))] struct Thing1Params { thing: String, } @@ -30,7 +30,7 @@ fn no_ts_handler(_ctx: TestContext, params: NoTSParams) -> Result