Skip to content

Commit

Permalink
feat: implement support for serde flatten (#49)
Browse files Browse the repository at this point in the history
  • Loading branch information
rlcurrall committed May 12, 2024
1 parent d25900c commit 2141be7
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 9 deletions.
49 changes: 44 additions & 5 deletions src/to_typescript/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,26 @@ impl super::ToTypescript for syn::ItemStruct {
let comments = utils::get_comments(self.clone().attrs);
state.write_comments(&comments, 0);

state.types.push_str(&format!(
"{export}interface {interface_name}{generics} {{\n",
interface_name = self.ident,
generics = utils::extract_struct_generics(self.generics.clone())
));
let intersections = get_intersections(&self.fields);

match intersections {
Some(intersections) => {
state.types.push_str(&format!(
"{export}type {struct_name}{generics} = {intersections} & {{\n",
export = export,
struct_name = self.ident,
generics = utils::extract_struct_generics(self.generics.clone()),
intersections = intersections
));
}
None => {
state.types.push_str(&format!(
"{export}interface {interface_name}{generics} {{\n",
interface_name = self.ident,
generics = utils::extract_struct_generics(self.generics.clone())
));
}
}

process_fields(self.fields, state, 2, casing);
state.types.push('}');
Expand All @@ -33,6 +48,12 @@ pub fn process_fields(
let space = utils::build_indentation(indentation_amount);
let case = case.into();
for field in fields {
// Check if the field has the serde flatten attribute, if so, skip it
let has_flatten_attr = utils::get_attribute_arg("serde", "flatten", &field.attrs).is_some();
if has_flatten_attr {
continue;
}

let comments = utils::get_comments(field.attrs);

state.write_comments(&comments, 2);
Expand All @@ -55,3 +76,21 @@ pub fn process_fields(
));
}
}

fn get_intersections(fields: &syn::Fields) -> Option<String> {
let mut types = Vec::new();

for field in fields {
let has_flatten_attr = utils::get_attribute_arg("serde", "flatten", &field.attrs).is_some();
let field_type = convert_type(&field.ty);
if has_flatten_attr {
types.push(field_type.ts_type);
}
}

if types.is_empty() {
return None;
}

Some(types.join(" & "))
}
32 changes: 30 additions & 2 deletions test/struct/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ struct Book {
/// Reviews of the book
/// by users.
user_reviews: Option<Vec<String>>,
#[serde(flatten)]
book_type: BookType,
}

#[tsync]
Expand Down Expand Up @@ -43,12 +45,38 @@ struct PaginationResult<T> {
total_items: number,
}


#[tsync]
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
/// Generic struct test with camelCase field names.
struct PaginationResultCamel<T> {
items: Vec<T>,
total_items: number,
}
}

#[tsync]
#[derive(Serialize)]
/// Struct with flattened field.
struct Author {
name: String,
#[serde(flatten)]
name: AuthorName,
}

#[tsync]
#[derive(Serialize)]
struct AuthorName {
alias: Option<String>,
first_name: String,
last_name: String,
}

#[tsync]
#[derive(Serialize)]
#[serde(tag = "type")]
enum BookType {
#[serde(rename = "fiction")]
Fiction { genre: String },
#[serde(rename = "non-fiction")]
NonFiction { subject: String },
}
26 changes: 25 additions & 1 deletion test/struct/typescript.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* This file is generated and managed by tsync */

/** Doc comments are preserved too! */
interface Book {
type Book = BookType & {
/** Name of the book. */
name: string;
/** Chapters of the book. */
Expand Down Expand Up @@ -47,3 +47,27 @@ interface PaginationResultCamel<T> {
items: Array<T>;
totalItems: number;
}

/** Struct with flattened field. */
type Author = AuthorName & {
name: string;
}

interface AuthorName {
alias?: string;
first_name: string;
last_name: string;
}

type BookType =
| BookType__Fiction
| BookType__NonFiction;

type BookType__Fiction = {
type: "Fiction";
genre: string;
};
type BookType__NonFiction = {
type: "NonFiction";
subject: string;
};
26 changes: 25 additions & 1 deletion test/struct/typescript.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* This file is generated and managed by tsync */

/** Doc comments are preserved too! */
export interface Book {
export type Book = BookType & {
/** Name of the book. */
name: string;
/** Chapters of the book. */
Expand Down Expand Up @@ -47,3 +47,27 @@ export interface PaginationResultCamel<T> {
items: Array<T>;
totalItems: number;
}

/** Struct with flattened field. */
export type Author = AuthorName & {
name: string;
}

export interface AuthorName {
alias?: string;
first_name: string;
last_name: string;
}

export type BookType =
| BookType__Fiction
| BookType__NonFiction;

type BookType__Fiction = {
type: "Fiction";
genre: string;
};
type BookType__NonFiction = {
type: "NonFiction";
subject: string;
};

0 comments on commit 2141be7

Please sign in to comment.