Skip to content

Commit a390ac5

Browse files
authored
support parsing of docs parameter in account, argument, field directives (#69)
1 parent 215b1c3 commit a390ac5

File tree

5 files changed

+114
-8
lines changed

5 files changed

+114
-8
lines changed

codama-attributes/src/codama_directives/account_directive.rs

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ impl AccountDirective {
2727
let mut is_signer = SetOnce::<IsAccountSigner>::new("signer").initial_value(false.into());
2828
let mut is_optional = SetOnce::<bool>::new("optional").initial_value(false);
2929
let mut default_value = SetOnce::<InstructionInputValueNode>::new("default_value");
30+
let mut docs = SetOnce::<Docs>::new("docs");
3031
match meta.is_path_or_empty_list() {
3132
true => (),
3233
false => meta
@@ -40,6 +41,7 @@ impl AccountDirective {
4041
InstructionInputValueNode::from_meta(meta.as_value()?)?,
4142
meta,
4243
),
44+
"docs" => docs.set(Docs::from_meta(meta)?, meta),
4345
_ => Err(meta.error("unrecognized attribute")),
4446
})?,
4547
}
@@ -49,8 +51,7 @@ impl AccountDirective {
4951
is_writable: is_writable.take(meta)?,
5052
is_signer: is_signer.take(meta)?,
5153
is_optional: is_optional.take(meta)?,
52-
// TODO: `docs` for account directives not attached to fields.
53-
docs: Docs::default(),
54+
docs: docs.option().unwrap_or_default(),
5455
default_value: default_value.option(),
5556
},
5657
})
@@ -161,4 +162,51 @@ mod tests {
161162
let error = AccountDirective::parse(&meta, &ctx).unwrap_err();
162163
assert_eq!(error.to_string(), "name is missing");
163164
}
165+
166+
#[test]
167+
fn with_docs() {
168+
let meta: Meta = syn::parse_quote! { account(name = "stake", writable, docs = "what this account is for") };
169+
let item = syn::parse_quote! { struct Foo; };
170+
let ctx = AttributeContext::Item(&item);
171+
let directive = AccountDirective::parse(&meta, &ctx).unwrap();
172+
assert_eq!(
173+
directive,
174+
AccountDirective {
175+
account: InstructionAccountNode {
176+
name: "stake".into(),
177+
is_writable: true,
178+
is_signer: IsAccountSigner::False,
179+
is_optional: false,
180+
default_value: None,
181+
docs: vec!["what this account is for".to_string()].into(),
182+
},
183+
}
184+
);
185+
}
186+
187+
#[test]
188+
fn with_docs_array() {
189+
let meta: Meta = syn::parse_quote! { account(name = "authority", signer, docs = ["Line 1", "Line 2", "Line 3"]) };
190+
let item = syn::parse_quote! { struct Foo; };
191+
let ctx = AttributeContext::Item(&item);
192+
let directive = AccountDirective::parse(&meta, &ctx).unwrap();
193+
assert_eq!(
194+
directive,
195+
AccountDirective {
196+
account: InstructionAccountNode {
197+
name: "authority".into(),
198+
is_writable: false,
199+
is_signer: IsAccountSigner::True,
200+
is_optional: false,
201+
default_value: None,
202+
docs: vec![
203+
"Line 1".to_string(),
204+
"Line 2".to_string(),
205+
"Line 3".to_string()
206+
]
207+
.into(),
208+
},
209+
}
210+
);
211+
}
164212
}

codama-attributes/src/codama_directives/argument_directive.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{
44
Attribute, CodamaAttribute, CodamaDirective,
55
};
66
use codama_errors::CodamaError;
7-
use codama_nodes::{Docs, InstructionArgumentNode};
7+
use codama_nodes::InstructionArgumentNode;
88
use codama_syn_helpers::Meta;
99

1010
#[derive(Debug, PartialEq)]
@@ -30,7 +30,7 @@ impl ArgumentDirective {
3030
argument: InstructionArgumentNode {
3131
name: consumer.name.take(meta)?,
3232
r#type: consumer.r#type.take(meta)?,
33-
docs: Docs::default(),
33+
docs: consumer.docs.option().unwrap_or_default(),
3434
default_value,
3535
default_value_strategy,
3636
},
@@ -106,4 +106,21 @@ mod tests {
106106
}
107107
);
108108
}
109+
110+
#[test]
111+
fn with_docs_string() {
112+
let meta: Meta = syn::parse_quote! { argument("cake", number(u8), docs = "The cake") };
113+
let directive = ArgumentDirective::parse(&meta).unwrap();
114+
assert_eq!(directive.argument.docs, vec!["The cake".to_string()].into());
115+
}
116+
117+
#[test]
118+
fn with_docs_array() {
119+
let meta: Meta = syn::parse_quote! { argument("cake", number(u8), docs = ["The cake", "must be a lie"]) };
120+
let directive = ArgumentDirective::parse(&meta).unwrap();
121+
assert_eq!(
122+
directive.argument.docs,
123+
vec!["The cake".to_string(), "must be a lie".to_string()].into()
124+
);
125+
}
109126
}

codama-attributes/src/codama_directives/field_directive.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{
44
Attribute, CodamaAttribute, CodamaDirective,
55
};
66
use codama_errors::CodamaError;
7-
use codama_nodes::{Docs, StructFieldTypeNode};
7+
use codama_nodes::StructFieldTypeNode;
88
use codama_syn_helpers::Meta;
99

1010
#[derive(Debug, PartialEq)]
@@ -30,7 +30,7 @@ impl FieldDirective {
3030
field: StructFieldTypeNode {
3131
name: consumer.name.take(meta)?,
3232
r#type: consumer.r#type.take(meta)?,
33-
docs: Docs::default(),
33+
docs: consumer.docs.option().unwrap_or_default(),
3434
default_value,
3535
default_value_strategy,
3636
},
@@ -106,4 +106,21 @@ mod tests {
106106
}
107107
);
108108
}
109+
110+
#[test]
111+
fn with_docs_string() {
112+
let meta: Meta = syn::parse_quote! { field("splines", number(u8), docs = "Splines") };
113+
let directive = FieldDirective::parse(&meta).unwrap();
114+
assert_eq!(directive.field.docs, vec!["Splines".to_string()].into());
115+
}
116+
117+
#[test]
118+
fn with_docs_array() {
119+
let meta: Meta = syn::parse_quote! { field("age", number(u8), docs = ["Splines", "Must be pre-reticulated"]) };
120+
let directive = FieldDirective::parse(&meta).unwrap();
121+
assert_eq!(
122+
directive.field.docs,
123+
vec!["Splines".to_string(), "Must be pre-reticulated".to_string()].into()
124+
);
125+
}
109126
}

codama-attributes/src/codama_directives/type_nodes/struct_field_meta_consumer.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::{
33
DefaultValueDirective,
44
};
55
use codama_nodes::{
6-
CamelCaseString, DefaultValueStrategy, InstructionInputValueNode, TypeNode, ValueNode,
6+
CamelCaseString, DefaultValueStrategy, Docs, InstructionInputValueNode, TypeNode, ValueNode,
77
};
88
use codama_syn_helpers::{extensions::*, Meta};
99

@@ -13,6 +13,7 @@ pub(crate) struct StructFieldMetaConsumer {
1313
pub r#type: SetOnce<TypeNode>,
1414
pub default_value: SetOnce<DefaultValueDirective>,
1515
pub after: SetOnce<bool>,
16+
pub docs: SetOnce<Docs>,
1617
}
1718

1819
impl MetaConsumer for StructFieldMetaConsumer {
@@ -23,6 +24,7 @@ impl MetaConsumer for StructFieldMetaConsumer {
2324
r#type: SetOnce::new("type"),
2425
default_value: SetOnce::new("default_value"),
2526
after: SetOnce::new("after"),
27+
docs: SetOnce::new("docs"),
2628
}
2729
}
2830

@@ -48,6 +50,10 @@ impl StructFieldMetaConsumer {
4850
.set(TypeNode::from_meta(meta.as_value()?)?, meta)?;
4951
Ok(None)
5052
}
53+
"docs" => {
54+
this.docs.set(Docs::from_meta(&meta)?, meta)?;
55+
Ok(None)
56+
}
5157
_ => {
5258
if let Ok(value) = meta.as_expr().and_then(|e| e.as_string()) {
5359
this.name.set(value.into(), meta)?;

codama-attributes/src/utils/from_meta.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use codama_nodes::{BytesEncoding, IsAccountSigner};
1+
use codama_nodes::{BytesEncoding, Docs, IsAccountSigner};
22
use codama_syn_helpers::{extensions::*, Meta};
33
use syn::Expr;
44

@@ -44,3 +44,21 @@ impl FromMeta for BytesEncoding {
4444
Err(expr.error("expected one of: \"base16\", \"base58\", \"base64\", \"utf8\""))
4545
}
4646
}
47+
48+
impl FromMeta for Docs {
49+
fn from_meta(meta: &Meta) -> syn::Result<Self> {
50+
match meta {
51+
Meta::PathList(pl) if pl.eq_token.is_some() => {
52+
let strings: Vec<String> = pl
53+
.as_meta_list()
54+
.parse_comma_args::<syn::LitStr>()?
55+
.into_iter()
56+
.map(|lit| lit.value())
57+
.collect();
58+
Ok(strings.into())
59+
}
60+
Meta::PathValue(pv) => pv.value.as_expr()?.as_string().map(|s| vec![s].into()),
61+
_ => Err(meta.error("expected a string or array of strings")),
62+
}
63+
}
64+
}

0 commit comments

Comments
 (0)