Infer graphql "deprecation" from #[deprecated(note = "...")] in derive (and macros) (#269)
* Update object/iface macro with doc/deprecated attrs for fields * Use the note from `#[deprecated]` by default in derived GraphQLType * Update to support multiline raw-docstring format * Support bare deprecated attribute * Update arguments to support #[doc] for parity with previous ` as ` syntax
This commit is contained in:
parent
f61fdb2063
commit
0f2a654471
13 changed files with 804 additions and 49 deletions
|
@ -14,3 +14,73 @@
|
||||||
generic code. To retain the current behaviour use `DefaultScalarValue` as scalar value type
|
generic code. To retain the current behaviour use `DefaultScalarValue` as scalar value type
|
||||||
|
|
||||||
[#251](https://github.com/graphql-rust/juniper/pull/251)
|
[#251](https://github.com/graphql-rust/juniper/pull/251)
|
||||||
|
|
||||||
|
- The `GraphQLObject` and `GraphQLEnum` derives will mark graphql fields as
|
||||||
|
`@deprecated` when struct fields or enum variants are marked with the
|
||||||
|
builtin `#[deprecated]` attribute.
|
||||||
|
|
||||||
|
The deprecation reason can be set using the `note = ...` meta item
|
||||||
|
(e.g. `#[deprecated(note = "Replaced by betterField")]`).
|
||||||
|
The `since` attribute is ignored.
|
||||||
|
|
||||||
|
[#269](https://github.com/graphql-rust/juniper/pull/269)
|
||||||
|
|
||||||
|
|
||||||
|
- There is an alternative syntax for setting a field's _description_ and
|
||||||
|
_deprecation reason_ in the `graphql_object!` and `graphql_interface!` macros.
|
||||||
|
|
||||||
|
To __deprecate__ a graphql field:
|
||||||
|
```rust
|
||||||
|
// Original syntax for setting deprecation reason
|
||||||
|
field deprecated "Reason" my_field() -> { ... }
|
||||||
|
|
||||||
|
// New alternative syntax for deprecation reason.
|
||||||
|
#[deprecated(note = "Reason")]
|
||||||
|
field my_field() -> { ... }
|
||||||
|
|
||||||
|
// You can now also deprecate without a reason.
|
||||||
|
#[deprecated]
|
||||||
|
field my_field() -> { ... }
|
||||||
|
```
|
||||||
|
|
||||||
|
To set the __description__ of a graphql field:
|
||||||
|
```rust
|
||||||
|
// Original syntax for field descriptions
|
||||||
|
field my_field() as "Description" -> { ... }
|
||||||
|
|
||||||
|
// Original syntax for argument descriptions
|
||||||
|
field my_field(
|
||||||
|
floops: i32 as "The number of starfish to be returned. \
|
||||||
|
Can't be more than 100.",
|
||||||
|
) -> {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
// New alternative syntax for field descriptions
|
||||||
|
#[doc = "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."]
|
||||||
|
arg: i32,
|
||||||
|
) -> {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
// You can also use raw strings and const &'static str.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
"]
|
||||||
|
#[doc = my_consts::ADDED_IN_VERSION_XYZ]
|
||||||
|
field my_field() -> { ... }
|
||||||
|
```
|
||||||
|
|
||||||
|
[#269](https://github.com/graphql-rust/juniper/pull/269)
|
||||||
|
|
|
@ -15,8 +15,8 @@ use value::Value;
|
||||||
use GraphQLError;
|
use GraphQLError;
|
||||||
|
|
||||||
use schema::meta::{
|
use schema::meta::{
|
||||||
Argument, EnumMeta, EnumValue, Field, InputObjectMeta, InterfaceMeta, ListMeta, MetaType,
|
Argument, DeprecationStatus, EnumMeta, EnumValue, Field, InputObjectMeta, InterfaceMeta,
|
||||||
NullableMeta, ObjectMeta, PlaceholderMeta, ScalarMeta, UnionMeta,
|
ListMeta, MetaType, NullableMeta, ObjectMeta, PlaceholderMeta, ScalarMeta, UnionMeta,
|
||||||
};
|
};
|
||||||
use schema::model::{RootNode, SchemaType, TypeType};
|
use schema::model::{RootNode, SchemaType, TypeType};
|
||||||
|
|
||||||
|
@ -729,7 +729,7 @@ where
|
||||||
description: None,
|
description: None,
|
||||||
arguments: None,
|
arguments: None,
|
||||||
field_type: self.get_type::<T>(info),
|
field_type: self.get_type::<T>(info),
|
||||||
deprecation_reason: None,
|
deprecation_status: DeprecationStatus::Current,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -748,7 +748,7 @@ where
|
||||||
description: None,
|
description: None,
|
||||||
arguments: None,
|
arguments: None,
|
||||||
field_type: self.get_type::<I>(info),
|
field_type: self.get_type::<I>(info),
|
||||||
deprecation_reason: None,
|
deprecation_status: DeprecationStatus::Current,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -398,7 +398,76 @@ macro_rules! __juniper_parse_field_list {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
(
|
||||||
|
success_callback = $success_callback: ident,
|
||||||
|
additional_parser = {$($additional:tt)*},
|
||||||
|
meta = {$($meta:tt)*},
|
||||||
|
items = [$({$($items: tt)*},)*],
|
||||||
|
rest = $(#[doc = $desc: tt])*
|
||||||
|
#[deprecated $(( $(since = $since: tt,)* note = $reason: tt ))* ]
|
||||||
|
field $name: ident (
|
||||||
|
$(&$executor: tt)* $(,)*
|
||||||
|
$($(#[doc = $arg_desc: expr])* $arg_name:ident $(= $arg_default: tt)* : $arg_ty: ty),* $(,)*
|
||||||
|
) -> $return_ty: ty $body: block
|
||||||
|
$($rest:tt)*
|
||||||
|
) => {
|
||||||
|
__juniper_parse_field_list!(
|
||||||
|
success_callback = $success_callback,
|
||||||
|
additional_parser = {$($additional)*},
|
||||||
|
meta = {$($meta)*},
|
||||||
|
items = [$({$($items)*},)* {
|
||||||
|
name = $name,
|
||||||
|
body = $body,
|
||||||
|
return_ty = $return_ty,
|
||||||
|
args = [
|
||||||
|
$({
|
||||||
|
arg_name = $arg_name,
|
||||||
|
arg_ty = $arg_ty,
|
||||||
|
$(arg_default = $arg_default,)*
|
||||||
|
$(arg_docstring = $arg_desc,)*
|
||||||
|
},)*
|
||||||
|
],
|
||||||
|
$(docstring = $desc,)*
|
||||||
|
deprecated = None$(.unwrap_or(Some($reason)))*,
|
||||||
|
$(executor_var = $executor,)*
|
||||||
|
},],
|
||||||
|
rest = $($rest)*
|
||||||
|
);
|
||||||
|
};
|
||||||
|
(
|
||||||
|
success_callback = $success_callback: ident,
|
||||||
|
additional_parser = {$($additional:tt)*},
|
||||||
|
meta = {$($meta:tt)*},
|
||||||
|
items = [$({$($items: tt)*},)*],
|
||||||
|
rest = $(#[doc = $desc: tt])*
|
||||||
|
field $name: ident (
|
||||||
|
$(&$executor: ident)* $(,)*
|
||||||
|
$($(#[doc = $arg_desc: expr])* $arg_name:ident $(= $arg_default: tt)* : $arg_ty: ty),* $(,)*
|
||||||
|
) -> $return_ty: ty $body: block
|
||||||
|
$($rest:tt)*
|
||||||
|
) => {
|
||||||
|
__juniper_parse_field_list!(
|
||||||
|
success_callback = $success_callback,
|
||||||
|
additional_parser = {$($additional)*},
|
||||||
|
meta = {$($meta)*},
|
||||||
|
items = [$({$($items)*},)* {
|
||||||
|
name = $name,
|
||||||
|
body = $body,
|
||||||
|
return_ty = $return_ty,
|
||||||
|
args = [
|
||||||
|
$({
|
||||||
|
arg_name = $arg_name,
|
||||||
|
arg_ty = $arg_ty,
|
||||||
|
$(arg_default = $arg_default,)*
|
||||||
|
$(arg_docstring = $arg_desc,)*
|
||||||
|
},)*
|
||||||
|
],
|
||||||
|
$(docstring = $desc,)*
|
||||||
|
$(executor_var = $executor,)*
|
||||||
|
},],
|
||||||
|
rest = $($rest)*
|
||||||
|
);
|
||||||
|
};
|
||||||
(
|
(
|
||||||
success_callback = $success_callback: ident,
|
success_callback = $success_callback: ident,
|
||||||
additional_parser = {$($additional:tt)*},
|
additional_parser = {$($additional:tt)*},
|
||||||
|
@ -406,7 +475,7 @@ macro_rules! __juniper_parse_field_list {
|
||||||
items = [$({$($items: tt)*},)*],
|
items = [$({$($items: tt)*},)*],
|
||||||
rest = field deprecated $reason:tt $name: ident (
|
rest = field deprecated $reason:tt $name: ident (
|
||||||
$(&$executor: tt)* $(,)*
|
$(&$executor: tt)* $(,)*
|
||||||
$($arg_name:ident $(= $default_value: tt)* : $arg_ty: ty $(as $arg_des: expr)*),* $(,)*
|
$($arg_name:ident $(= $arg_default: tt)* : $arg_ty: ty $(as $arg_desc: expr)*),* $(,)*
|
||||||
) -> $return_ty: ty $(as $desc: tt)* $body: block
|
) -> $return_ty: ty $(as $desc: tt)* $body: block
|
||||||
$($rest:tt)*
|
$($rest:tt)*
|
||||||
) => {
|
) => {
|
||||||
|
@ -422,12 +491,12 @@ macro_rules! __juniper_parse_field_list {
|
||||||
$({
|
$({
|
||||||
arg_name = $arg_name,
|
arg_name = $arg_name,
|
||||||
arg_ty = $arg_ty,
|
arg_ty = $arg_ty,
|
||||||
|
$(arg_default = $arg_default,)*
|
||||||
$(arg_description = $arg_desc,)*
|
$(arg_description = $arg_desc,)*
|
||||||
$(arg_default = $default_value,)*
|
|
||||||
},)*
|
},)*
|
||||||
],
|
],
|
||||||
$(decs = $desc,)*
|
$(decs = $desc,)*
|
||||||
deprecated = $reason,
|
deprecated = Some($reason),
|
||||||
$(executor_var = $executor,)*
|
$(executor_var = $executor,)*
|
||||||
},],
|
},],
|
||||||
rest = $($rest)*
|
rest = $($rest)*
|
||||||
|
@ -440,7 +509,7 @@ macro_rules! __juniper_parse_field_list {
|
||||||
items = [$({$($items: tt)*},)*],
|
items = [$({$($items: tt)*},)*],
|
||||||
rest = field $name: ident (
|
rest = field $name: ident (
|
||||||
$(&$executor: ident)* $(,)*
|
$(&$executor: ident)* $(,)*
|
||||||
$($arg_name:ident $(= $default_value: tt)* : $arg_ty: ty $(as $arg_desc: expr)*),* $(,)*
|
$($arg_name:ident $(= $arg_default: tt)* : $arg_ty: ty $(as $arg_desc: expr)*),* $(,)*
|
||||||
) -> $return_ty: ty $(as $desc: tt)* $body: block
|
) -> $return_ty: ty $(as $desc: tt)* $body: block
|
||||||
$($rest:tt)*
|
$($rest:tt)*
|
||||||
) => {
|
) => {
|
||||||
|
@ -456,8 +525,8 @@ macro_rules! __juniper_parse_field_list {
|
||||||
$({
|
$({
|
||||||
arg_name = $arg_name,
|
arg_name = $arg_name,
|
||||||
arg_ty = $arg_ty,
|
arg_ty = $arg_ty,
|
||||||
|
$(arg_default = $arg_default,)*
|
||||||
$(arg_description = $arg_desc,)*
|
$(arg_description = $arg_desc,)*
|
||||||
$(arg_default = $default_value,)*
|
|
||||||
},)*
|
},)*
|
||||||
],
|
],
|
||||||
$(decs = $desc,)*
|
$(decs = $desc,)*
|
||||||
|
@ -601,12 +670,14 @@ macro_rules! __juniper_create_arg {
|
||||||
arg_ty = $arg_ty: ty,
|
arg_ty = $arg_ty: ty,
|
||||||
arg_name = $arg_name: ident,
|
arg_name = $arg_name: ident,
|
||||||
$(description = $arg_description: expr,)*
|
$(description = $arg_description: expr,)*
|
||||||
|
$(docstring = $arg_docstring: expr,)*
|
||||||
) => {
|
) => {
|
||||||
$reg.arg::<$arg_ty>(
|
$reg.arg::<$arg_ty>(
|
||||||
&$crate::to_camel_case(stringify!($arg_name)),
|
&$crate::to_camel_case(stringify!($arg_name)),
|
||||||
$info,
|
$info,
|
||||||
)
|
)
|
||||||
$(.description($arg_description))*
|
$(.description($arg_description))*
|
||||||
|
$(.push_docstring($arg_docstring))*
|
||||||
};
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
|
@ -614,8 +685,9 @@ macro_rules! __juniper_create_arg {
|
||||||
info = $info: ident,
|
info = $info: ident,
|
||||||
arg_ty = $arg_ty: ty,
|
arg_ty = $arg_ty: ty,
|
||||||
arg_name = $arg_name: ident,
|
arg_name = $arg_name: ident,
|
||||||
$(description = $arg_description: expr,)*
|
|
||||||
default = $arg_default: expr,
|
default = $arg_default: expr,
|
||||||
|
$(description = $arg_description: expr,)*
|
||||||
|
$(docstring = $arg_docstring: expr,)*
|
||||||
) => {
|
) => {
|
||||||
$reg.arg_with_default::<$arg_ty>(
|
$reg.arg_with_default::<$arg_ty>(
|
||||||
&$crate::to_camel_case(stringify!($arg_name)),
|
&$crate::to_camel_case(stringify!($arg_name)),
|
||||||
|
@ -623,5 +695,6 @@ macro_rules! __juniper_create_arg {
|
||||||
$info,
|
$info,
|
||||||
)
|
)
|
||||||
$(.description($arg_description))*
|
$(.description($arg_description))*
|
||||||
|
$(.push_docstring($arg_docstring))*
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,10 +117,12 @@ macro_rules! graphql_interface {
|
||||||
args = [$({
|
args = [$({
|
||||||
arg_name = $arg_name : ident,
|
arg_name = $arg_name : ident,
|
||||||
arg_ty = $arg_ty: ty,
|
arg_ty = $arg_ty: ty,
|
||||||
$(arg_description = $arg_description: expr,)*
|
|
||||||
$(arg_default = $arg_default: expr,)*
|
$(arg_default = $arg_default: expr,)*
|
||||||
|
$(arg_description = $arg_description: expr,)*
|
||||||
|
$(arg_docstring = $arg_docstring: expr,)*
|
||||||
},)*],
|
},)*],
|
||||||
$(decs = $fn_description: expr,)*
|
$(decs = $fn_description: expr,)*
|
||||||
|
$(docstring = $docstring: expr,)*
|
||||||
$(deprecated = $deprecated: expr,)*
|
$(deprecated = $deprecated: expr,)*
|
||||||
$(executor_var = $executor: ident,)*
|
$(executor_var = $executor: ident,)*
|
||||||
},)*],
|
},)*],
|
||||||
|
@ -151,6 +153,7 @@ macro_rules! graphql_interface {
|
||||||
info
|
info
|
||||||
)
|
)
|
||||||
$(.description($fn_description))*
|
$(.description($fn_description))*
|
||||||
|
$(.push_docstring($docstring))*
|
||||||
$(.deprecated($deprecated))*
|
$(.deprecated($deprecated))*
|
||||||
$(.argument(
|
$(.argument(
|
||||||
__juniper_create_arg!(
|
__juniper_create_arg!(
|
||||||
|
@ -158,8 +161,9 @@ macro_rules! graphql_interface {
|
||||||
info = info,
|
info = info,
|
||||||
arg_ty = $arg_ty,
|
arg_ty = $arg_ty,
|
||||||
arg_name = $arg_name,
|
arg_name = $arg_name,
|
||||||
$(description = $arg_description,)*
|
|
||||||
$(default = $arg_default,)*
|
$(default = $arg_default,)*
|
||||||
|
$(description = $arg_description,)*
|
||||||
|
$(docstring = $arg_docstring,)*
|
||||||
)
|
)
|
||||||
))*,
|
))*,
|
||||||
)*];
|
)*];
|
||||||
|
|
|
@ -63,6 +63,45 @@ graphql_object!(User: () |&self| {
|
||||||
# fn main() { }
|
# 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,
|
||||||
|
) -> bool {
|
||||||
|
self.group_ids.iter().any(|gid| gid == &group_id)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
# fn main() { }
|
||||||
|
```
|
||||||
|
|
||||||
## Generics and lifetimes
|
## Generics and lifetimes
|
||||||
|
|
||||||
You can expose generic or pointer types by prefixing the type with the necessary
|
You can expose generic or pointer types by prefixing the type with the necessary
|
||||||
|
@ -232,6 +271,24 @@ Defines a field on the object. The name is converted to camel case, e.g.
|
||||||
`user_name` is exposed as `userName`. The `as "Field description"` adds the
|
`user_name` is exposed as `userName`. The `as "Field description"` adds the
|
||||||
string as documentation on the field.
|
string as documentation on the field.
|
||||||
|
|
||||||
|
A field's description and deprecation can also be set using the
|
||||||
|
builtin `doc` and `deprecated` attributes.
|
||||||
|
|
||||||
|
```text
|
||||||
|
#[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"]
|
||||||
|
#[deprecated(note = "Reason")] // deprecated must come after doc
|
||||||
|
field deprecated "Reason" name(args...) -> Type { }
|
||||||
|
```
|
||||||
|
|
||||||
### Field arguments
|
### Field arguments
|
||||||
|
|
||||||
```text
|
```text
|
||||||
|
@ -269,6 +326,13 @@ arg_name = (Point { x: 1, y: 2 }): Point
|
||||||
arg_name = ("default".to_owned()): String
|
arg_name = ("default".to_owned()): String
|
||||||
```
|
```
|
||||||
|
|
||||||
|
A description can also be provided using the builtin `doc` attribute.
|
||||||
|
|
||||||
|
```text
|
||||||
|
#[doc = "Argument description"]
|
||||||
|
arg_name: ArgType
|
||||||
|
```
|
||||||
|
|
||||||
[1]: struct.Executor.html
|
[1]: struct.Executor.html
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
@ -295,10 +359,12 @@ macro_rules! graphql_object {
|
||||||
args = [$({
|
args = [$({
|
||||||
arg_name = $arg_name : ident,
|
arg_name = $arg_name : ident,
|
||||||
arg_ty = $arg_ty: ty,
|
arg_ty = $arg_ty: ty,
|
||||||
$(arg_description = $arg_description: expr,)*
|
|
||||||
$(arg_default = $arg_default: expr,)*
|
$(arg_default = $arg_default: expr,)*
|
||||||
|
$(arg_description = $arg_description: expr,)*
|
||||||
|
$(arg_docstring = $arg_docstring: expr,)*
|
||||||
},)*],
|
},)*],
|
||||||
$(decs = $fn_description: expr,)*
|
$(decs = $fn_description: expr,)*
|
||||||
|
$(docstring = $docstring: expr,)*
|
||||||
$(deprecated = $deprecated: expr,)*
|
$(deprecated = $deprecated: expr,)*
|
||||||
$(executor_var = $executor: ident,)*
|
$(executor_var = $executor: ident,)*
|
||||||
},)*],
|
},)*],
|
||||||
|
@ -325,6 +391,7 @@ macro_rules! graphql_object {
|
||||||
info
|
info
|
||||||
)
|
)
|
||||||
$(.description($fn_description))*
|
$(.description($fn_description))*
|
||||||
|
$(.push_docstring($docstring))*
|
||||||
$(.deprecated($deprecated))*
|
$(.deprecated($deprecated))*
|
||||||
$(.argument(
|
$(.argument(
|
||||||
__juniper_create_arg!(
|
__juniper_create_arg!(
|
||||||
|
@ -332,8 +399,9 @@ macro_rules! graphql_object {
|
||||||
info = info,
|
info = info,
|
||||||
arg_ty = $arg_ty,
|
arg_ty = $arg_ty,
|
||||||
arg_name = $arg_name,
|
arg_name = $arg_name,
|
||||||
$(description = $arg_description,)*
|
|
||||||
$(default = $arg_default,)*
|
$(default = $arg_default,)*
|
||||||
|
$(description = $arg_description,)*
|
||||||
|
$(docstring = $arg_docstring,)*
|
||||||
)
|
)
|
||||||
))*,
|
))*,
|
||||||
)*];
|
)*];
|
||||||
|
|
|
@ -49,6 +49,13 @@ graphql_object!(Root: () |&self| {
|
||||||
arg2: i32 as "The second arg",
|
arg2: i32 as "The second arg",
|
||||||
) -> i32 { 0 }
|
) -> i32 { 0 }
|
||||||
|
|
||||||
|
field attr_arg_descr(#[doc = "The arg"] arg: i32) -> i32 { 0 }
|
||||||
|
field attr_arg_descr_collapse(
|
||||||
|
#[doc = "The arg"]
|
||||||
|
#[doc = "and more details"]
|
||||||
|
arg: i32,
|
||||||
|
) -> i32 { 0 }
|
||||||
|
|
||||||
field arg_with_default(arg = 123: i32) -> i32 { 0 }
|
field arg_with_default(arg = 123: i32) -> i32 { 0 }
|
||||||
field multi_args_with_default(
|
field multi_args_with_default(
|
||||||
arg1 = 123: i32,
|
arg1 = 123: i32,
|
||||||
|
@ -499,6 +506,72 @@ fn introspect_field_multi_args_descr_trailing_comma() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn introspect_field_attr_arg_descr() {
|
||||||
|
run_args_info_query("attrArgDescr", |args| {
|
||||||
|
assert_eq!(args.len(), 1);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
args.contains(&Value::object(
|
||||||
|
vec![
|
||||||
|
("name", Value::scalar("arg")),
|
||||||
|
("description", Value::scalar("The arg")),
|
||||||
|
("defaultValue", Value::null()),
|
||||||
|
(
|
||||||
|
"type",
|
||||||
|
Value::object(
|
||||||
|
vec![
|
||||||
|
("name", Value::null()),
|
||||||
|
(
|
||||||
|
"ofType",
|
||||||
|
Value::object(
|
||||||
|
vec![("name", Value::scalar("Int"))].into_iter().collect(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].into_iter()
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].into_iter()
|
||||||
|
.collect(),
|
||||||
|
))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn introspect_field_attr_arg_descr_collapse() {
|
||||||
|
run_args_info_query("attrArgDescrCollapse", |args| {
|
||||||
|
assert_eq!(args.len(), 1);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
args.contains(&Value::object(
|
||||||
|
vec![
|
||||||
|
("name", Value::scalar("arg")),
|
||||||
|
("description", Value::scalar("The arg\nand more details")),
|
||||||
|
("defaultValue", Value::null()),
|
||||||
|
(
|
||||||
|
"type",
|
||||||
|
Value::object(
|
||||||
|
vec![
|
||||||
|
("name", Value::null()),
|
||||||
|
(
|
||||||
|
"ofType",
|
||||||
|
Value::object(
|
||||||
|
vec![("name", Value::scalar("Int"))].into_iter().collect(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].into_iter()
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].into_iter()
|
||||||
|
.collect(),
|
||||||
|
))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn introspect_field_arg_with_default() {
|
fn introspect_field_arg_with_default() {
|
||||||
run_args_info_query("argWithDefault", |args| {
|
run_args_info_query("argWithDefault", |args| {
|
||||||
|
|
|
@ -31,6 +31,31 @@ graphql_object!(Root: () |&self| {
|
||||||
field deprecated "Deprecation reason"
|
field deprecated "Deprecation reason"
|
||||||
deprecated_descr() -> i32 as "Field description" { 0 }
|
deprecated_descr() -> i32 as "Field description" { 0 }
|
||||||
|
|
||||||
|
#[doc = "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 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.
|
||||||
|
"#]
|
||||||
|
field attr_description_long() -> i32 { 0 }
|
||||||
|
|
||||||
|
#[deprecated]
|
||||||
|
field attr_deprecated() -> i32 { 0 }
|
||||||
|
|
||||||
|
#[deprecated(note = "Deprecation reason")]
|
||||||
|
field attr_deprecated_reason() -> i32 { 0 }
|
||||||
|
|
||||||
|
#[doc = "Field description"]
|
||||||
|
#[deprecated(note = "Deprecation reason")]
|
||||||
|
field attr_deprecated_descr() -> i32 { 0 }
|
||||||
|
|
||||||
field with_field_result() -> FieldResult<i32> { Ok(0) }
|
field with_field_result() -> FieldResult<i32> { Ok(0) }
|
||||||
|
|
||||||
field with_return() -> i32 { return 0; }
|
field with_return() -> i32 { return 0; }
|
||||||
|
@ -51,6 +76,31 @@ graphql_interface!(Interface: () |&self| {
|
||||||
field deprecated "Deprecation reason"
|
field deprecated "Deprecation reason"
|
||||||
deprecated_descr() -> i32 as "Field description" { 0 }
|
deprecated_descr() -> i32 as "Field description" { 0 }
|
||||||
|
|
||||||
|
#[doc = "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 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.
|
||||||
|
"#]
|
||||||
|
field attr_description_long() -> i32 { 0 }
|
||||||
|
|
||||||
|
#[deprecated]
|
||||||
|
field attr_deprecated() -> i32 { 0 }
|
||||||
|
|
||||||
|
#[deprecated(note = "Deprecation reason")]
|
||||||
|
field attr_deprecated_reason() -> i32 { 0 }
|
||||||
|
|
||||||
|
#[doc = "Field description"]
|
||||||
|
#[deprecated(note = "Deprecation reason")]
|
||||||
|
field attr_deprecated_descr() -> i32 { 0 }
|
||||||
|
|
||||||
instance_resolvers: |&_| {
|
instance_resolvers: |&_| {
|
||||||
Root => Some(Root {}),
|
Root => Some(Root {}),
|
||||||
}
|
}
|
||||||
|
@ -280,3 +330,255 @@ fn introspect_interface_field_deprecated_descr() {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn introspect_object_field_attr_description() {
|
||||||
|
run_field_info_query("Root", "attrDescription", |field| {
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("name"),
|
||||||
|
Some(&Value::scalar("attrDescription"))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("description"),
|
||||||
|
Some(&Value::scalar("Field description"))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("isDeprecated"),
|
||||||
|
Some(&Value::scalar(false))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("deprecationReason"),
|
||||||
|
Some(&Value::null())
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn introspect_interface_field_attr_description() {
|
||||||
|
run_field_info_query("Interface", "attrDescription", |field| {
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("name"),
|
||||||
|
Some(&Value::scalar("attrDescription"))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("description"),
|
||||||
|
Some(&Value::scalar("Field description"))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("isDeprecated"),
|
||||||
|
Some(&Value::scalar(false))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("deprecationReason"),
|
||||||
|
Some(&Value::null())
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn introspect_object_field_attr_description_long() {
|
||||||
|
run_field_info_query("Root", "attrDescriptionLong", |field| {
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("name"),
|
||||||
|
Some(&Value::scalar("attrDescriptionLong"))
|
||||||
|
);
|
||||||
|
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."))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("isDeprecated"),
|
||||||
|
Some(&Value::scalar(false))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("deprecationReason"),
|
||||||
|
Some(&Value::null())
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn introspect_interface_field_attr_description_long() {
|
||||||
|
run_field_info_query("Interface", "attrDescriptionLong", |field| {
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("name"),
|
||||||
|
Some(&Value::scalar("attrDescriptionLong"))
|
||||||
|
);
|
||||||
|
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."))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("isDeprecated"),
|
||||||
|
Some(&Value::scalar(false))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("deprecationReason"),
|
||||||
|
Some(&Value::null())
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn introspect_object_field_attr_description_collapse() {
|
||||||
|
run_field_info_query("Root", "attrDescriptionCollapse", |field| {
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("name"),
|
||||||
|
Some(&Value::scalar("attrDescriptionCollapse"))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("description"),
|
||||||
|
Some(&Value::scalar("Field description\nwith `collapse_docs` behavior"))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("isDeprecated"),
|
||||||
|
Some(&Value::scalar(false))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("deprecationReason"),
|
||||||
|
Some(&Value::null())
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn introspect_interface_field_attr_description_collapse() {
|
||||||
|
run_field_info_query("Interface", "attrDescriptionCollapse", |field| {
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("name"),
|
||||||
|
Some(&Value::scalar("attrDescriptionCollapse"))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("description"),
|
||||||
|
Some(&Value::scalar("Field description\nwith `collapse_docs` behavior"))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("isDeprecated"),
|
||||||
|
Some(&Value::scalar(false))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("deprecationReason"),
|
||||||
|
Some(&Value::null())
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn introspect_object_field_attr_deprecated() {
|
||||||
|
run_field_info_query("Root", "attrDeprecated", |field| {
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("name"),
|
||||||
|
Some(&Value::scalar("attrDeprecated"))
|
||||||
|
);
|
||||||
|
assert_eq!(field.get_field_value("description"), Some(&Value::null()));
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("isDeprecated"),
|
||||||
|
Some(&Value::scalar(true))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("deprecationReason"),
|
||||||
|
Some(&Value::null())
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn introspect_interface_field_attr_deprecated() {
|
||||||
|
run_field_info_query("Interface", "attrDeprecated", |field| {
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("name"),
|
||||||
|
Some(&Value::scalar("attrDeprecated"))
|
||||||
|
);
|
||||||
|
assert_eq!(field.get_field_value("description"), Some(&Value::null()));
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("isDeprecated"),
|
||||||
|
Some(&Value::scalar(true))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("deprecationReason"),
|
||||||
|
Some(&Value::null())
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn introspect_object_field_attr_deprecated_reason() {
|
||||||
|
run_field_info_query("Root", "attrDeprecatedReason", |field| {
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("name"),
|
||||||
|
Some(&Value::scalar("attrDeprecatedReason"))
|
||||||
|
);
|
||||||
|
assert_eq!(field.get_field_value("description"), Some(&Value::null()));
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("isDeprecated"),
|
||||||
|
Some(&Value::scalar(true))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("deprecationReason"),
|
||||||
|
Some(&Value::scalar("Deprecation reason"))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn introspect_interface_field_attr_deprecated_reason() {
|
||||||
|
run_field_info_query("Interface", "attrDeprecatedReason", |field| {
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("name"),
|
||||||
|
Some(&Value::scalar("attrDeprecatedReason"))
|
||||||
|
);
|
||||||
|
assert_eq!(field.get_field_value("description"), Some(&Value::null()));
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("isDeprecated"),
|
||||||
|
Some(&Value::scalar(true))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("deprecationReason"),
|
||||||
|
Some(&Value::scalar("Deprecation reason"))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn introspect_object_field_attr_deprecated_descr() {
|
||||||
|
run_field_info_query("Root", "attrDeprecatedDescr", |field| {
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("name"),
|
||||||
|
Some(&Value::scalar("attrDeprecatedDescr"))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("description"),
|
||||||
|
Some(&Value::scalar("Field description"))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("isDeprecated"),
|
||||||
|
Some(&Value::scalar(true))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("deprecationReason"),
|
||||||
|
Some(&Value::scalar("Deprecation reason"))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn introspect_interface_field_attr_deprecated_descr() {
|
||||||
|
run_field_info_query("Interface", "attrDeprecatedDescr", |field| {
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("name"),
|
||||||
|
Some(&Value::scalar("attrDeprecatedDescr"))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("description"),
|
||||||
|
Some(&Value::scalar("Field description"))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("isDeprecated"),
|
||||||
|
Some(&Value::scalar(true))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
field.get_field_value("deprecationReason"),
|
||||||
|
Some(&Value::scalar("Deprecation reason"))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,33 @@ use schema::model::SchemaType;
|
||||||
use types::base::TypeKind;
|
use types::base::TypeKind;
|
||||||
use value::{DefaultScalarValue, ParseScalarValue, ScalarRefValue, ScalarValue};
|
use value::{DefaultScalarValue, ParseScalarValue, ScalarRefValue, ScalarValue};
|
||||||
|
|
||||||
|
/// Whether an item is deprecated, with context.
|
||||||
|
#[derive(Debug, PartialEq, Hash, Clone)]
|
||||||
|
pub enum DeprecationStatus {
|
||||||
|
/// The field/variant is not deprecated.
|
||||||
|
Current,
|
||||||
|
/// The field/variant is deprecated, with an optional reason
|
||||||
|
Deprecated(Option<String>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeprecationStatus {
|
||||||
|
/// If this deprecation status indicates the item is deprecated.
|
||||||
|
pub fn is_deprecated(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
&DeprecationStatus::Current => false,
|
||||||
|
&DeprecationStatus::Deprecated(_) => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An optional reason for the deprecation, or none if `Current`.
|
||||||
|
pub fn reason(&self) -> Option<&String> {
|
||||||
|
match self {
|
||||||
|
&DeprecationStatus::Current => None,
|
||||||
|
&DeprecationStatus::Deprecated(ref reason) => reason.as_ref(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Scalar type metadata
|
/// Scalar type metadata
|
||||||
pub struct ScalarMeta<'a, S> {
|
pub struct ScalarMeta<'a, S> {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
@ -135,7 +162,7 @@ pub struct Field<'a, S> {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub field_type: Type<'a>,
|
pub field_type: Type<'a>,
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub deprecation_reason: Option<String>,
|
pub deprecation_status: DeprecationStatus,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Metadata for an argument to a field
|
/// Metadata for an argument to a field
|
||||||
|
@ -163,10 +190,8 @@ pub struct EnumValue {
|
||||||
/// Note: this is not the description of the enum itself; it's the
|
/// Note: this is not the description of the enum itself; it's the
|
||||||
/// description of this enum _value_.
|
/// description of this enum _value_.
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
/// The optional deprecation reason
|
/// Whether the field is deprecated or not, with an optional reason.
|
||||||
///
|
pub deprecation_status: DeprecationStatus,
|
||||||
/// If this is `Some`, the field will be considered `isDeprecated`.
|
|
||||||
pub deprecation_reason: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, S> MetaType<'a, S> {
|
impl<'a, S> MetaType<'a, S> {
|
||||||
|
@ -580,6 +605,28 @@ impl<'a, S> Field<'a, S> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds a (multi)line doc string to the description of the field.
|
||||||
|
/// Any leading or trailing newlines will be removed.
|
||||||
|
///
|
||||||
|
/// If the docstring contains newlines, repeated leading tab and space characters
|
||||||
|
/// will be removed from the beginning of each line.
|
||||||
|
///
|
||||||
|
/// 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Add an argument to the field
|
/// Add an argument to the field
|
||||||
///
|
///
|
||||||
/// Arguments are unordered and can't contain duplicates by name.
|
/// Arguments are unordered and can't contain duplicates by name.
|
||||||
|
@ -596,11 +643,11 @@ impl<'a, S> Field<'a, S> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the deprecation reason
|
/// Set the field to be deprecated with an optional reason.
|
||||||
///
|
///
|
||||||
/// This overwrites the deprecation reason if any was previously set.
|
/// This overwrites the deprecation reason if any was previously set.
|
||||||
pub fn deprecated(mut self, reason: &str) -> Self {
|
pub fn deprecated(mut self, reason: Option<&str>) -> Self {
|
||||||
self.deprecation_reason = Some(reason.to_owned());
|
self.deprecation_status = DeprecationStatus::Deprecated(reason.map(|s| s.to_owned()));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -624,6 +671,28 @@ impl<'a, S> Argument<'a, S> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds a (multi)line doc string to the description of the field.
|
||||||
|
/// Any leading or trailing newlines will be removed.
|
||||||
|
///
|
||||||
|
/// If the docstring contains newlines, repeated leading tab and space characters
|
||||||
|
/// will be removed from the beginning of each line.
|
||||||
|
///
|
||||||
|
/// 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the default value of the argument
|
/// Set the default value of the argument
|
||||||
///
|
///
|
||||||
/// This overwrites the description if any was previously set.
|
/// This overwrites the description if any was previously set.
|
||||||
|
@ -639,7 +708,7 @@ impl EnumValue {
|
||||||
EnumValue {
|
EnumValue {
|
||||||
name: name.to_owned(),
|
name: name.to_owned(),
|
||||||
description: None,
|
description: None,
|
||||||
deprecation_reason: None,
|
deprecation_status: DeprecationStatus::Current,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -651,11 +720,11 @@ impl EnumValue {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the deprecation reason for the enum value
|
/// Set the enum value to be deprecated with an optional reason.
|
||||||
///
|
///
|
||||||
/// This overwrites the deprecation reason if any was previously set.
|
/// This overwrites the deprecation reason if any was previously set.
|
||||||
pub fn deprecated(mut self, reason: &str) -> EnumValue {
|
pub fn deprecated(mut self, reason: Option<&str>) -> Self {
|
||||||
self.deprecation_reason = Some(reason.to_owned());
|
self.deprecation_status = DeprecationStatus::Deprecated(reason.map(|s| s.to_owned()));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -696,3 +765,27 @@ where
|
||||||
{
|
{
|
||||||
<T as FromInputValue<S>>::from_input_value(v).is_some()
|
<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..]
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
Cow::from(trimmed.join("\n").trim_matches('\n').to_owned())
|
||||||
|
} else {
|
||||||
|
Cow::from(multiline.trim_matches('\n'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -132,7 +132,7 @@ graphql_object!(<'a> TypeType<'a, S>: SchemaType<'a, S> as "__Type"
|
||||||
TypeType::Concrete(&MetaType::Object(ObjectMeta { ref fields, .. })) =>
|
TypeType::Concrete(&MetaType::Object(ObjectMeta { ref fields, .. })) =>
|
||||||
Some(fields
|
Some(fields
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|f| include_deprecated || f.deprecation_reason.is_none())
|
.filter(|f| include_deprecated || !f.deprecation_status.is_deprecated())
|
||||||
.filter(|f| !f.name.starts_with("__"))
|
.filter(|f| !f.name.starts_with("__"))
|
||||||
.collect()),
|
.collect()),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -201,7 +201,7 @@ graphql_object!(<'a> TypeType<'a, S>: SchemaType<'a, S> as "__Type"
|
||||||
TypeType::Concrete(&MetaType::Enum(EnumMeta { ref values, .. })) =>
|
TypeType::Concrete(&MetaType::Enum(EnumMeta { ref values, .. })) =>
|
||||||
Some(values
|
Some(values
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|f| include_deprecated || f.deprecation_reason.is_none())
|
.filter(|f| include_deprecated || !f.deprecation_status.is_deprecated())
|
||||||
.collect()),
|
.collect()),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
@ -228,11 +228,11 @@ graphql_object!(<'a> Field<'a, S>: SchemaType<'a, S> as "__Field"
|
||||||
}
|
}
|
||||||
|
|
||||||
field is_deprecated() -> bool {
|
field is_deprecated() -> bool {
|
||||||
self.deprecation_reason.is_some()
|
self.deprecation_status.is_deprecated()
|
||||||
}
|
}
|
||||||
|
|
||||||
field deprecation_reason() -> &Option<String> {
|
field deprecation_reason() -> Option<&String> {
|
||||||
&self.deprecation_reason
|
self.deprecation_status.reason()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -266,11 +266,11 @@ graphql_object!(EnumValue: () as "__EnumValue" where Scalar = <S> |&self| {
|
||||||
}
|
}
|
||||||
|
|
||||||
field is_deprecated() -> bool {
|
field is_deprecated() -> bool {
|
||||||
self.deprecation_reason.is_some()
|
self.deprecation_status.is_deprecated()
|
||||||
}
|
}
|
||||||
|
|
||||||
field deprecation_reason() -> &Option<String> {
|
field deprecation_reason() -> Option<&String> {
|
||||||
&self.deprecation_reason
|
self.deprecation_status.reason()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ impl EnumAttrs {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
panic!(format!(
|
panic!(format!(
|
||||||
"Unknown attribute for #[derive(GraphQLEnum)]: {:?}",
|
"Unknown enum attribute for #[derive(GraphQLEnum)]: {:?}",
|
||||||
item
|
item
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ impl EnumAttrs {
|
||||||
struct EnumVariantAttrs {
|
struct EnumVariantAttrs {
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
description: Option<String>,
|
description: Option<String>,
|
||||||
deprecation: Option<String>,
|
deprecation: Option<DeprecationAttr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EnumVariantAttrs {
|
impl EnumVariantAttrs {
|
||||||
|
@ -67,6 +67,9 @@ impl EnumVariantAttrs {
|
||||||
// Check doc comments for description.
|
// Check doc comments for description.
|
||||||
res.description = get_doc_comment(&variant.attrs);
|
res.description = get_doc_comment(&variant.attrs);
|
||||||
|
|
||||||
|
// Check builtin deprecated attribute for deprecation.
|
||||||
|
res.deprecation = get_deprecated(&variant.attrs);
|
||||||
|
|
||||||
// Check attributes for name and description.
|
// Check attributes for name and description.
|
||||||
if let Some(items) = get_graphql_attr(&variant.attrs) {
|
if let Some(items) = get_graphql_attr(&variant.attrs) {
|
||||||
for item in items {
|
for item in items {
|
||||||
|
@ -90,13 +93,24 @@ impl EnumVariantAttrs {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if let Some(AttributeValue::String(val)) =
|
if let Some(AttributeValue::String(val)) =
|
||||||
keyed_item_value(&item, "deprecated", AttributeValidation::String)
|
keyed_item_value(&item, "deprecation", AttributeValidation::String)
|
||||||
{
|
{
|
||||||
res.deprecation = Some(val);
|
res.deprecation = Some(DeprecationAttr { reason: Some(val) });
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
match keyed_item_value(&item, "deprecated", AttributeValidation::String) {
|
||||||
|
Some(AttributeValue::String(val)) => {
|
||||||
|
res.deprecation = Some(DeprecationAttr { reason: Some(val) });
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Some(AttributeValue::Bare) => {
|
||||||
|
res.deprecation = Some(DeprecationAttr { reason: None });
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
panic!(format!(
|
panic!(format!(
|
||||||
"Unknown attribute for #[derive(GraphQLEnum)]: {:?}",
|
"Unknown variant attribute for #[derive(GraphQLEnum)]: {:?}",
|
||||||
item
|
item
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -151,14 +165,21 @@ pub fn impl_enum(ast: &syn::DeriveInput) -> TokenStream {
|
||||||
None => quote!{ None },
|
None => quote!{ None },
|
||||||
};
|
};
|
||||||
let depr = match var_attrs.deprecation {
|
let depr = match var_attrs.deprecation {
|
||||||
Some(s) => quote!{ Some(#s.to_string()) },
|
Some(DeprecationAttr { reason: Some(s) }) => quote!{
|
||||||
None => quote!{ None },
|
_juniper::meta::DeprecationStatus::Deprecated(Some(#s.to_string()))
|
||||||
|
},
|
||||||
|
Some(DeprecationAttr { reason: None }) => quote!{
|
||||||
|
_juniper::meta::DeprecationStatus::Deprecated(None)
|
||||||
|
},
|
||||||
|
None => quote!{
|
||||||
|
_juniper::meta::DeprecationStatus::Current
|
||||||
|
},
|
||||||
};
|
};
|
||||||
values.extend(quote!{
|
values.extend(quote!{
|
||||||
_juniper::meta::EnumValue{
|
_juniper::meta::EnumValue{
|
||||||
name: #name.to_string(),
|
name: #name.to_string(),
|
||||||
description: #descr,
|
description: #descr,
|
||||||
deprecation_reason: #depr,
|
deprecation_status: #depr,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ impl ObjAttrs {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
panic!(format!(
|
panic!(format!(
|
||||||
"Unknown object attribute for #[derive(GraphQLObject)]: {:?}",
|
"Unknown struct attribute for #[derive(GraphQLObject)]: {:?}",
|
||||||
item
|
item
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ impl ObjAttrs {
|
||||||
struct ObjFieldAttrs {
|
struct ObjFieldAttrs {
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
description: Option<String>,
|
description: Option<String>,
|
||||||
deprecation: Option<String>,
|
deprecation: Option<DeprecationAttr>,
|
||||||
skip: bool,
|
skip: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +71,9 @@ impl ObjFieldAttrs {
|
||||||
// Check doc comments for description.
|
// Check doc comments for description.
|
||||||
res.description = get_doc_comment(&variant.attrs);
|
res.description = get_doc_comment(&variant.attrs);
|
||||||
|
|
||||||
|
// Check builtin deprecated attribute for deprecation.
|
||||||
|
res.deprecation = get_deprecated(&variant.attrs);
|
||||||
|
|
||||||
// Check attributes.
|
// Check attributes.
|
||||||
if let Some(items) = get_graphql_attr(&variant.attrs) {
|
if let Some(items) = get_graphql_attr(&variant.attrs) {
|
||||||
for item in items {
|
for item in items {
|
||||||
|
@ -96,9 +99,20 @@ impl ObjFieldAttrs {
|
||||||
if let Some(AttributeValue::String(val)) =
|
if let Some(AttributeValue::String(val)) =
|
||||||
keyed_item_value(&item, "deprecation", AttributeValidation::String)
|
keyed_item_value(&item, "deprecation", AttributeValidation::String)
|
||||||
{
|
{
|
||||||
res.deprecation = Some(val);
|
res.deprecation = Some(DeprecationAttr { reason: Some(val) });
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
match keyed_item_value(&item, "deprecated", AttributeValidation::String) {
|
||||||
|
Some(AttributeValue::String(val)) => {
|
||||||
|
res.deprecation = Some(DeprecationAttr { reason: Some(val) });
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Some(AttributeValue::Bare) => {
|
||||||
|
res.deprecation = Some(DeprecationAttr { reason: None });
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
if let Some(_) = keyed_item_value(&item, "skip", AttributeValidation::Bare) {
|
if let Some(_) = keyed_item_value(&item, "skip", AttributeValidation::Bare) {
|
||||||
res.skip = true;
|
res.skip = true;
|
||||||
continue;
|
continue;
|
||||||
|
@ -167,7 +181,8 @@ pub fn impl_object(ast: &syn::DeriveInput) -> TokenStream {
|
||||||
};
|
};
|
||||||
|
|
||||||
let build_deprecation = match field_attrs.deprecation {
|
let build_deprecation = match field_attrs.deprecation {
|
||||||
Some(s) => quote!{ field.deprecated(#s) },
|
Some(DeprecationAttr { reason: Some(s) }) => quote!{ field.deprecated(Some(#s)) },
|
||||||
|
Some(DeprecationAttr { reason: None }) => quote!{ field.deprecated(None) },
|
||||||
None => quote!{ field },
|
None => quote!{ field },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use syn::{Attribute, Lit, Meta, MetaNameValue, NestedMeta};
|
use syn::{Attribute, Lit, Meta, MetaList, MetaNameValue, NestedMeta};
|
||||||
|
|
||||||
pub enum AttributeValidation {
|
pub enum AttributeValidation {
|
||||||
Any,
|
Any,
|
||||||
|
@ -12,6 +12,42 @@ pub enum AttributeValue {
|
||||||
String(String),
|
String(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct DeprecationAttr {
|
||||||
|
pub reason: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_deprecated(attrs: &Vec<Attribute>) -> Option<DeprecationAttr> {
|
||||||
|
for attr in attrs {
|
||||||
|
match attr.interpret_meta() {
|
||||||
|
Some(Meta::List(ref list)) if list.ident == "deprecated" => {
|
||||||
|
return Some(get_deprecated_meta_list(list));
|
||||||
|
}
|
||||||
|
Some(Meta::Word(ref ident)) if ident == "deprecated" => {
|
||||||
|
return Some(DeprecationAttr { reason: None });
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_deprecated_meta_list(list: &MetaList) -> DeprecationAttr {
|
||||||
|
for meta in &list.nested {
|
||||||
|
match meta {
|
||||||
|
&NestedMeta::Meta(Meta::NameValue(ref nv)) if nv.ident == "note" => {
|
||||||
|
match &nv.lit {
|
||||||
|
&Lit::Str(ref strlit) => {
|
||||||
|
return DeprecationAttr { reason: Some(strlit.value().to_string()) };
|
||||||
|
}
|
||||||
|
_ => panic!("deprecated attribute note value only has string literal"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DeprecationAttr { reason: None }
|
||||||
|
}
|
||||||
|
|
||||||
// Gets doc comment.
|
// Gets doc comment.
|
||||||
pub fn get_doc_comment(attrs: &Vec<Attribute>) -> Option<String> {
|
pub fn get_doc_comment(attrs: &Vec<Attribute>) -> Option<String> {
|
||||||
if let Some(items) = get_doc_attr(attrs) {
|
if let Some(items) = get_doc_attr(attrs) {
|
||||||
|
|
|
@ -78,7 +78,7 @@ impl<'a> GraphQLType for &'a Fake {
|
||||||
&[juniper::meta::EnumValue {
|
&[juniper::meta::EnumValue {
|
||||||
name: "fake".to_string(),
|
name: "fake".to_string(),
|
||||||
description: None,
|
description: None,
|
||||||
deprecation_reason: None,
|
deprecation_status: juniper::meta::DeprecationStatus::Current,
|
||||||
}],
|
}],
|
||||||
);
|
);
|
||||||
meta.into_meta()
|
meta.into_meta()
|
||||||
|
|
Loading…
Reference in a new issue