Skip to content

Commit abaed01

Browse files
committed
Add rename_all support
1 parent e4fba7f commit abaed01

File tree

3 files changed

+83
-11
lines changed

3 files changed

+83
-11
lines changed

packages/cw-schema-derive/src/expand.rs

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,40 @@
11
use crate::bail;
22
use proc_macro2::TokenStream;
3-
use quote::quote;
3+
use quote::{format_ident, quote};
44
use std::borrow::Cow;
55
use syn::{DataEnum, DataStruct, DataUnion, DeriveInput, Lit};
66

7+
type Converter = fn(&str) -> String;
8+
9+
fn case_converter(case: &syn::LitStr) -> syn::Result<Converter> {
10+
macro_rules! define_converter {
11+
(match $value:expr => {
12+
$( $case:pat => $converter:expr, )*
13+
}) => {
14+
match $value {
15+
$( $case => |txt: &str| $converter(txt).to_string(), )*
16+
_ => return Err(syn::Error::new_spanned(case, "unsupported case style")),
17+
}
18+
};
19+
}
20+
21+
let case = case.value();
22+
let converter = define_converter!(match case.as_str() => {
23+
"camelCase" => heck::AsLowerCamelCase,
24+
"snake_case" => heck::AsSnakeCase,
25+
"kebab-case" => heck::AsKebabCase,
26+
"SCREAMING_SNAKE_CASE" => heck::AsShoutySnakeCase,
27+
"SCREAMING-KEBAB-CASE" => heck::AsShoutyKebabCase,
28+
});
29+
30+
Ok(converter)
31+
}
32+
33+
fn ident_adapter(converter: Converter) -> impl Fn(&syn::Ident) -> syn::Ident {
34+
let adapter = move |ident: &syn::Ident| format_ident!("{}", converter(&ident.to_string()));
35+
Box::new(adapter)
36+
}
37+
738
struct SerdeContainerOptions {
839
rename_all: Option<syn::LitStr>,
940
untagged: bool,
@@ -140,13 +171,20 @@ pub struct ContainerMeta {
140171

141172
fn expand_enum(mut meta: ContainerMeta, input: DataEnum) -> syn::Result<TokenStream> {
142173
let crate_path = &meta.options.crate_path;
174+
let converter = ident_adapter(
175+
meta.serde_options
176+
.rename_all
177+
.as_ref()
178+
.map(case_converter)
179+
.unwrap_or_else(|| Ok(|txt: &str| txt.to_string()))?,
180+
);
143181

144182
let mut cases = Vec::new();
145183
for variant in input.variants.iter() {
146184
let value = match variant.fields {
147185
syn::Fields::Named(ref fields) => {
148186
let items = fields.named.iter().map(|field| {
149-
let name = field.ident.as_ref().unwrap();
187+
let name = converter(field.ident.as_ref().unwrap());
150188
let description = normalize_option(extract_documentation(&field.attrs)?);
151189
let field_ty = &field.ty;
152190

@@ -185,7 +223,7 @@ fn expand_enum(mut meta: ContainerMeta, input: DataEnum) -> syn::Result<TokenStr
185223
syn::Fields::Unit => quote! { #crate_path::EnumValue::Unit },
186224
};
187225

188-
let variant_name = &variant.ident;
226+
let variant_name = converter(&variant.ident);
189227
let description = normalize_option(extract_documentation(&variant.attrs)?);
190228

191229
let expanded = quote! {
@@ -214,7 +252,7 @@ fn expand_enum(mut meta: ContainerMeta, input: DataEnum) -> syn::Result<TokenStr
214252
impl #impl_generics #crate_path::Schemaifier for #name #ty_generics #where_clause {
215253
fn visit_schema(visitor: &mut #crate_path::SchemaVisitor) -> #crate_path::DefinitionReference {
216254
let node = #crate_path::Node {
217-
name: std::any::type_name::<Self>().into(),
255+
name: stringify!(#name).into(),
218256
description: #description,
219257
value: #crate_path::NodeType::Enum {
220258
discriminator: None,
@@ -231,6 +269,14 @@ fn expand_enum(mut meta: ContainerMeta, input: DataEnum) -> syn::Result<TokenStr
231269
}
232270

233271
fn expand_struct(mut meta: ContainerMeta, input: DataStruct) -> syn::Result<TokenStream> {
272+
let converter = ident_adapter(
273+
meta.serde_options
274+
.rename_all
275+
.as_ref()
276+
.map(case_converter)
277+
.unwrap_or_else(|| Ok(|txt: &str| txt.to_string()))?,
278+
);
279+
234280
let name = &meta.name;
235281
let description = normalize_option(meta.description.as_ref());
236282
let crate_path = &meta.options.crate_path;
@@ -249,7 +295,7 @@ fn expand_struct(mut meta: ContainerMeta, input: DataStruct) -> syn::Result<Toke
249295
let node_ty = match input.fields {
250296
syn::Fields::Named(named) => {
251297
let items = named.named.iter().map(|field| {
252-
let name = field.ident.as_ref().unwrap();
298+
let name = converter(field.ident.as_ref().unwrap());
253299
let description = normalize_option(extract_documentation(&field.attrs)?);
254300
let field_ty = &field.ty;
255301

@@ -297,7 +343,7 @@ fn expand_struct(mut meta: ContainerMeta, input: DataStruct) -> syn::Result<Toke
297343

298344
quote! {
299345
#crate_path::Node {
300-
name: std::any::type_name::<Self>().into(),
346+
name: stringify!(#name).into(),
301347
description: #description,
302348
value: #node_ty,
303349
}

packages/cw-schema/tests/derive.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ struct HelloWorld {
1212
/// Baz field!
1313
baz: Baz,
1414

15+
/// Quux field!
16+
quux: Quux,
17+
1518
/// Tuple field!
1619
tuple: (u32, u32),
1720
}
@@ -37,6 +40,14 @@ enum Baz {
3740
D(u32, u32),
3841
}
3942

43+
#[derive(Schemaifier)]
44+
#[serde(rename_all = "camelCase")]
45+
/// Quux struct!
46+
pub struct Quux {
47+
/// Quux field!
48+
quux_field: u32,
49+
}
50+
4051
#[test]
4152
fn snapshot_schema() {
4253
let schema = cw_schema::schema_of::<HelloWorld>();

packages/cw-schema/tests/snapshots/derive__snapshot_schema.snap

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ expression: schema
44
---
55
{
66
"type": "v1",
7-
"root": 6,
7+
"root": 7,
88
"definitions": [
99
{
1010
"name": "String",
@@ -17,7 +17,7 @@ expression: schema
1717
"signed": false
1818
},
1919
{
20-
"name": "derive::Bar",
20+
"name": "Bar",
2121
"description": "Bar struct!",
2222
"type": "struct",
2323
"properties": {
@@ -33,7 +33,7 @@ expression: schema
3333
"inner": 2
3434
},
3535
{
36-
"name": "derive::Baz",
36+
"name": "Baz",
3737
"description": "Baz enum!",
3838
"type": "enum",
3939
"cases": {
@@ -61,6 +61,17 @@ expression: schema
6161
}
6262
}
6363
},
64+
{
65+
"name": "Quux",
66+
"description": "Quux struct!",
67+
"type": "struct",
68+
"properties": {
69+
"quuxField": {
70+
"description": "Quux field!",
71+
"value": 1
72+
}
73+
}
74+
},
6475
{
6576
"name": "(u32, u32)",
6677
"type": "tuple",
@@ -70,7 +81,7 @@ expression: schema
7081
]
7182
},
7283
{
73-
"name": "derive::HelloWorld",
84+
"name": "HelloWorld",
7485
"description": "Hello world struct!",
7586
"type": "struct",
7687
"properties": {
@@ -86,9 +97,13 @@ expression: schema
8697
"description": "Name field!",
8798
"value": 0
8899
},
100+
"quux": {
101+
"description": "Quux field!",
102+
"value": 5
103+
},
89104
"tuple": {
90105
"description": "Tuple field!",
91-
"value": 5
106+
"value": 6
92107
}
93108
}
94109
}

0 commit comments

Comments
 (0)