Skip to content

Commit

Permalink
Impl TypeScriptDef for API Route bodies
Browse files Browse the repository at this point in the history
  • Loading branch information
novacrazy committed Nov 15, 2024
1 parent b540ded commit d365885
Show file tree
Hide file tree
Showing 11 changed files with 139 additions and 45 deletions.
21 changes: 19 additions & 2 deletions src/api/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ macro_rules! command {
};

// entry point
($(
($group_name:ident; $(
// meta
$(#[$($meta:tt)*])*

Expand Down Expand Up @@ -337,7 +337,17 @@ macro_rules! command {
}
)?
}
)*) => {paste::paste!{$(
)*) => {paste::paste!{

#[cfg(feature = "ts")]
#[allow(unused_variables)]
pub fn [<register_ $group_name:snake _routes>](registry: &mut ts_bindgen::TypeRegistry) {
$(
$( <$body_name as ts_bindgen::TypeScriptDef>::register(registry); )?
)*
}

$(
// verify presence of exactly one `struct` without prefix
command!(@STRUCT $($auth_struct)? $($noauth_struct)?);

Expand Down Expand Up @@ -649,6 +659,13 @@ macro_rules! command_module {
$($vis use super::$mod::*;)*
}

#[cfg(feature = "ts")]
pub fn register_routes(registry: &mut ts_bindgen::TypeRegistry) {
$(
paste::paste! { $mod::[<register_ $mod _routes>](registry); }
)*
}

// TODO: Collect schemas from each object
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/api/commands/config.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::*;

command! {
command! { Config;

/// Gets the global server configuration
-struct GetServerConfig -> One ServerConfig: GET("config") {}
}
3 changes: 2 additions & 1 deletion src/api/commands/file.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::*;

command! {
command! { File;

+struct CreateFile -> One FileId: POST("file") {
;
#[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))]
Expand Down
3 changes: 2 additions & 1 deletion src/api/commands/invite.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::*;

command! {
command! { Invite;

+struct GetInvite -> One Invite: GET("invite" / code) {
pub code: SmolStr,
}
Expand Down
5 changes: 3 additions & 2 deletions src/api/commands/party.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::*;

command! {
command! { Party;

+struct GetParty -> One Party: GET("party" / party_id) {
pub party_id: PartyId,
}
Expand Down Expand Up @@ -252,7 +253,7 @@ command! {
#[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))]
#[cfg_attr(feature = "bon", derive(bon::Builder))]
struct SearchQuery {
#[serde(flatten)]
#[serde(alias = "q")]
#[cfg_attr(feature = "typed-builder", builder(setter(into)))]
#[cfg_attr(feature = "bon", builder(into))]
pub query: ThinString,
Expand Down
4 changes: 2 additions & 2 deletions src/api/commands/room.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::*;

command! {
command! { Room;
/// Create message command
+struct CreateMessage -> One Message: POST[100 ms, 2]("room" / room_id / "messages") where SEND_MESSAGES {
pub room_id: RoomId,
Expand Down Expand Up @@ -78,7 +78,7 @@ command! {
#[cfg_attr(feature = "bon", derive(bon::Builder))]
#[derive(Default)] struct StartTypingBody {
/// Will only show within the parent context if set
#[serde(flatten, default, skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "typed-builder", builder(default))]
pub parent: Option<MessageId>,
}
Expand Down
2 changes: 1 addition & 1 deletion src/api/commands/user.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::*;

command! {
command! { User;
-struct UserRegister(U) -> One Session: POST[1000 ms, 1]("user") {
;
#[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))]
Expand Down
4 changes: 4 additions & 0 deletions ts-bindgen/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ts-bindgen
==========

This is a crate specific to Lantern's Client SDK used to generate TypeScript bindings for the SDK. It's not exactly intended for general use.
36 changes: 20 additions & 16 deletions ts-bindgen/src/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ pub struct TypeRegistry {
}

impl TypeRegistry {
pub fn insert(&mut self, name: &'static str, ty: TypeScriptType) {
pub fn insert(&mut self, name: &'static str, mut ty: TypeScriptType) {
ty.unify();

self.types.insert(name, ty);
}

Expand All @@ -25,15 +27,8 @@ impl TypeRegistry {
use core::fmt::{Display, Error as FmtError, Write};

impl TypeScriptType {
fn inner(&self) -> &TypeScriptType {
match self {
TypeScriptType::Ref(rc) => rc.inner(),
_ => self,
}
}

fn is_extendible(&self, registry: &TypeRegistry) -> bool {
match self.inner() {
match self {
TypeScriptType::Interface { .. } => true,
TypeScriptType::Named(name) => match registry.get(name) {
Some(ty) => ty.is_extendible(registry),
Expand All @@ -55,8 +50,6 @@ impl TypeRegistry {
let mut first = true;

for (name, ty) in &self.types {
let ty = ty.inner();

if !first {
out.write_str("\n\n")?;
}
Expand All @@ -81,6 +74,7 @@ impl TypeRegistry {
| TypeScriptType::Undefined
| TypeScriptType::Tuple(_)
| TypeScriptType::Array(_, _)
| TypeScriptType::Partial(_)
| TypeScriptType::Named(_) => {
writeln!(out, "export type {name} = {ty};")?;
}
Expand All @@ -96,8 +90,6 @@ impl TypeRegistry {
writeln!(out, "export type {name} = {{ [key: {key}]: {value} }};")?;
}

TypeScriptType::Ref(_) => unreachable!(),

TypeScriptType::Enum(vec) | TypeScriptType::ConstEnum(vec) => {
let is_const = match ty {
TypeScriptType::ConstEnum(_) => " const",
Expand All @@ -119,6 +111,14 @@ impl TypeRegistry {
let mut do_extend = true;

for extend in extends {
let extend = match extend {
TypeScriptType::Named(name) => name,
_ => {
do_extend = false;
break;
}
};

do_extend &= match self.types.get(&**extend) {
Some(ty) => ty.is_extendible(self),
None => false,
Expand All @@ -135,15 +135,15 @@ impl TypeRegistry {
if i != 0 {
out.write_str(", ")?;
}
out.write_str(extend)?;
write!(out, "{extend}")?;
}
}
} else {
// take the intersection of the interface and extends
write!(out, "export type {name} = ")?;

for extend in extends {
write!(out, "{extend} & ")?;
write!(out, "{extend} &")?;
}
}

Expand All @@ -161,6 +161,10 @@ impl TypeRegistry {
out.write_str(",\n")?;
}
out.write_str("}")?;

if !do_extend {
out.write_str(";")?;
}
}
}
}
Expand All @@ -173,13 +177,13 @@ impl TypeScriptType {
fn fmt_depth<W: Write>(&self, depth: usize, f: &mut W) -> std::fmt::Result {
match self {
TypeScriptType::Named(name) => f.write_str(name),
TypeScriptType::Ref(rc) => rc.fmt_depth(depth, f),
TypeScriptType::Null => f.write_str("null"),
TypeScriptType::Undefined => f.write_str("undefined"),

TypeScriptType::EnumValue(e, v) => write!(f, "{e}.{v}"),

TypeScriptType::Array(inner, _) => write!(f, "Array<{inner}>"),
TypeScriptType::Partial(inner) => write!(f, "Partial<{inner}>"),
TypeScriptType::Boolean(value) => match value {
Some(value) => write!(f, "{value}"),
None => f.write_str("boolean"),
Expand Down
Loading

0 comments on commit d365885

Please sign in to comment.