Use doc comments instead of the doc attribute in the changelog examples (#273)
This commit is contained in:
parent
0f2a654471
commit
4ecf558066
6 changed files with 102 additions and 118 deletions
|
@ -57,13 +57,13 @@
|
|||
}
|
||||
|
||||
// New alternative syntax for field descriptions
|
||||
#[doc = "Description"]
|
||||
/// Description
|
||||
field my_field() -> { ... }
|
||||
|
||||
// New alternative syntax for argument descriptions
|
||||
field my_field(
|
||||
#[doc = "The number of starfish to be returned. \
|
||||
Can't be more than 100."]
|
||||
/// The number of starfish to be returned.
|
||||
/// Can't be more than 100.
|
||||
arg: i32,
|
||||
) -> {
|
||||
...
|
||||
|
@ -73,12 +73,11 @@
|
|||
//
|
||||
// Multiple docstrings will be collapsed into a single
|
||||
// description separated by newlines.
|
||||
#[doc = r#"
|
||||
This is my field.
|
||||
|
||||
Make sure not to flitz the bitlet.
|
||||
Flitzing without a bitlet has undefined behaviour.
|
||||
"]
|
||||
/// This is my field.
|
||||
///
|
||||
/// Make sure not to filtz the bitlet.
|
||||
/// Flitzing without a bitlet has undefined behaviour.
|
||||
///
|
||||
#[doc = my_consts::ADDED_IN_VERSION_XYZ]
|
||||
field my_field() -> { ... }
|
||||
```
|
||||
|
|
|
@ -677,7 +677,7 @@ macro_rules! __juniper_create_arg {
|
|||
$info,
|
||||
)
|
||||
$(.description($arg_description))*
|
||||
$(.push_docstring($arg_docstring))*
|
||||
.push_docstring(&[$($arg_docstring,)*])
|
||||
};
|
||||
|
||||
(
|
||||
|
@ -695,6 +695,6 @@ macro_rules! __juniper_create_arg {
|
|||
$info,
|
||||
)
|
||||
$(.description($arg_description))*
|
||||
$(.push_docstring($arg_docstring))*
|
||||
.push_docstring(&[$($arg_docstring,)*])
|
||||
};
|
||||
}
|
||||
|
|
|
@ -153,7 +153,7 @@ macro_rules! graphql_interface {
|
|||
info
|
||||
)
|
||||
$(.description($fn_description))*
|
||||
$(.push_docstring($docstring))*
|
||||
.push_docstring(&[$($docstring,)*])
|
||||
$(.deprecated($deprecated))*
|
||||
$(.argument(
|
||||
__juniper_create_arg!(
|
||||
|
|
|
@ -35,8 +35,11 @@ graphql_object!(User: () |&self| {
|
|||
|
||||
## Documentation and descriptions
|
||||
|
||||
You can optionally add descriptions to the type itself, the fields, and field
|
||||
arguments:
|
||||
You can optionally add descriptions to the type itself, the fields,
|
||||
and field arguments. For field and argument descriptions it is
|
||||
possible to use normal rustdoc comments or doc
|
||||
attributes. Alternatively the same syntax as for the type could be
|
||||
used
|
||||
|
||||
```rust
|
||||
# #[macro_use] extern crate juniper;
|
||||
|
@ -45,7 +48,9 @@ struct User { id: String, name: String, group_ids: Vec<String> }
|
|||
graphql_object!(User: () |&self| {
|
||||
description: "A user in the database"
|
||||
|
||||
field id() -> &String as "The user's unique identifier" {
|
||||
|
||||
/// The user's unique identifier
|
||||
field id() -> &String {
|
||||
&self.id
|
||||
}
|
||||
|
||||
|
@ -53,47 +58,11 @@ graphql_object!(User: () |&self| {
|
|||
&self.name
|
||||
}
|
||||
|
||||
#[doc = "Test if a user is member of a group"]
|
||||
field member_of_group(
|
||||
group_id: String as "The group id you want to test membership against"
|
||||
) -> bool as "Test if a user is member of a group" {
|
||||
self.group_ids.iter().any(|gid| gid == &group_id)
|
||||
}
|
||||
});
|
||||
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
**Alternatively,** descriptions can be added with the builtin `doc` attribute.
|
||||
Consecutive `#[doc = "..."]` attributes will be collapsed into a single description
|
||||
where the docstrings are separated by newlines.
|
||||
|
||||
```rust
|
||||
# #[macro_use] extern crate juniper;
|
||||
struct User { id: String, name: String, group_ids: Vec<String> }
|
||||
|
||||
graphql_object!(User: () |&self| {
|
||||
description: "A user in the database"
|
||||
|
||||
#[doc = "The user's unique identifier"]
|
||||
field id() -> &String {
|
||||
&self.id
|
||||
}
|
||||
|
||||
#[doc = "The user's name"]
|
||||
field name() -> &String {
|
||||
&self.name
|
||||
}
|
||||
|
||||
#[doc = r#"
|
||||
Test if a user is member of a group.
|
||||
|
||||
This may return a flitzbit if the floop is twizled.
|
||||
Make sure not to rumblejumble the cog-rotater.
|
||||
"#]
|
||||
#[doc = "Added in vX.Y.44"]
|
||||
field member_of_group(
|
||||
#[doc = "The group id you want to test membership against"]
|
||||
group_id: String,
|
||||
/// The group id you want to test membership against
|
||||
/// second line
|
||||
group_id: String
|
||||
) -> bool {
|
||||
self.group_ids.iter().any(|gid| gid == &group_id)
|
||||
}
|
||||
|
@ -275,16 +244,19 @@ A field's description and deprecation can also be set using the
|
|||
builtin `doc` and `deprecated` attributes.
|
||||
|
||||
```text
|
||||
#[doc = "Field description"]
|
||||
/// Field description
|
||||
field name(args...) -> Type { }
|
||||
|
||||
#[doc = "Field description"]
|
||||
field name(args...) -> Type {}
|
||||
|
||||
#[deprecated] // no reason required
|
||||
field name(args...) -> Type { }
|
||||
|
||||
#[deprecated(note = "Reason")]
|
||||
field name(args...) -> Type { }
|
||||
|
||||
#[doc = "Field description"]
|
||||
/// Field description
|
||||
#[deprecated(note = "Reason")] // deprecated must come after doc
|
||||
field deprecated "Reason" name(args...) -> Type { }
|
||||
```
|
||||
|
@ -326,9 +298,11 @@ arg_name = (Point { x: 1, y: 2 }): Point
|
|||
arg_name = ("default".to_owned()): String
|
||||
```
|
||||
|
||||
A description can also be provided using the builtin `doc` attribute.
|
||||
A description can also be provided using normal doc comments or doc attributes.
|
||||
|
||||
```text
|
||||
/// Argument description
|
||||
arg_name: ArgType
|
||||
#[doc = "Argument description"]
|
||||
arg_name: ArgType
|
||||
```
|
||||
|
@ -391,7 +365,7 @@ macro_rules! graphql_object {
|
|||
info
|
||||
)
|
||||
$(.description($fn_description))*
|
||||
$(.push_docstring($docstring))*
|
||||
.push_docstring(&[$($docstring,)*])
|
||||
$(.deprecated($deprecated))*
|
||||
$(.argument(
|
||||
__juniper_create_arg!(
|
||||
|
|
|
@ -31,19 +31,18 @@ graphql_object!(Root: () |&self| {
|
|||
field deprecated "Deprecation reason"
|
||||
deprecated_descr() -> i32 as "Field description" { 0 }
|
||||
|
||||
#[doc = "Field description"]
|
||||
/// Field description
|
||||
field attr_description() -> i32 { 0 }
|
||||
|
||||
#[doc = "Field description"]
|
||||
#[doc = "with `collapse_docs` behavior"] // https://doc.rust-lang.org/rustdoc/the-doc-attribute.html
|
||||
/// Field description
|
||||
/// with `collapse_docs` behavior
|
||||
field attr_description_collapse() -> i32 { 0 }
|
||||
|
||||
#[doc = r#"
|
||||
Get the i32 representation of 0.
|
||||
|
||||
- This comment is longer.
|
||||
- These two lines are rendered as bullets by GraphiQL.
|
||||
"#]
|
||||
/// Get the i32 representation of 0.
|
||||
///
|
||||
/// - This comment is longer.
|
||||
/// - These two lines are rendered as bullets by GraphiQL.
|
||||
/// - subsection
|
||||
field attr_description_long() -> i32 { 0 }
|
||||
|
||||
#[deprecated]
|
||||
|
@ -52,7 +51,7 @@ graphql_object!(Root: () |&self| {
|
|||
#[deprecated(note = "Deprecation reason")]
|
||||
field attr_deprecated_reason() -> i32 { 0 }
|
||||
|
||||
#[doc = "Field description"]
|
||||
/// Field description
|
||||
#[deprecated(note = "Deprecation reason")]
|
||||
field attr_deprecated_descr() -> i32 { 0 }
|
||||
|
||||
|
@ -76,19 +75,17 @@ graphql_interface!(Interface: () |&self| {
|
|||
field deprecated "Deprecation reason"
|
||||
deprecated_descr() -> i32 as "Field description" { 0 }
|
||||
|
||||
#[doc = "Field description"]
|
||||
/// Field description
|
||||
field attr_description() -> i32 { 0 }
|
||||
|
||||
#[doc = "Field description"]
|
||||
#[doc = "with `collapse_docs` behavior"] // https://doc.rust-lang.org/rustdoc/the-doc-attribute.html
|
||||
/// Field description
|
||||
/// with `collapse_docs` behavior
|
||||
field attr_description_collapse() -> i32 { 0 }
|
||||
|
||||
#[doc = r#"
|
||||
Get the i32 representation of 0.
|
||||
|
||||
- This comment is longer.
|
||||
- These two lines are rendered as bullets by GraphiQL.
|
||||
"#]
|
||||
/// Get the i32 representation of 0.
|
||||
///
|
||||
/// - This comment is longer.
|
||||
/// - These two lines are rendered as bullets by GraphiQL.
|
||||
field attr_description_long() -> i32 { 0 }
|
||||
|
||||
#[deprecated]
|
||||
|
@ -97,7 +94,7 @@ graphql_interface!(Interface: () |&self| {
|
|||
#[deprecated(note = "Deprecation reason")]
|
||||
field attr_deprecated_reason() -> i32 { 0 }
|
||||
|
||||
#[doc = "Field description"]
|
||||
/// Field description
|
||||
#[deprecated(note = "Deprecation reason")]
|
||||
field attr_deprecated_descr() -> i32 { 0 }
|
||||
|
||||
|
@ -384,7 +381,7 @@ fn introspect_object_field_attr_description_long() {
|
|||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("description"),
|
||||
Some(&Value::scalar("Get the i32 representation of 0.\n\n- This comment is longer.\n- These two lines are rendered as bullets by GraphiQL."))
|
||||
Some(&Value::scalar("Get the i32 representation of 0.\n\n- This comment is longer.\n- These two lines are rendered as bullets by GraphiQL.\n - subsection"))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("isDeprecated"),
|
||||
|
|
|
@ -613,15 +613,16 @@ impl<'a, S> Field<'a, S> {
|
|||
///
|
||||
/// If the description hasn't been set, the description is set to the provided line.
|
||||
/// Otherwise, the doc string is added to the current description after a newline.
|
||||
pub fn push_docstring(mut self, multiline: &str) -> Field<'a, S> {
|
||||
let docstring = clean_docstring(multiline);
|
||||
match &mut self.description {
|
||||
&mut Some(ref mut desc) => {
|
||||
desc.push('\n');
|
||||
desc.push_str(&docstring);
|
||||
}
|
||||
desc @ &mut None => {
|
||||
*desc = Some(docstring.to_string());
|
||||
pub fn push_docstring(mut self, multiline: &[&str]) -> Field<'a, S> {
|
||||
if let Some(docstring) = clean_docstring(multiline) {
|
||||
match &mut self.description {
|
||||
&mut Some(ref mut desc) => {
|
||||
desc.push('\n');
|
||||
desc.push_str(&docstring);
|
||||
}
|
||||
desc @ &mut None => {
|
||||
*desc = Some(docstring);
|
||||
}
|
||||
}
|
||||
}
|
||||
self
|
||||
|
@ -679,15 +680,16 @@ impl<'a, S> Argument<'a, S> {
|
|||
///
|
||||
/// If the description hasn't been set, the description is set to the provided line.
|
||||
/// Otherwise, the doc string is added to the current description after a newline.
|
||||
pub fn push_docstring(mut self, multiline: &str) -> Argument<'a, S> {
|
||||
let docstring = clean_docstring(multiline);
|
||||
match &mut self.description {
|
||||
&mut Some(ref mut desc) => {
|
||||
desc.push('\n');
|
||||
desc.push_str(&docstring);
|
||||
}
|
||||
desc @ &mut None => {
|
||||
*desc = Some(docstring.to_string());
|
||||
pub fn push_docstring(mut self, multiline: &[&str]) -> Argument<'a, S> {
|
||||
if let Some(docstring) = clean_docstring(multiline) {
|
||||
match &mut self.description {
|
||||
&mut Some(ref mut desc) => {
|
||||
desc.push('\n');
|
||||
desc.push_str(&docstring);
|
||||
}
|
||||
desc @ &mut None => {
|
||||
*desc = Some(docstring)
|
||||
}
|
||||
}
|
||||
}
|
||||
self
|
||||
|
@ -766,26 +768,38 @@ where
|
|||
<T as FromInputValue<S>>::from_input_value(v).is_some()
|
||||
}
|
||||
|
||||
fn clean_docstring<'a>(multiline: &'a str) -> Cow<'a, str> {
|
||||
let trim_start = multiline.split('\n')
|
||||
.skip(1)
|
||||
.filter_map(|ln| ln.chars().position(|ch| ch != ' ' && ch != '\t'))
|
||||
.min();
|
||||
if let Some(trim) = trim_start {
|
||||
let trimmed = multiline
|
||||
.split('\n')
|
||||
.map(|ln| {
|
||||
if !ln.starts_with(' ') && !ln.starts_with('\t') {
|
||||
ln // skip trimming the first line
|
||||
} else if ln.len() >= trim {
|
||||
&ln[trim..]
|
||||
fn clean_docstring(multiline: &[&str]) -> Option<String> {
|
||||
if multiline.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let trim_start = multiline
|
||||
.iter()
|
||||
.filter_map(|ln| ln.chars().position(|ch| !ch.is_whitespace()))
|
||||
.min()
|
||||
.unwrap_or(0);
|
||||
Some(
|
||||
multiline
|
||||
.iter()
|
||||
.enumerate()
|
||||
.flat_map(|(line, ln)| {
|
||||
let new_ln = if !ln
|
||||
.chars()
|
||||
.next()
|
||||
.map(|ch| ch.is_whitespace())
|
||||
.unwrap_or(false)
|
||||
{
|
||||
ln.trim_end() // skip trimming the first line
|
||||
} else if ln.len() >= trim_start {
|
||||
&ln[trim_start..].trim_end()
|
||||
} else {
|
||||
""
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
Cow::from(trimmed.join("\n").trim_matches('\n').to_owned())
|
||||
} else {
|
||||
Cow::from(multiline.trim_matches('\n'))
|
||||
}
|
||||
};
|
||||
new_ln.chars().chain(
|
||||
['\n']
|
||||
.iter()
|
||||
.take_while(move |_| line < multiline.len() - 1)
|
||||
.cloned(),
|
||||
)
|
||||
}).collect::<String>(),
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue