Skip to content

Commit a9a71b5

Browse files
authored
Skip serializing if Option::is_none (#28)
1 parent b0a5f3c commit a9a71b5

File tree

7 files changed

+62
-12
lines changed

7 files changed

+62
-12
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
authors = ["ImJeremyHe<[email protected]>"]
33
edition = "2018"
44
name = "gents"
5-
version = "1.0.3"
5+
version = "1.0.4"
66
license = "MIT"
77
description = "generate Typescript interfaces from Rust code"
88
repository = "https://github.com/ImJeremyHe/gents"
@@ -11,6 +11,7 @@ keywords = ["Typescript", "interface", "ts-rs", "Rust", "wasm"]
1111
[dependencies]
1212
dprint-plugin-typescript = "0.95.8"
1313
serde = { version = "1.0", features = ["derive"] }
14+
serde_with = "3.14.0"
1415

1516
[workspace]
1617
members = ["./", "derives", "tests"]

README.md

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
It bridges the gap between Rust backends and TypeScript frontends by automatically generating type definitions, making it easy to use `serde-json` for communication between the two languages without manually maintaining duplicate type stubs.
88

99
**Why use gents?**
10+
****
1011

1112
- **Automatic type synchronization:** When your Rust data models change, you can instantly regenerate matching TypeScript interfaces, ensuring your frontend and backend always stay in sync.
1213
- **Eliminate manual boilerplate:** No need to hand-write or update TypeScript types every time your Rust structs or enums change, reducing human error and saving time.
@@ -23,7 +24,7 @@ This tool is designed for [LogiSheets](https://github.com/proclml/LogiSheets) an
2324

2425
Your issues and PRs are welcome!
2526

26-
---
27+
****
2728

2829
## 🛠️ How to Use `gents` (Quickstart & Advanced)
2930

@@ -65,7 +66,7 @@ You can use `rename_all` and `rename` for field naming policies.
6566

6667
### 3. Generate TypeScript Files
6768

68-
Write a unit test (or integration test):
69+
Write a binary or unit test:
6970

7071
```rust
7172
#[ignore]
@@ -80,24 +81,21 @@ fn gents() {
8081
}
8182
```
8283

84+
Since `Group` has dependencies on `Person`, `gents` will automatically include `Person` in the generated files.
85+
8386
- Run with `cargo test -- --ignored` to generate files.
8487

8588
### 4. Output Directory
8689

8790
- All generated `.ts` files will be placed in the directory you specify (e.g., `outdir`).
8891
- If you set the second argument of `gen_files` to `true`, an `index.ts` exporting all types will be generated.
8992

90-
### 5. Cross-Crate Usage
91-
92-
If your `TS` derives are spread across multiple crates, define a feature called `gents` in each crate and use `#[cfg(feature = "gents")]` to control code generation.
93-
See [LogiSheets example](https://github.com/proclml/LogiSheets/blob/master/crates/buildtools/src/generate.rs) for advanced multi-crate setup.
94-
95-
### 6. Integration with Frontend
93+
### 5. Integration with Frontend
9694

9795
- Add the generated `.ts` files to your frontend project (or link via a monorepo).
9896
- Now your TypeScript code can safely import and use the types generated from Rust, ensuring type consistency.
9997

100-
---
98+
****
10199

102100
## 💡 Advanced Tips
103101

@@ -108,7 +106,7 @@ See [LogiSheets example](https://github.com/proclml/LogiSheets/blob/master/crate
108106
- **Use in CI:**
109107
You can run the generation test in your CI pipeline to ensure TypeScript types are always up to date.
110108

111-
---
109+
****
112110

113111
## Why not `ts-rs`?
114112

derives/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "gents_derives"
3-
version = "1.0.3"
3+
version = "1.0.4"
44
description = "provides some macros for gents"
55
authors = ["ImJeremyHe<[email protected]>"]
66
license = "MIT"

derives/src/serde_json.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ fn get_serde_struct_impl_block(
312312
};
313313

314314
let dummy_type = quote! {
315+
#[::gents::serde_with::skip_serializing_none]
315316
#[derive(::gents::serde::Serialize, ::gents::serde::Deserialize)]
316317
#rename_all
317318
#dummy

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,4 @@ pub use descriptor::*;
6262
pub use file_generator::*;
6363

6464
pub use serde;
65+
pub use serde_with;

tests/src/lib.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,33 @@ fn test_struct_tagged_enum_serde() {
8585
_ => panic!(),
8686
}
8787
}
88+
89+
#[derive(Debug, Clone, gents_derives::TS)]
90+
#[ts(file_name = "b.ts", rename_all = "camelCase")]
91+
pub struct Pet {
92+
pub name: String,
93+
pub owner: Option<User>,
94+
}
95+
96+
#[test]
97+
fn test_option_none_to_json() {
98+
let pet = Pet {
99+
name: "test".to_string(),
100+
owner: None,
101+
};
102+
let json = serde_json::to_string(&pet).unwrap();
103+
assert_eq!(json, "{\"name\":\"test\"}");
104+
105+
let pet = Pet {
106+
name: "test".to_string(),
107+
owner: Some(User {
108+
id: 1,
109+
name: "test".to_string(),
110+
}),
111+
};
112+
let json = serde_json::to_string(&pet).unwrap();
113+
assert_eq!(
114+
json,
115+
"{\"name\":\"test\",\"owner\":{\"id\":1,\"name\":\"test\"}}"
116+
);
117+
}

tests/src/serde_test/mod.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub struct User {
3636
pub enum TestEnum {
3737
Variant1(User),
3838
Variant2(User),
39+
Variant3,
3940
}
4041

4142
#[test]
@@ -74,6 +75,24 @@ fn test_ts_rust_json_compatibility_enum() {
7475
TestEnum::Variant1(_) => assert!(true),
7576
_ => assert!(false),
7677
}
78+
79+
let test_enum = TestEnum::Variant3;
80+
let json = serde_json::to_string(&test_enum).unwrap();
81+
fs::write(format!("{}/{}.json", JS_DIR, file_name), &json).unwrap();
82+
83+
let ts_file_content = CHECK_PATTERN
84+
.replace("{file_name}", file_name)
85+
.replace("{type_name}", type_name);
86+
fs::write("src/serde_test/ts/check.ts", ts_file_content).unwrap();
87+
88+
let path = fs::canonicalize("src/serde_test/ts").unwrap();
89+
90+
let status = Command::new("npm")
91+
.args(["run", "check"])
92+
.current_dir(path)
93+
.status()
94+
.unwrap();
95+
assert!(status.success(), "TypeScript failed to check types");
7796
}
7897

7998
#[test]

0 commit comments

Comments
 (0)